Problem
Current docker-compose.yml only mounts a PostgreSQL volume (postgres_data). No automated backups, no PITR, no restore drills documented.
Risks
| Scenario |
Impact |
Current Mitigation |
| Disk failure / volume corruption |
Total data loss |
None |
Accidental DROP TABLE / bad migration |
Hours of downtime |
Manual pg_dump if remembered |
Ransomware / TRUNCATE |
Irrecoverable |
None |
| Need to clone prod → staging |
Manual, error-prone |
None |
Requirements
1. Automated Backups (PITR-ready)
- Tool:
pgBackRest or wal-g (recommended: pgBackRest — supports S3/GCS/Azure, parallel, compression, encryption)
- Schedule:
- Full backup: daily 02:00 UTC
- Incremental: every 6h
- WAL archiving: continuous (streaming replication slot)
- Retention: 30 daily fulls + 7 weekly + 12 monthly
- Storage: S3-compatible (MinIO for dev, AWS S3/GCS for prod) with lifecycle policy
- Encryption: AES-256 at rest (pgBackRest
--repo1-cipher-type=aes-256-cbc)
2. Point-in-Time Recovery (PITR)
- Restore to any second within retention window
- Target: RPO < 5 min (WAL archiving), RTO < 30 min (restore parallelism)
- Documented
pgbackrest restore --type=time --target=... procedure
3. Restore Automation (CI/CD + Runbook)
- Staging refresh job: Weekly, restores latest backup to
staging-db, runs migrations, validates schema checksum
- Disaster drill: Quarterly, restore to fresh cluster, verify app comes up, document timing
- Runbook:
docs/DISASTER_RECOVERY.md with:
- Step-by-step restore commands
- Contact tree (on-call, infra, security)
- RTO/RPO targets
- Post-restore validation checklist
4. Monitoring & Alerting
- Backup success/failure → alert (PagerDuty/Slack)
- WAL lag > 5 min → alert
- Backup age > 26h → alert (missing daily)
- Restore drill overdue → alert
Implementation Plan
| Phase |
Task |
Owner |
Est. |
| 1 |
Add pgbackrest sidecar to docker-compose.yml (dev) + Helm chart (prod) |
Infra |
1d |
| 2 |
Configure S3 repo, encryption, retention |
Infra |
0.5d |
| 3 |
Implement WAL archiving (replication slot) |
Infra |
0.5d |
| 4 |
Write restore script + staging refresh job (GitHub Actions) |
Infra |
1d |
| 5 |
Document runbook (docs/DISASTER_RECOVERY.md) |
Infra/Backend |
0.5d |
| 6 |
First disaster drill (schedule, execute, document) |
Team |
2h |
| 7 |
Add alerts (Prometheus rules / pgBackRest webhook) |
Infra |
0.5d |
Acceptance Criteria
References
Problem
Current
docker-compose.ymlonly mounts a PostgreSQL volume (postgres_data). No automated backups, no PITR, no restore drills documented.Risks
DROP TABLE/ bad migrationpg_dumpif rememberedTRUNCATERequirements
1. Automated Backups (PITR-ready)
pgBackRestorwal-g(recommended:pgBackRest— supports S3/GCS/Azure, parallel, compression, encryption)--repo1-cipher-type=aes-256-cbc)2. Point-in-Time Recovery (PITR)
pgbackrest restore --type=time --target=...procedure3. Restore Automation (CI/CD + Runbook)
staging-db, runs migrations, validates schema checksumdocs/DISASTER_RECOVERY.mdwith:4. Monitoring & Alerting
Implementation Plan
pgbackrestsidecar todocker-compose.yml(dev) + Helm chart (prod)docs/DISASTER_RECOVERY.md)Acceptance Criteria
pgbackrest --stanza=micopay backupsucceeds in CIpgbackrest --stanza=micopay restore --type=time --target="2026-07-27 12:00:00"restores to fresh DB in < 30 mindocs/DISASTER_RECOVERY.mdexists and is accurateReferences