Demo Environment Refresh (golden backup → Railway)
| Owner | Classification | Version | Effective | Next review | Status |
|---|---|---|---|---|---|
| Platform Engineering | Internal | 1.0 | 2026-09-05 | 2026-12-05 | Draft |
Purpose. How to refresh a demo environment (typically Railway) with the current demo dataset. The demo state lives in two stores that must move together: the finance Postgres DB and the RustFS object store (attachments, remittance/invoice PDFs, extracted docs). The reproducible unit is a golden pair.
The golden pair
| Golden | What | Format |
|---|---|---|
| DB | the whole finance DB (all schemas incl. demo.* functions, matching config, cash/invoice/journal data) | finance-DEMO-GOLDEN-<desc>-<YYYYMMDD-HHMMSS>.dump — pg_dump -Fc (custom) |
| RustFS | the default bucket contents only | object-store-default-GOLDEN-<YYYYMMDD-HHMMSS>.zip — zip of the bucket's top-level prefixes |
One shared DB backs all four dev clusters, so a single
financedump is the whole demo.
Create the goldens (local)
1. Arm the demo first so the golden captures a clean starting state (scenarios ready, engine not yet run):
SELECT * FROM demo.reset_cashapp(); -- (+ other modules' reset_* as needed)2. DB dump (from the Postgres container):
docker exec blitz-db-1 pg_dump -U postgres -d finance -Fc -f /tmp/g.dump
docker cp blitz-db-1:/tmp/g.dump ~/blitz-goldens/finance-DEMO-GOLDEN-<desc>-$(date +%Y%m%d-%H%M%S).dump3. RustFS zip — the bucket is small (~20 MB / a few hundred files); /data/temp is transient (can be 16 GB) and must be excluded, as must .rustfs.sys. Zip the contents of /data/default so the archive's top level is the bucket prefixes (closehub/, demo/, documentreceipts/, invoice/, journal/, reconciliation/, templates/, uploads/, zhttp/, …):
docker cp blitz-s3:/data/default/. /tmp/g-src/ # bucket contents (excludes .rustfs.sys + temp)
# zip /tmp/g-src/* as object-store-default-GOLDEN-<ts>.zip (host `zip`, or python zipfile if absent)Verify the zip's top-level entries are bucket prefixes (not a wrapping default/ folder).
Restore to Railway
Railway has no shell/psql/docker at demo time, so the pieces move as artifacts:
- DB:
pg_restorethe.dumpinto Railway'sfinanceDB (custom format →pg_restore -d finance). - RustFS: unzip the bucket zip into the RustFS
defaultbucket. - Demo Control: the
demo.*functions ride in the dump; use/system/demo-controlto reset/verify on Railway (no shell needed). See Demo Control. - Services/data-driven bits the dump does not cover: the
emailprocessorservice and thedocument-processqueueTemporal schedule are provisioned per-env — see Email & Document Ingestion.
If you apply migrations instead of copying the DB
When you pull main and apply schema (rather than copy a golden), run the drift ritualbefore prisma generate:
bun run src/scripts/db/check-prisma-drift.ts— lists prisma fields/tables missing from the livefinanceDB (all finance schemas).- Fix each with an idempotent
manual/migration (ADD COLUMN IF NOT EXISTS …).finbase.sqlis pureCREATE TABLE IF NOT EXISTS+ indexes (noDROP/INSERT/ALTER) — safe to rerun; it only creates what's missing. For a changed column on an existing table,IF NOT EXISTSwon't alter it — drop that one (empty) table first, then rerunfinbase.sqlto recreate it with the new shape. - Re-run the drift check until
✓ no drift, thenprisma generate.
Known recurring trap: a prisma field added without a
manual/migration → the column is missing in the DB → 500s. The drift check catches it every time.
Constraints
- Always take a fresh DB dump before a schema-mutating step (drop/rerun), even though a recent golden exists — keeps the demo golden pristine and gives a precise rollback point.
- Never commit
db-backups/or~/blitz-goldens/artifacts to git. - The DB and RustFS goldens are a matched pair — restore both, or attachments/PDFs won't resolve for records the DB references.
Related
Revision history
| Version | Date | Author | Change |
|---|---|---|---|
| 1.0 | 2026-09-05 | Platform Engineering | Initial runbook — golden pair (DB dump + RustFS bucket zip) format + create/restore, and the post-pull drift ritual. |