Backup & restore
Backups
Section titled “Backups”- Logical:
scripts/backup.sh [PG_URL] [OUT_DIR]→ timestampedpg_dumpcustom-format file. Schedule daily (cron/CI) and ship off-host (object storage) with retention. - Managed Postgres: also enable the provider’s automated backups + point-in-time recovery. Keep both; logical dumps are portable, PITR is finer-grained.
Restore drill (run regularly — proves the backup, not just that it exists)
Section titled “Restore drill (run regularly — proves the backup, not just that it exists)”make restore-drill # restores the latest ./backups dump into riser_restore_test# or explicitly:bash scripts/restore.sh <dump-file> riser_restore_testThe drill drops + recreates the target DB and pg_restores into it. Verify after: table count,
seeded plans, and a known row are present (this was exercised in Phase 10 — 22 tables + data
restored cleanly). Drop the scratch DB when done.
Real restore (incident)
Section titled “Real restore (incident)”- Stop writes to the affected DB (scale backend to 0 / maintenance mode).
- Restore the latest good dump into a new database; do not overwrite the live one until validated.
- Validate: row counts, latest telemetry timestamps, a login + dashboard load.
- Cut over
DATABASE_URLto the restored DB; redeploy backend; verifyGET /health. - Note the data-loss window (since the last good backup) and communicate it.
DR plan (summary)
Section titled “DR plan (summary)”- RPO: ≤ 24h via daily logical dumps; tighter with managed PITR.
- RTO: restore + cutover, target < 1h for a single-region failure.
- Heating during DR: unaffected — controllers run locally and buffer telemetry; the platform DR is about visibility/history/ops, never about keeping buildings warm.