Implement scheduled database backup with configurable destinations #26

Open
opened 2026-07-28 04:55:09 +00:00 by claude-bot · 1 comment

Context

The database holds every dating decision, every piece of evidence, and the full audit
history — the entire product of the review work. The photo files are replaceable by
rescanning; the review history is not. There is currently no backup of any kind.

Scope

Scheduled database backup with configurable destinations, using the existing
JobType.backup.

Implementation notes

  • Use SQLite's online backup API or VACUUM INTO, not a filesystem copy. Copying a WAL
    database while it is being written produces a corrupt backup that looks fine until it
    is needed.
  • Verify each backup after writing it — at minimum a PRAGMA integrity_check on the
    result. An unverified backup is a guess.
  • Configurable destinations behind a small interface: local path first, with the shape
    ready for the S3 backend in v0.5.0.
  • Configurable retention with pruning, so backups cannot fill the disk.
  • Scheduling via the backup job type on the existing worker.
  • Record outcome, size, duration, and destination for each run so failures are visible
    rather than silent. A backup system that fails quietly is worse than none, because it
    removes the motivation to have another.
  • Document the restore procedure and test it — an untested restore path is not a
    backup. Restoration should be verifiable in a scratch environment.
  • Backups contain personal data: document their sensitivity and keep credentials out of
    the repo.

Done when

  • Backups run on schedule via the worker
  • Each backup is integrity-checked after writing
  • Destination and retention are configurable, with pruning
  • Failures are recorded and visible
  • The restore procedure is documented and exercised at least once

References

  • backend/app/models/models.py (JobType.backup)
  • docs/circa-spec.md Phase 2

Depends on: #2 (worker runtime).

## Context The database holds every dating decision, every piece of evidence, and the full audit history — the entire product of the review work. The photo files are replaceable by rescanning; the review history is not. There is currently no backup of any kind. ## Scope Scheduled database backup with configurable destinations, using the existing `JobType.backup`. ## Implementation notes - Use SQLite's online backup API or `VACUUM INTO`, not a filesystem copy. Copying a WAL database while it is being written produces a corrupt backup that looks fine until it is needed. - Verify each backup after writing it — at minimum a `PRAGMA integrity_check` on the result. An unverified backup is a guess. - Configurable destinations behind a small interface: local path first, with the shape ready for the S3 backend in v0.5.0. - Configurable retention with pruning, so backups cannot fill the disk. - Scheduling via the `backup` job type on the existing worker. - Record outcome, size, duration, and destination for each run so failures are visible rather than silent. A backup system that fails quietly is worse than none, because it removes the motivation to have another. - Document the restore procedure and **test it** — an untested restore path is not a backup. Restoration should be verifiable in a scratch environment. - Backups contain personal data: document their sensitivity and keep credentials out of the repo. ## Done when - [ ] Backups run on schedule via the worker - [ ] Each backup is integrity-checked after writing - [ ] Destination and retention are configurable, with pruning - [ ] Failures are recorded and visible - [ ] The restore procedure is documented and exercised at least once ## References - `backend/app/models/models.py` (`JobType.backup`) - `docs/circa-spec.md` Phase 2 Depends on: #2 (worker runtime).
claude-bot added this to the v0.4.0 milestone 2026-07-28 04:55:09 +00:00
Author

Amended by the audit of 2026-07-28 — the scope of this issue is wrong.

This issue states photo files are "replaceable by rescanning" and therefore backs up only the
database. The user has confirmed that assumption does not hold: the physical originals are being
kept, but they are inconvenient to access and continuing to degrade.

So rescanning is not a recovery plan — it is weeks of work that produces worse scans than the
ones being replaced.

Storage-tree backup, executable restore, and scheduled restore verification are now tracked in
#117. Keep this issue for the database backup mechanism; treat #117 as its required companion
rather than a nice-to-have.

**Amended by the audit of 2026-07-28 — the scope of this issue is wrong.** This issue states photo files are "replaceable by rescanning" and therefore backs up only the database. The user has confirmed that assumption does not hold: the physical originals are being kept, but they are inconvenient to access and **continuing to degrade**. So rescanning is not a recovery plan — it is weeks of work that produces *worse* scans than the ones being replaced. Storage-tree backup, executable restore, and scheduled restore verification are now tracked in #117. Keep this issue for the database backup mechanism; treat #117 as its required companion rather than a nice-to-have.
Sign in to join this conversation.
No description provided.