Implementation Log: ANU-7 - Migrate Supabase Postgres data and verify local cutover
Changes and decisions
2026-07-21: Validated ANU-7 as Ready for anuvax-cms; dependency ANU-6 was
Done and Product Main scope, acceptance, docs, and verification inputs were
complete.
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: Kept the accepted ANU-6 evidence immutable and created a separate
ANU-7 change record for the stateful migration and cutover.
2026-07-21: Pinned Supabase CLI 2.109.1 as a project dev dependency, following
the official project-local installation model. Added source and combined
source/local wrapper commands that keep connection strings in process
environment only.
2026-07-21: Extended the guarded database tool with read-only inventory,
reviewed schema selection, CLI dry runs, component-level credential redaction,
checksum verification, local schema preparation, fresh target creation,
empty-target extension alignment, transactional restore, semantic parity, and
targeted cutover probes.
2026-07-21: Source inventory ran in a read-only transaction against PostgreSQL
17.6. It found about 52 MB, 137 non-system tables overall, 102 application
tables in public, Payload migrations, 27 Mastra tables, RAG tables, and the
application vector index. Supabase-managed schemas and roles were recorded by
name only and excluded from restore.
2026-07-21: The first CLI dry run exposed a credential assignment in its raw
diagnostic output. Deleted that ignored dry-run directory, expanded redaction
to full URI and decoded/encoded username/password components, then repeated
the dry run successfully with no URI or credential component in the log.
2026-07-21: Exported only public schema and data with Supabase CLI 2.109.1.
The schema was 206,471 bytes and data was 36,471,404 bytes. SHA-256 verification,
.gitignore checks, and Git absence checks passed.
2026-07-21: Prepared a local schema without importing hosted roles. The
deterministic preparation removed 178 ownership statements, 340 grants, and
12 default-privilege statements; it removed no table, constraint, index, or
data statement and found no residual hosted-role reference.
2026-07-21: Preserved the accepted anuvax database and created a separate
anuvax_anu7 database in the same named volume. The first direct create
attempt failed at host-shell parsing before mutation; the guarded TypeScript
operation then created the database successfully.
2026-07-21: The first restore transport hit a Windows spawnSync EOF while
piping the 36 MB dump. The target remained empty. Changed restore transport so
the web container reads bind-mounted ignored files directly with
psql --single-transaction.
2026-07-21: The second restore rolled back because the portable schema
references public.vector while the first target setup installed pgvector in
extensions. The target again remained empty. Moved pgvector to public only
on that empty database and changed future target creation accordingly.
2026-07-21: The third restore committed successfully. No role import, managed
schema import, blanket public grant, or privilege weakening occurred.
2026-07-21: Fixed parity-query implementation issues exposed before a report
was accepted: session temporary tables now precede the read-only snapshot, a
PostgreSQL char signature field is cast explicitly, and JSON objects are
canonicalized before semantic comparison.
2026-07-21: Final parity passed with 102 table counts, 99 primary-key hashes,
283 constraint signatures, 482 index signatures, nine sequence states,
workspace-null counts, Payload state, 27 Mastra tables, and RAG/vector state
equal between source and target. PostgreSQL 17.6 to 17.10 and pgvector 0.8.0
to 0.8.2 were retained as reviewed platform patch differences.
2026-07-21: Targeted probes found zero presentation or RAG workspace
mismatches, four Payload migration rows, 51 Mastra workflow snapshots, 786 RAG
chunks, 786 migrated vectors, the migrated vector index, and one successful
nearest-neighbor result. All three job queues were empty.
2026-07-21: Switched only ignored .env.composePOSTGRES_DB to
anuvax_anu7. Compose recreated all services healthy; the web container
resolved the local target and integrated Payload, Mastra, RAG, and worker API
smoke passed.
2026-07-21: Payload migration status reported all three checked-in migrations
applied. Public, Payload admin, login, and pgAdmin endpoints returned HTTP 200.
RAG, presentation, and Anuva workers each passed bounded startup probes while
all queues were empty.
2026-07-21: Restart and routine down/up preserved the target. The full
application smoke passed after both cycles, and the aggregate targeted probe
matched exactly after volume reattachment.
2026-07-21: Demonstrated rollback connectivity by forwarding the untouched
Supabase URI from ignored .env into a separate PAYLOAD_DB_PUSH=0 Payload
migration-status process. It reported all checked-in migrations applied. The
running web service remained on postgres/anuvax_anu7, and the local volume
was not deleted.
2026-07-21: Acceptance review found and corrected two repeatability gaps. Fresh
target creation now derives its administrative connection from the
always-present loopback postgres database instead of trying to connect to
the not-yet-created target, and restore paths are passed as positional shell
arguments instead of interpolated shell source. Parity now exits nonzero after
writing its ignored report when application state differs. Added regression
coverage; focused Biome, 17 guard tests, and typecheck passed.
2026-07-21: Acceptance review also brought the required verification harness
back to the current implementation contract. The orchestration assertion now
names the split narrative and presentation-analysis actions. Playwright now
starts from a clean .next build, waits for route hydration, starts directly
at Video Setup, uses the current assistant label, and compiles the slides
preview before expecting render readiness. The full integration/unit suite
passed 103 tests, and all six Chromium presentation flows passed against the
migrated local database. The test server still emits non-fatal Better Auth 401
diagnostics while its explicit E2E bypass is active.
2026-07-21: The repository-wide pnpm lint rerun remained failed with exit
code 1 after checking 441 files. Biome 2.3.9 reported exactly six errors and
six warnings across five files unchanged by ANU-7: formatter errors in
docs/_stale/archive/globals.css, docs/stylesheets.css, and
src/payload-types.ts; organize-imports errors in
src/app/(payload)/admin/importMap.js and
src/mastra/tools/presentation/index.ts; one additional formatter error in
src/app/(payload)/admin/importMap.js; and six noImportantStyles warnings
in docs/stylesheets.css. The repository runs Biome 2.3.9, unchanged from
main; its package specification, lock entry, and biome.json configuration
are unchanged. These findings were accepted as an out-of-scope baseline
exception for ANU-7 only; the full lint result remains recorded as failed and
the unrelated files were not modified.
2026-07-21: After recording the exception, the focused Biome check passed all
six ANU-7 TypeScript/config/test files, typecheck passed, the integration/unit
suite passed all 103 tests, and the Chromium project passed all six flows.
Recursive documentation index validation found no missing or empty indexes or
directories, and the strict MkDocs build passed.
Files and documentation updated
package.json and pnpm-lock.yaml for pinned Supabase CLI 2.109.1 and local
database wrapper commands.
scripts/local-stack/database.ts, database-migrate.ts, inventory.sql,
parity-summary.sql, and cutover-verification.sql for guarded migration and
redacted verification behavior.
tests/unit/local-stack.test.ts for inventory plan mode, schema validation,
checksum tamper detection, schema preparation, and target-creation guards.
Local-stack runbook plus testing, environment, command, and known-gap docs.
Repository-wide pnpm lint: failed with exit code 1; exact accepted baseline
was six errors and six warnings across five unchanged files under Biome 2.3.9.
Recursive documentation index validation and strict MkDocs build: passed.
Deviations, risks, and follow-ups
Repository-wide pnpm lint remains failed with six errors and six warnings
across the five unchanged generated/historical and source files recorded
above. Biome 2.3.9, its package specification, lock entry, and configuration
are unchanged from main. This is an ANU-7-only baseline exception, not a
passing lint result; all ANU-7 files pass focused lint.
The required integration/unit and Chromium suites pass. Better Auth 401
diagnostics still appear in the mocked E2E server output even though all six
browser flows complete; cleaning up that non-fatal harness noise is separate
from database parity and cutover behavior.
Source writes were not frozen product-wide, so acceptance proves a consistent
logical snapshot at export time rather than continuous replication after
cutover. Future refreshes must repeat export and parity.