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>
58 lines
2.8 KiB
Markdown
58 lines
2.8 KiB
Markdown
# 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):
|
|
1. PostgreSQL: nightly `pg_dump -Fc` from a backup sidecar container.
|
|
2. Uploads + plugins volume: nightly `tar` archive (or rsync snapshot)
|
|
taken **after** the dump, referencing the same backup id.
|
|
- **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
|
|
dedicated `dorfteich-backup` user with home under `/home/` is created on
|
|
BASEL (per the operator's "cleaner alternative" note — not reusing the
|
|
Debian `backup` system 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 via
|
|
`pg_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).
|
|
- **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.
|