Initial deliverable of the architecture phase: 16 ADRs (stack, CRDT collaboration, plugin sandbox, import/export, backups, CI/CD), data model, permission model, real-time collaboration and plugin concepts, deployment/operations/security documentation, and the milestone roadmap that the implementation issues are derived from. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2.8 KiB
2.8 KiB
ADR 0015: Nightly pg_dump + uploads sync, 30-day retention, off-host mirror
- Status: accepted
- Date: 2026-07-04
Context
The operator's standard for database-driven apps applies (global
convention): nightly dump via sidecar, ~30 days local retention, manual
download/restore via admin UI, mirroring of nightly dumps to the BASEL host
over WireGuard (/home/RAID/BACKUPS/<app>/). Dorfteich adds a second
persistence root: the uploads/plugins volume (ADR 0011).
Decision
- What is backed up (together forming a consistent restore set):
- PostgreSQL: nightly
pg_dump -Fcfrom a backup sidecar container. - Uploads + plugins volume: nightly
tararchive (or rsync snapshot) taken after the dump, referencing the same backup id.
- PostgreSQL: nightly
- Retention: 30 days locally (both artifact types), pruned by the sidecar.
- Mirroring: nightly rsync of the local backup directory to BASEL,
target
/home/RAID/BACKUPS/dorfteich-<stage>/, same retention. A dedicateddorfteich-backupuser with home under/home/is created on BASEL (per the operator's "cleaner alternative" note — not reusing the Debianbackupsystem user, avoiding its UID-34/home-path pitfalls). - Scope per stage: Prod is fully backed up + mirrored. Test/Int get the nightly dump with 7-day local retention and no off-host mirror (reproducible from Prod data or fixtures). This is the deliberate, ADR-documented deviation from the standard pattern for non-Prod stages.
- Restore paths:
- Documented CLI runbook (
operations.md): stop stack → restore dump viapg_restore→ restore volume archive → start stack. Practiced against Test in a recurring story ("restore drill"). - Admin UI: Site Admin can download the latest dumps and trigger an on-demand backup. Restore stays a CLI operation (a web-triggered restore of the database that serves the web UI is a foot-gun).
- Documented CLI runbook (
- Integrity/alerting: the sidecar writes a status file consumed by the
health endpoint; a failed or missing nightly backup raises an alert
(see
operations.md). Dump restorability is verified monthly by an automated restore into a scratch database on Test.
Consequences
- Consistency between database and file volume is "nightly point-in-time, files may be minutes newer" — acceptable: a restored page referencing a file uploaded after the dump shows a missing image, never corruption.
- Moving Prod to a dedicated host keeps the identical sidecar; only the WireGuard/rsync route changes (ADR 0014 consequence applies).
Alternatives considered
- WAL archiving / PITR (e.g. pgBackRest): better RPO, but operationally heavier than the standard pattern warrants at this scale; revisit if Dorfteich.online grows.
- Volume backup via S3-compatible offsite: no existing infrastructure; BASEL mirror is the established pattern.