Database Readiness Gate
Date: 2026-05-05
Objective
Make the database state explicit before the Hetzner stack is treated as deployable.
The previous local runtime proof showed that the services can start. This gate adds a database-specific proof:
- Studio API migrations exist and have been applied locally.
- Zweistein has a synchronized schema locally, but no migration source was found in the imported snapshot.
- Hetzner needs an explicit Studio migration step before application startup is considered ready.
What Was Added
scripts/database-gate.mjsLocal and Hetzner database helper for migration/table-count checks and Studio API migration execution.package.jsonscripts:db:local:checkhetzner:db:planhetzner:db:commandshetzner:db:studio:migratehetzner:db:check
Local Evidence
Run:
npm run db:local:check
Latest result:
- Studio API migration source files: 84.
- Studio API applied migrations: 84.
- Studio API public tables: 37.
- Studio API latest migration:
AddExternalUsersToFlowProtection1758128437372. - Zweistein public tables: 39.
- Zweistein
src/dataSource.ts: not present. - Zweistein
src/migrations: not present. - Zweistein migration files: 0.
- Zweistein primary TypeORM connection has
synchronize:true.
No database rows or secret values are printed.
Hetzner Database Sequence
Run this after real env values exist and after the relevant images are built:
npm run hetzner:db:plan
npm run hetzner:db:commands
npm run hetzner:db:studio:migrate
npm run hetzner:db:check
The helper runs the Studio API migration command through the Compose service:
docker compose --env-file configs/hetzner/frontend-build.env -f docker-compose.hetzner.yml run --rm --no-deps studio-api npm run migration:run
Then it checks migration and table counts through Postgres without printing table rows.
Zweistein Boundary
The imported Zweistein server currently has package scripts for migrations, but the expected TypeORM data source and migration files are not present:
legacy-src/zweistein/server/src/dataSource.ts: missing.legacy-src/zweistein/server/src/migrations: missing.
The primary Zweistein DB connection currently uses:
synchronize: true
That is acceptable as a local preservation proof, because it creates the legacy schema from the entities. It is not a production-grade Hetzner database strategy.
Before a production cutover, one of these must happen:
- recover the original Zweistein migration history;
- create a baseline migration from the synchronized schema;
- create a fresh migration plan for the rebuilt service.
Local Verification Evidence
node --check scripts/database-gate.mjspassed.npm run db:local:checkpassed.npm run hetzner:db:planprints the DB sequence and current source facts.npm run hetzner:db:commandsprints the exact Compose/Postgres commands.npm run hetzner:db:checkfails locally as expected because it is guarded for native Linux x64/amd64.
Current Boundary
The DB gate is ready as a helper, but it has not been executed on a real Hetzner server yet.