Adopt a two-level ownership model: a customer owns many sites, with isolation/containers/DB/backup at the site level and grouping (one SFTP login, recursive backup, billing, bulk delete) at the customer level. - 03-naming-conventions: rewritten for customer/site ids and slug = <customer>-<site>; nested ZFS, per-customer SFTP chroot, deployments mirror the nesting. - Propagated paths through docs 01, 04, 05, 06, 07 and deployments/README. - ADR 0005 retitled/updated to per-site datasets nested under customer. - architecture-plan.md: note pointing to doc 03 as authoritative on naming. Clarifies subdomains: same-app subdomains are aliases on one site; a separate-app subdomain is its own isolated site under the same customer. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1.3 KiB
1.3 KiB
ADR 0005 — ZFS dataset per site (nested under customer)
Status: Accepted
Context
Backups must be cheap, integrity-checked, and restorable per customer without
touching neighbours. ZFS offers checksummed integrity, cheap copy-on-write
snapshots, and incremental zfs send.
Decision
Create a ZFS dataset per site, nested under the owning customer
(tank/customers/<customer>/<site>/web), holding only the web root. The
customer level is a grouping parent enabling recursive snapshots and a single
SFTP chroot; the site level is the isolation/restore unit. Docker image/layer
storage and the MariaDB datadir live on separate platform datasets. Site web
data is bind-mounted into containers from its dataset.
Consequences
- ✅ Snapshot and
zfs sendoperate at the customer granularity — restore one customer independently. - ✅ Data integrity via checksums; cheap frequent snapshots.
- ✅ Keeping the dataset to web files only (no logs, no DB dumps) means an
unchanged site produces a near-empty incremental, keeping offsite
sendcheap — the explicit reason logs and DB dumps are stored elsewhere (ADR 0006). - ❌ Ties the platform to a ZFS-capable host (OpenZFS on Linux); not portable to arbitrary cloud block storage without rework.