Implementation Log: ANU-6 - Add the containerized local CMS development stack
Changes and decisions
2026-07-21: Validated ANU-6 as Ready for anuvax-cms, with no blockers and
complete Product Main, scope, acceptance, docs, and verification inputs.
2026-07-21: Started the issue through anuva work start; Linear moved to In
Progress and the dedicated implementation branch was created from main.
2026-07-21: Confirmed the approved three-service boundary and kept the real
database migration explicitly outside this issue.
2026-07-21: Added pinned development images, a three-service Compose model,
loopback bindings, health gates, hot reload, and persistent named volumes.
2026-07-21: Removed the Supabase-hostname schema-push exception; local schema
push is now governed only by the explicit PAYLOAD_DB_PUSH flag.
2026-07-21: Added guarded export, restore, parity, and volume-reset tooling.
Every destructive or connecting operation requires explicit inputs and
execution flags; real migration execution remains deferred.
2026-07-21: Verified the smoke implementation against installed Mastra
PgVector docs and types before using create/upsert/query/delete APIs.
2026-07-21: The first no-cache web build reached the pinned Node base image
but its bundled Corepack rejected pnpm's current signing key. Replaced the
Corepack prepare step with a direct, version-pinned npm install --global
pnpm@10.7.0 bootstrap and repeated the clean build.
2026-07-21: Playwright verification exposed two pre-existing harness gaps:
dotenv/config lacked a direct dependency and the web-server command used
POSIX-only environment syntax. Added the direct dev dependency and changed
the command to the repository's existing cross-platform cross-env runner.
2026-07-21: The first browser assertion run showed that the active hosted
.env still requested Payload schema push. Made the e2e boundary explicit
with PAYLOAD_DB_PUSH=0, while Compose continues to opt into push for its
empty local database.
2026-07-21: Rebuilt the web image against the final lockfile. The build
completed with local manifest-list digest
sha256:73f45d1e6555d88c3cbdf8b99c1f012c08c29395247fd21b8b65036da74107bc.
2026-07-21: After Docker Desktop was changed to use the classic image store,
the pinned pgvector and pgAdmin images pulled successfully. A Docker Desktop
restart repaired a transient Windows bind-mount bridge error introduced by
the engine setting change.
2026-07-21: Runtime startup exposed and fixed three local-stack lifecycle
defects: pgAdmin 9.16 rejected the special-use .invalid example address,
Payload schema push was unsafe on a populated restart, and the standalone
smoke needed independent pool cleanup/termination. Added regression coverage
for the accepted pgAdmin address and restart/smoke boundaries.
2026-07-21: Added a web launcher that waits for PostgreSQL, inspects the local
Payload schema with psql, enables push only for an empty first boot, and
disables repeat push on restart. Connection credentials remain in libpq
environment variables rather than process arguments or logs.
2026-07-21: Completed runtime acceptance. All services became healthy on
loopback ports; running versions matched the pinned baselines; Payload,
Mastra, pgvector, and authenticated worker API smoke passed; PostgreSQL and
pgAdmin sentinels survived restart and routine down/up and were then removed.
2026-07-21: Repository-wide checks exposed unrelated existing failures: the
full Biome check reports historical/generated files, one integration test
expects an obsolete combined narrative-agent call, and all six Playwright
cases wait for a use-case selector absent from the current Video Setup page.
Targeted ANU-6 lint, typecheck, 10 local-stack tests, strict MkDocs, Compose
validation, and diff sanity pass.
2026-07-21: Acceptance review confirmed the PR head is clean and mergeable,
has no review comments or requested changes, maps every ANU-6 acceptance item
to runtime evidence, and preserves the ANU-7 migration boundary. The known
repository-wide lint, integration, and E2E failures remain documented as
out-of-scope follow-ups rather than being folded into this child.
2026-07-21: Created draft PR
#30
through the Anuva CLI. The CLI linked the PR and moved ANU-6 from In Progress
to In Review (receipt 20260721T073343Z-pr-create-da06).
Files and documentation updated
Initial change-folder index, implementation plan, implementation log, and
completion-report shell.
Change navigation and recursive index coverage.
Dockerfile.dev, .dockerignore, compose.yaml, and safe environment examples.
scripts/local-stack/** for initialization, pgAdmin registration, runtime
smoke, migration guards, parity summaries, and reset confirmation.
tests/unit/local-stack.test.ts for immutable references, configuration
boundaries, path/target guards, plan mode, and reset refusal.
Payload/Mastra wording and schema-push configuration.
Repository README plus bootstrap, architecture, environment, command,
testing, API, and known-gap documentation.
Verification evidence
Planning docs recursive index validation: passed.
Planning preview: all change overview/plan/log/report pages returned HTTP 200.
docker compose --env-file .env.compose config --quiet: passed; Docker CLI
warned that the user Docker config was unreadable in the sandbox.
Targeted Biome check: passed after formatting and guard cleanup.
TypeScript tsc --noEmit: passed.
Local-stack Vitest file: 10 tests passed.
Final web image build against the updated lockfile: passed.
Strict MkDocs build: passed with existing informational warnings.
Deviations, risks, and follow-ups
The Docker Hub pull blocker is resolved by the Docker Desktop image-store
setting change. The local stack remains intentionally separate from the real
Supabase export/restore/parity work owned by the dependent migration issue.
Immutable manifest and Linux amd64 child digests were resolved from the
Docker Hub tag API. Running version commands remain required before accepting
the dependent migration issue.