From 08ab293dfc91e79e279923217585917161dbe70d Mon Sep 17 00:00:00 2001 From: gitaddremote Date: Tue, 28 Apr 2026 16:50:15 -0400 Subject: [PATCH] docs: add backup operations runbook Adds infra/docs/backups.md covering all 7 sections required by #133: - What is backed up (PostgreSQL, nightly at 3AM UTC + pre-deploy) - Where backups live (B2 bucket path structure) - How to verify backups are running (log tail + healthchecks.io) - What to do when a backup alert fires (5-step checklist) - Retention policy (180-day B2 lifecycle) - How to silence a false alarm (healthchecks.io pause/mute) - How to restore using restore-db.sh Also updates infra/README.md to reference #133 and the new doc. Closes #133 --- infra/README.md | 6 +++ infra/docs/backups.md | 91 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 infra/docs/backups.md diff --git a/infra/README.md b/infra/README.md index fd2b496..75e3ac8 100644 --- a/infra/README.md +++ b/infra/README.md @@ -89,6 +89,12 @@ Issue `#125` adds the production backup contract: The production release workflow writes `/opt/station/rclone.conf` from GitHub environment secrets and runs a pre-deploy backup before rolling the backend forward. +Issue `#133` adds backup failure alerting via a healthchecks.io dead-man's switch: + +- `backup-db.sh` pings `BACKUP_HEALTHCHECK_URL` after a successful upload; if the ping is absent, healthchecks.io fires an alert +- `BACKUP_HEALTHCHECK_URL` is a production-only GitHub environment secret written into `.env.production` at deploy time +- See `infra/docs/backups.md` for operational procedures: verification, alert response, retention policy, and restore steps + ## Redis Persistence Issue `#126` enables Redis AOF persistence in both compose stacks and documents verification/recovery in `infra/docs/redis.md`. diff --git a/infra/docs/backups.md b/infra/docs/backups.md new file mode 100644 index 0000000..3bc9b2e --- /dev/null +++ b/infra/docs/backups.md @@ -0,0 +1,91 @@ +# Backup Operations + +## What is backed up + +PostgreSQL data only. The database is backed up: + +- **Nightly** at 3 AM UTC (cron job on the VPS) +- **Pre-deploy** before every production release (triggered by `release.yml`) + +Redis is not backed up — its contents are derived from the database and repopulate automatically. + +## Where backups live + +Backblaze B2 bucket: `station-backups` + +Path structure: `postgres/YYYYMM/YYYYMMDD_HHMMSS_