feat(backup): admin UI with admin-chosen target directory
The backup destination is now chosen by the on-site admin in the UI (Setup -> Backup), not a server env var. An env-pinned target defeats the purpose: the admin can't point backups at a freshly-plugged USB or a NAS mount without editing .env and restarting. The encryption key stays a server secret. Target storage: - New site_config.backup_target_dir (migration 0016, nullable; null = not configured). BackupService reads it fresh each run, so a UI change takes effect with no restart. Only BACKUP_KEY stays env -- a key must never live in the DB it backs up. Routes: - PUT /api/backup/config -- set/clear the target (backup:update; upserts id=1). - POST /api/backup/test -- probe a candidate path server-side (exists / is a directory / writable) so the admin gets feedback before relying on it. - status() now exposes targetDir + keyPresent, so the UI distinguishes 'no target set' from 'BACKUP_KEY missing'. UI (apps/web/src/BackupSettings.tsx): - A Setup -> Backup tab (gated backup:read): an editable target-path field with a Test-target probe (localized ok/missing/not-a-dir/not-writable), Save, the status panel (config state, last-run size/pruned/error, a distinct amber missing-key warning), a Back up now button, and the restore-is-out-of-band note. Full i18n (sq + en); nav.backup. - API client: fetchBackupStatus / setBackupTarget / testBackupTarget / runBackup. Also includes a small in-progress copy trim to the setup-intro i18n strings. Verified live with Playwright: typed a path -> Test reported writable -> Save persisted it -> status reflected it and showed the key-missing warning. Whole monorepo build/lint/test green. Wiki backup-recovery + open-question #5 updated. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -23,9 +23,12 @@ procurement. (See [[parking-system-architecture]] §10.)
|
||||
4. **Reconciliation channel.** Even if "offline," establish *some* periodic path (USB, hotspot,
|
||||
manager visit) to reconcile the signed log against an external authority — the real anti-fraud
|
||||
control. See [[reconciliation]].
|
||||
5. **Durability / backup.** _(Design SETTLED + first slice BUILT 2026-06-29 — see [[backup-recovery]];
|
||||
engine + local/mounted target + daily timer + manual route done, SFTP/UI/restore-tooling pending.)_
|
||||
A disk failure / stolen-or-destroyed PC currently leaves **total revenue-history loss**.
|
||||
5. **Durability / backup.** _(Design SETTLED + engine/target/UI BUILT 2026-06-29 — see
|
||||
[[backup-recovery]]; engine + admin-configured target (site_config, migration 0016) + daily timer +
|
||||
manual route + admin UI (target field, Test-target probe, status, Back-up-now) done; SFTP +
|
||||
restore-tooling pending. The target dir is admin-chosen in the UI, not env; only BACKUP_KEY is a
|
||||
server secret.)_ A disk failure / stolen-or-destroyed PC currently leaves **total revenue-history
|
||||
loss**.
|
||||
Settled design: an **admin-driven encrypted full-DB backup** (online-backup/`VACUUM INTO`, snapshots
|
||||
included) to a **local/USB · SMB/NFS · SFTP** target, **manual button + in-process daily timer**,
|
||||
**keep-last-N + dailies** retention, encrypted with a **dedicated `park_buzi_backup_key`** (separate
|
||||
|
||||
Reference in New Issue
Block a user