Skip to content

Completion Report: ANU-6 - Add the containerized local CMS development stack

Implementation summary

ANU-6 adds the repository-owned local development stack without moving any production or hosted data. The tracked implementation contains:

  • a pinned Node 22.5.1 development image and Compose web service
  • pinned PostgreSQL 17/pgvector 0.8.2 and pgAdmin 9.16 services
  • loopback-only ports, health gates, hot reload, and persistent named volumes
  • safe tracked environment examples and ignored machine-local secrets/artifacts
  • explicit database export, loopback-only restore, parity, and volume-reset guards whose default modes do not connect or mutate
  • a container smoke for Payload, Mastra storage, pgvector insert/query/delete, and the authenticated worker API
  • bootstrap, architecture, environment, command, testing, and recovery docs

The real Supabase export, restore, parity acceptance, and cutover remain owned by the dependent migration issue. No source database was read or modified while implementing ANU-6.

Acceptance evidence

Acceptance check Result Redacted evidence
Compose validates without embedded secrets Passed docker compose --env-file .env.compose config --quiet exited 0. Tracked Compose contains interpolated variable requirements, while .env.compose and .local-data/** are ignored. The guard test also rejects tracked placeholder/secret literals in compose.yaml.
One command starts web, postgres, and pgadmin on approved ports Passed After the Docker Desktop image-store change, pnpm stack:up pulled and built the images and reported all three services healthy. stack:status showed loopback-only mappings for 127.0.0.1:3000, 127.0.0.1:5432, and 127.0.0.1:5050; pgAdmin returned HTTP 200 and PostgreSQL accepted TCP connections.
PostgreSQL 17.10, pgvector 0.8.2, pgAdmin 9.16, and resolved digests Passed Running containers reported PostgreSQL 17.10, pgvector 0.8.2, pgAdmin 9.16, and Node 22.5.1. PostgreSQL and pgAdmin ran from the pinned repository digests; the final local web image ID was sha256:3d13dc30087e229ad0f5cb4d5a71fe6e49ae3f00ef8184f042135938a39e7b7e.
Restart preserves named-volume state and routine stops do not delete it Passed Exact temporary sentinels in PostgreSQL and the pgAdmin data directory survived both an all-service restart and stack:down followed by stack:up. The named volume identities remained unchanged, and the sentinels were removed after verification.
Payload, Mastra, RAG vector operations, and worker API work from web against local Postgres Passed pnpm stack:verify returned ok: true with Payload initialized, Mastra storage initialized, deterministic pgvector insert/query successful, and the authenticated worker API returning 200. The final smoke was repeated after the down/up persistence cycle.
Export/restore tooling has explicit inputs, ignored outputs, and destructive guards Passed The 10-test local-stack suite passed. Plan mode does not require or read a source URI; artifacts must be named descendants of .local-data/database; restore requires an exact redacted loopback fingerprint and a second exact confirmation for a non-empty target; reset also requires an exact project confirmation. No real export or restore ran.

Verification commands and results

  • docker compose --env-file .env.compose config --quiet: passed.
  • docker compose build --no-cache web: passed after replacing the failing bundled Corepack signature path with pinned pnpm@10.7.0 installation.
  • Final docker compose --env-file .env.compose build web: passed with a 61.68 kB Docker context and local image ID sha256:3d13dc30087e229ad0f5cb4d5a71fe6e49ae3f00ef8184f042135938a39e7b7e.
  • pnpm stack:up: passed after the Docker Desktop image-store change; all three health gates passed. A Docker Desktop restart repaired one transient Windows bind-mount bridge error encountered after changing the engine setting.
  • Runtime probes: PostgreSQL 17.10, pgvector 0.8.2, pgAdmin 9.16, Node 22.5.1, pgAdmin HTTP 200, PostgreSQL TCP reachable, and authenticated web worker health requests returned 200.
  • pnpm stack:restart plus docker compose up --wait: passed. The web launcher detects an initialized Payload schema, disables repeat schema push, and waits for PostgreSQL readiness during simultaneous service restarts.
  • pnpm stack:down followed by pnpm stack:up: passed; temporary PostgreSQL and pgAdmin sentinels persisted through container/network removal and were cleaned up afterward.
  • pnpm stack:verify: passed twice, including after down/up, with Payload, Mastra storage, pgvector insert/query, and authenticated worker API results.
  • pnpm lint -- <ANU-6 implementation files>: passed.
  • pnpm lint: repository-wide check reached unrelated pre-existing findings in historical/generated CSS, the generated import map and Payload types, and src/mastra/tools/presentation/index.ts; ANU-6 files pass the targeted check.
  • pnpm typecheck: passed.
  • tests/unit/local-stack.test.ts: 10 tests passed.
  • pnpm test:int: 95 tests passed; the one unrelated existing failure is tests/unit/anuva-orchestration-service.test.ts, whose expectation still names the obsolete combined narrative-agent call after the repository split that orchestration into separate calls.
  • pnpm test:e2e: the server and Chromium started, then all six existing presentation scenarios timed out on the same stale presentation-usecase-product_explainer locator. The captured page was already on the current Video Setup screen, which does not contain that old use-case control; server output also contained Better Auth 401 responses. This route-suite drift is outside the local-stack scope.
  • git diff --check: passed.
  • mkdocs build --strict: passed; only existing navigation and absolute-link informational warnings were reported.
  • Recursive documentation index validation and preview HTTP checks: passed.

Documentation and preview URLs

  • Change overview: https://web1.girishd.com/changes/2026-07-20-switch-to-local-postgres/
  • Implementation plan: https://web1.girishd.com/changes/2026-07-20-switch-to-local-postgres/ImplementationPlan/
  • Implementation log: https://web1.girishd.com/changes/2026-07-20-switch-to-local-postgres/ImplementationLog/
  • Completion report: https://web1.girishd.com/changes/2026-07-20-switch-to-local-postgres/CompletionReport/
  • Local stack bootstrap: https://web1.girishd.com/bootstrap/LocalDevelopmentStack/
  • System architecture: https://web1.girishd.com/core/SystemArchitecture/
  • Environment and services: https://web1.girishd.com/state/EnvAndServices/
  • Scripts and commands: https://web1.girishd.com/state/ScriptsAndCommands/
  • Testing and verification: https://web1.girishd.com/core/TestingAndVerification/
  • Known gaps: https://web1.girishd.com/state/KnownGaps/

Product Main synchronization

Product Main/ANU-5 must receive [ANU-6 draft PR

30](https://github.com/Shoonya-Game-Technologies/anuvax-cms/pull/30), this

plan/log/report, exact preview URLs, immutable version/digest evidence, and the completed local runtime acceptance evidence. The dependent migration issue must retain ownership of the real Supabase export, reviewed role/schema selection, local restore, parity proof, application acceptance, source protection, and cutover/rollback decision.

Canonical docs remain unpublished. The CMS URLs above are review previews only.

Remaining risks and skipped checks

  • The repository-wide lint/integration/E2E failures described above are not caused by the local-stack files, but they remain visible acceptance debt and should be resolved by their owning work before release-level verification.
  • External S3, AI, email, billing, Python, and Unity dependencies are deliberately outside this Compose stack and still require environment-specific testing.

Rollback and recovery

  • Reverting the ANU-6 commit restores the prior host-run configuration; it does not touch the remote Supabase source.
  • pnpm stack:down is the normal diagnostic stop and preserves all named-volume state. Review pnpm stack:logs before retrying a failed start.
  • pnpm stack:reset only prints its exact target plan. Volume deletion requires --execute --confirm anuvax-cms-local and was not used during verification.
  • Restore execution accepts only a loopback target and refuses ambiguous or non-empty targets without exact confirmations. Those paths remain deferred to the dependent migration issue.