Skip to content

Implementation Plan: ANU-6 - Add the containerized local CMS development stack

Scope

Add a development-focused local stack owned by anuvax-cms:

  • a Node 22 web development image and Compose web service
  • PostgreSQL 17.10 with pgvector 0.8.2 as the postgres service
  • pgAdmin 9.16 as the pgadmin service
  • loopback-only host bindings on ports 3000, 5432, and 5050
  • health checks and named volumes for database and pgAdmin state
  • ignored machine-local configuration plus tracked secret-free examples
  • explicit, guarded database export, restore, and parity tooling
  • repository docs, tests, and redacted verification evidence

The web service will use postgres:5432 inside Compose. Host tools will use 127.0.0.1:5432. External S3, AI, email, billing, Python, and Unity services remain outside the stack.

Product Main inputs and dependencies

  • Product Main change: 2026-07-20-switch-to-local-postgres
  • Product Main source: docs/changes/2026-07-20-switch-to-local-postgres/index.md
  • Linear parent: ANU-5
  • Linear implementation child: ANU-6
  • Repository label: anuvax-cms
  • Blockers: none
  • Required baselines: PostgreSQL 17.10, pgvector 0.8.2, pgAdmin 9.16, Node 22.5
  • Local runtime dependency: Docker Desktop with Compose v2

The approved Product Main plan is authoritative for the service names, ports, persistence behavior, security boundaries, migration sequencing, and cross-repository compatibility contract.

Implementation approach

  1. Add a development Dockerfile, Compose definition, and Docker ignore rules.
  2. Pin explicit image versions and record resolved immutable digests without embedding credentials.
  3. Add safe tracked environment examples and ignore all machine-local credentials, dump files, restore logs, checksums, and parity reports.
  4. Configure health-gated startup, loopback port publishing, named volumes, source hot reload, and container-aware database/server URLs.
  5. Remove only the Supabase-specific wording and pooler guard that are no longer part of the supported local database contract.
  6. Add cross-platform lifecycle and database tooling that requires explicit source, target, artifact directory, and destructive confirmation inputs.
  7. Add static tests for the configuration and guard behavior, then exercise Compose and application smoke paths against the local stack.
  8. Update durable architecture, environment, bootstrap, command, and testing documentation while maintaining the implementation log.
  9. Map every acceptance criterion to exact redacted evidence in the completion report and identify Product Main synchronization requirements.

Expected implementation surfaces:

  • Dockerfile.dev
  • .dockerignore
  • compose.yaml
  • .env.compose.example
  • .gitignore
  • .env.example
  • package.json
  • src/payload.config.ts
  • src/mastra/env.ts
  • scripts/local-stack/**
  • tests/unit/local-stack.test.ts
  • README.md
  • docs/bootstrap/**
  • docs/core/SystemArchitecture.md
  • docs/core/TestingAndVerification.md
  • docs/state/EnvAndServices.md
  • docs/state/ScriptsAndCommands.md
  • this change folder and mkdocs.yml

Documentation impact

  • Document the Compose topology and service boundary in system architecture.
  • Replace hosted/Supabase-only local assumptions in environment and bootstrap guidance with the local Compose contract.
  • Document start, stop, restart, logs, health, persistence, guarded migration, recovery, and explicit reset commands.
  • Document static, runtime, application, migration-tool, and parity checks.
  • Return exact preview URLs after the planning update, implementation docs update, and final completion-evidence update.
  • Record publication as preview-only; Product Main remains responsible for the cross-repository completion review and canonical publishing decision.

Verification and acceptance checks

Check Planned evidence
Secret-free valid Compose configuration docker compose config plus tracked-file secret scan
One-command three-service startup clean docker compose up --build --wait result and service status
Approved loopback endpoints HTTP and TCP probes for ports 3000, 5432, and 5050
Required versions and digests SQL, pgAdmin metadata, image inspection, and recorded immutable references
Persistent routine restart sentinel data/config before and after restart/down/up without volumes removal
Payload and Mastra startup web health/log evidence and database relation probes
RAG vector behavior extension/index creation plus deterministic vector insert/query/delete smoke
Worker API compatibility authenticated container-to-host or published-port smoke request
Guarded export/restore/parity tooling static tests, help/dry-run checks, and explicit refusal cases
Repository quality pnpm lint, pnpm typecheck, pnpm test:int, targeted Playwright smoke
Documentation quality index validation, mkdocs build --strict, preview wait and exact links

Any unavailable runtime check will be marked skipped with its cause and the remaining evidence. A partial boot is not acceptance.

Non-goals and rollback

Non-goals:

  • running the real Supabase export, restore, migration, or cutover
  • modifying or disabling the Supabase source database
  • importing Supabase-managed schemas, roles, Auth, Storage, Realtime, or Edge Functions
  • production deployment, Python/Unity containerization, or external-provider containerization
  • framework, Payload, Mastra, Node-major, or PostgreSQL-major upgrades

Rollback removes the ANU-6 tracked configuration changes and returns local development to the prior host-run application configuration. Routine docker compose down preserves named volumes. Volume removal or restore over an existing database is never automatic and requires an exact target plus explicit confirmation. The dependent migration issue retains the authoritative data cutover and rollback procedure.