docs: add monthly backup verification owner

Align the approved backup design and implementation plan on the monthly full Restic integrity check and disposable restore rehearsal without adding production code.

Constraint: PostgreSQL logical dump plus tdlib_state and tdlib_bot_state only

Rejected: Add a second production timer or backup script changes | outside requested docs-only scope

Confidence: high

Scope-risk: narrow
This commit is contained in:
2026-07-22 09:19:15 +02:00
parent a8818dcf0c
commit 3536089d52
3 changed files with 81 additions and 10 deletions
@@ -0,0 +1,71 @@
# Backup Scope-Correction Documentation Report
**Date:** 2026-07-22
## Changed files
- `docs/superpowers/specs/2026-07-21-database-and-file-backups-design.md`
- `docs/superpowers/plans/2026-07-21-database-and-file-backups.md`
- `.superpowers/sdd/scope-correction-docs-report.md`
## Rationale
The backup design and implementation plan now define the protected data set as a PostgreSQL logical dump plus the `tdlib_state` and `tdlib_bot_state` session volumes. They continue to require a host-restricted Synology NFS repository, Restic encryption, 30 daily snapshots, service quiescing, guarded restore, and session persistence.
`manual_uploads` and `tmp_zips` are explicitly excluded. The documents no longer require local retention of completed STL binaries, worker cleanup changes, database lifecycle fields for retained uploads, restored local STL files, or file-path validation. They state that STL binaries remain in Telegram and that the restored database preserves the metadata and mappings required to locate and send them.
Future Telegram channel-forwarding behavior and archive/STL-content integrity validation are explicitly identified as out of scope and future work.
## Checks run
- `git diff --check`
- Scope scan of both documents for `manual_uploads`, `tmp_zips`, local STL retention, file-path validation, channel forwarding, and integrity language.
- Reviewed the final diff to confirm the removed implementation work is limited to the specified backup-scope correction.
- `git status --short` to confirm the commit stages only the two requested documents and this required report.
## Concerns
- This change intentionally updates documentation only. It does not modify backup scripts, Docker Compose, database schema, worker cleanup, or Telegram behavior.
- A future implementation should validate its actual backup manifests and Compose mounts against this corrected plan before deployment.
---
# Monthly Backup Verification Documentation Follow-up
**Date:** 2026-07-22
## Fix
Aligned the approved backup design and implementation plan on the missing recurring operational work. The deployment operator now owns a documented monthly manual runbook task to run full `restic check --read-data`, perform a disposable restore rehearsal, and record the date, snapshot ID, integrity-check result, restore/health result, and cleanup result.
The plan verifies the first full-read check and rehearsal during acceptance, then carries the same procedure into the monthly runbook without adding a second systemd timer, script, or other production implementation. The Synology wording now precisely identifies the dedicated shared folder's NFS export as restricted to the Docker host's fixed IP.
## Scope preserved
The recovery set remains the PostgreSQL logical dump plus `tdlib_state` and `tdlib_bot_state` only. `manual_uploads`, STL binaries, archive/STL-content integrity, and future channel-forwarding checks remain outside this work.
## Checks completed
- `git diff --check` completed with no whitespace errors.
- Focused assertions passed: `restic check --read-data` (4 matches), `deployment operator` (3), `disposable restore rehearsal` (6), `manual_uploads` (8), and `archive/STL-content integrity` (4) across the two approved documents.
- Final diff review confirmed that this follow-up changes documentation only; no backup scripts, Compose configuration, or other production implementation files were modified.
---
# Monthly Backup Verification Review-Finding Fix
**Date:** 2026-07-22
## Fix
Confirmed and kept the approved design and implementation plan aligned on the reviewer finding: monthly recovery verification is an operator-owned operational task, consisting of a full `restic check --read-data` and a disposable restore rehearsal.
## Scope
The approved docs continue to limit the protected recovery set to the PostgreSQL logical dump, `tdlib_state`, and `tdlib_bot_state`. They do not add `manual_uploads`, STL-binary restore/checks, archive-content integrity checks, future channel-forwarding checks, or any new production timer/script.
## Checks
- `git diff --check`
- Focused scope assertions over the two approved docs for monthly full Restic check/rehearsal wording and exclusions.
- Staged-file review before commit to confirm the commit contains documentation/report files only.
@@ -336,7 +336,7 @@ git commit -m "feat: add guarded database and session restore"
- [ ] **Step 1: Document Synology configuration** - [ ] **Step 1: Document Synology configuration**
Document creating the `dragonsstash-backups` shared folder, enabling NFS, restricting the export to the Docker host's fixed IP, and mounting it at `/mnt/dragonsstash-backups`. Include commands for checking the mount: Document creating the `dragonsstash-backups` shared folder, enabling NFS, and configuring that shared folder's NFS export to allow only the Docker host's fixed IP. Document mounting it at `/mnt/dragonsstash-backups`. Include commands for checking the mount:
```bash ```bash
mountpoint /mnt/dragonsstash-backups mountpoint /mnt/dragonsstash-backups
@@ -365,9 +365,9 @@ sudo journalctl -u dragons-stash-backup.service -n 100 --no-pager
Explain that the first run captures PostgreSQL and TDLib session state. State clearly that STL binaries stay in Telegram, and that restored PostgreSQL metadata and mappings are what allow normal lookup and delivery after restore. Explain that the first run captures PostgreSQL and TDLib session state. State clearly that STL binaries stay in Telegram, and that restored PostgreSQL metadata and mappings are what allow normal lookup and delivery after restore.
- [ ] **Step 4: Document monitoring, retention, and restore** - [ ] **Step 4: Document monitoring, retention, restore, and the monthly recovery check**
Document how to inspect timer status, service failures, Restic snapshots, repository checks, and the four restore modes. Explicitly state that `restore-live` is destructive and requires the confirmation flag. Explain that channel-forwarding behavior and archive/STL-content integrity validation are future work, not restore checks. Document how to inspect timer status, service failures, Restic snapshots, repository checks, and the four restore modes. Explicitly state that `restore-live` is destructive and requires the confirmation flag. Assign the deployment operator a recurring monthly runbook task: run `docker compose --profile backup run --rm backup check --read-data`, then perform the documented disposable restore rehearsal using a selected snapshot. Record the date, snapshot ID, full-check result, restore/health result, and cleanup result. This is an operator-owned manual procedure, not a second production timer or a change to the nightly backup service. Limit the rehearsal to the PostgreSQL logical dump, `tdlib_state`, and `tdlib_bot_state`; do not add `manual_uploads`, STL-binary, archive-content, or channel-forwarding checks. Explain that channel-forwarding behavior and archive/STL-content integrity validation are future work, not restore checks.
- [ ] **Step 5: Add a concise production-backup section to the root README** - [ ] **Step 5: Add a concise production-backup section to the root README**
@@ -387,7 +387,7 @@ git commit -m "docs: document Synology backup and recovery"
**Interfaces:** **Interfaces:**
- Consumes: the complete backup stack from Tasks 1-5. - Consumes: the complete backup stack from Tasks 1-5.
- Produces: evidence that the acceptance criteria are met, including a disposable restore rehearsal and a failure-path result. - Produces: evidence that the acceptance criteria are met, including a full `restic check --read-data`, a disposable restore rehearsal, and a failure-path result. After deployment, the same full-check and rehearsal are an operator-owned monthly runbook task documented in Task 5.
- [ ] **Step 1: Validate configuration and scripts** - [ ] **Step 1: Validate configuration and scripts**
@@ -422,9 +422,9 @@ Expected: the service succeeds, the snapshot exists, the repository check succee
Temporarily unmount the Synology share in a controlled maintenance session, run the systemd service, and confirm it fails before creating a new snapshot. Remount the share and confirm the previously successful snapshot remains listed. Verify that services are running after the failed attempt. Temporarily unmount the Synology share in a controlled maintenance session, run the systemd service, and confirm it fails before creating a new snapshot. Remount the share and confirm the previously successful snapshot remains listed. Verify that services are running after the failed attempt.
- [ ] **Step 5: Rehearse a disposable restore** - [ ] **Step 5: Run the full-read integrity check and rehearse a disposable restore**
Restore the selected snapshot to a disposable Compose project or isolated Docker volumes. Import the database dump, restore the two TDLib session trees, start the disposable app/worker/bot services, and call `/api/health`. Confirm the recognizable database metadata and Telegram mappings match the pre-backup record. Do not assert the presence, checksum, content, or forwarding behavior of STL binaries. Run `docker compose --profile backup run --rm backup check --read-data` against the selected repository, then restore the selected snapshot to a disposable Compose project or isolated Docker volumes. Import the database dump, restore the two TDLib session trees, start the disposable app/worker/bot services, and call `/api/health`. Confirm the recognizable database metadata and Telegram mappings match the pre-backup record. Record the check and rehearsal evidence as the initial monthly-runbook baseline. Do not assert the presence, checksum, content, or forwarding behavior of STL binaries.
- [ ] **Step 6: Verify retention behavior** - [ ] **Step 6: Verify retention behavior**
@@ -443,7 +443,7 @@ git commit -m "test: document verified backup and restore procedure"
## Plan Self-Review ## Plan Self-Review
- **Spec coverage:** PostgreSQL logical dump, both Telegram session volumes, Synology NFS, Restic encryption, 30-day retention, maintenance window, service restart on failure, guarded restore, monthly repository/restore checks, database metadata recovery, and NAS-loss caveat are covered by Tasks 1-6. - **Spec coverage:** PostgreSQL logical dump, both Telegram session volumes, Synology NFS, Restic encryption, 30-day retention, maintenance window, service restart on failure, guarded restore, and an explicitly deployment-operator-owned monthly `restic check --read-data` plus disposable restore rehearsal are covered by Tasks 1-6. The initial run is verified in Task 6 and the recurring runbook is documented in Task 5; neither adds a second production timer.
- **Exclusions:** `manual_uploads` and `tmp_zips` are excluded; local STL retention, restored STL binaries, file-path/checksum validation, channel forwarding, and archive/STL-content integrity checks are not implementation requirements. - **Exclusions:** `manual_uploads` and `tmp_zips` are excluded; local STL retention, restored STL binaries, file-path/checksum validation, channel forwarding, and archive/STL-content integrity checks are not implementation requirements.
- **Placeholder scan:** No `TBD`, `TODO`, or unspecified implementation task remains. Environment-dependent values are explicit configuration variables or operator-supplied paths. - **Placeholder scan:** No `TBD`, `TODO`, or unspecified implementation task remains. Environment-dependent values are explicit configuration variables or operator-supplied paths.
- **Type/interface consistency:** The Compose service name is consistently `backup`; the container command modes are `backup` and `restore`; the host wrapper owns service lifecycle; the restore script owns destructive confirmation; Restic owns snapshots and pruning. - **Type/interface consistency:** The Compose service name is consistently `backup`; the container command modes are `backup` and `restore`; the host wrapper owns service lifecycle; the restore script owns destructive confirmation; Restic owns snapshots and pruning.
@@ -42,8 +42,7 @@ This approach keeps backup and restore explicit, avoids tying recovery to Postgr
Create a dedicated shared folder, for example `dragonsstash-backups`, with: Create a dedicated shared folder, for example `dragonsstash-backups`, with:
- NFS enabled only for the Docker host's fixed IP address. - The dedicated backup shared folder is exported through NFS only to the Docker host's fixed IP address.
- A restricted NFS export used only for this backup share, with host access limited to the Docker host's fixed IP address.
- No Internet exposure. - No Internet exposure.
- Sufficient capacity for the repository plus growth and safety margin. - Sufficient capacity for the repository plus growth and safety margin.
@@ -103,7 +102,7 @@ The restore process must be safe to rehearse against a disposable Compose projec
- Backup failure produces a non-zero systemd result and a clear log entry. - Backup failure produces a non-zero systemd result and a clear log entry.
- Retention pruning runs only after a verified successful snapshot. - Retention pruning runs only after a verified successful snapshot.
- A snapshot listing and repository metadata check run after each backup. - A snapshot listing and repository metadata check run after each backup.
- A full Restic integrity check and disposable restore test run monthly. - The deployment operator completes and records a monthly operational check: `restic check --read-data` followed by a disposable restore rehearsal. This verifies only the PostgreSQL logical dump and TDLib session-state recovery set; archive/STL-content integrity and future forwarding checks remain out of scope.
- The project documentation describes how to inspect the last successful snapshot and how to recover when the NAS is unavailable. - The project documentation describes how to inspect the last successful snapshot and how to recover when the NAS is unavailable.
## Security considerations ## Security considerations
@@ -119,6 +118,7 @@ The restore process must be safe to rehearse against a disposable Compose projec
- A nightly systemd timer creates a Restic snapshot on the Synology share. - A nightly systemd timer creates a Restic snapshot on the Synology share.
- A snapshot includes a PostgreSQL logical dump and both Telegram session volumes, while excluding `manual_uploads` and `tmp_zips`. - A snapshot includes a PostgreSQL logical dump and both Telegram session volumes, while excluding `manual_uploads` and `tmp_zips`.
- At least 30 daily recovery points are retained. - At least 30 daily recovery points are retained.
- Each month, the deployment operator runs and records a full `restic check --read-data` and a disposable restore rehearsal of the PostgreSQL dump plus both TDLib session volumes.
- A simulated host-loss restore reconstructs the database and Telegram session state in a disposable Compose environment. - A simulated host-loss restore reconstructs the database and Telegram session state in a disposable Compose environment.
- The restored database retains the Telegram metadata and mappings the worker and bot use to locate and send STL binaries that remain in Telegram. - The restored database retains the Telegram metadata and mappings the worker and bot use to locate and send STL binaries that remain in Telegram.
- A failed backup leaves services running and preserves the last known-good snapshot. - A failed backup leaves services running and preserves the last known-good snapshot.