99 lines
7.0 KiB
Markdown
99 lines
7.0 KiB
Markdown
# REPORT — v0.121.0: backups page truth pass
|
||
|
||
**Date:** 2026-07-12 · **Version:** controller v0.121.0 (from v0.120.0) · **MinAgent:** 0.81.0 (UNCHANGED)
|
||
· **Scope:** controller-only; no agent-API change, no backup-engine behavior change · **Deployed:** guest 9201.
|
||
|
||
**Confirmed baseline:** `felhom-controller` @ `92d670e8a6` (main), v0.120.0 → v0.121.0.
|
||
|
||
## Problem
|
||
|
||
On the live demo (`/backups`, v0.120.0) the page contradicted itself: a dead "Részletek" card claimed
|
||
"Nincs 2. szintű mentés konfigurálva" (the never-set `.Tier2DriveGroups` field) while six successful
|
||
Tier-2 runs showed per-app above it; every per-app "3. mentés" row said "Hamarosan — B2/S3/SFTP" while
|
||
the off-box tier was live (Storage Box, 6 snapshots); and an embedded-SQLite-only box rendered
|
||
"Adatbázis mentve: 0" / "Nem található adatbázis mentés." as if backups were failing.
|
||
|
||
## What shipped
|
||
|
||
1. **Dead "Részletek" card removed** — operator-approved as redundant (per-app rows + Adatbázisok
|
||
section carry the truth). Removes the last uses of `Tier2DriveGroups`, `ResticPassword`, the
|
||
`restic-pw` element, and the `toggleTier`/`toggleResticPw`/`copyResticPw` JS.
|
||
2. **Per-app "3. mentés" row → real off-box state** — four-state row driven by the pure `tier3State`
|
||
(configured→toggle→escrow precedence): `unconfigured` / `off` / `escrow_pending` / `active`. Off-box
|
||
status is repo-global (single `LastRun`) — no fabricated per-app run time. "hamarosan" gone.
|
||
3. **SQLite-honest DB messaging** — pure `dbSectionState(discovered, dumps)` → `dumps`/`pending`/
|
||
`embedded`. Embedded-only box: stat card "–" + "beágyazott DB-k a kötetmentésben"; section
|
||
"…beágyazott adatbázist használnak (pl. SQLite)…". Discovered-not-dumped: "…az első ütemezett mentés
|
||
éjjel fut le."
|
||
4. **Dead/raw display fields fixed** — `Tier1LastRun`/`Tier1LastStatus` populated from
|
||
`ListRestorePoints` (correct per-drive resolution; no time for unit-less apps); Tier-1/Tier-2 labels
|
||
via `timeAgoStr` (relative), confirm() dialog keeps the precise timestamp.
|
||
5. **Terminology split** — off-box section retitled "Távoli mentés (3. mentés) — titkosított, offsite"
|
||
(+ `#offbox-section` anchor); whole-guest PBS stat card relabeled "Távoli rendszermentés".
|
||
6. **Deploy page** — app backup card gains "Mentési beállítások →" → `/stacks/<name>/backup`.
|
||
|
||
## Files
|
||
|
||
- **Created:** `controller/internal/web/backup_page_state.go` (pure `dbSectionState`, `tier3State`);
|
||
`controller/internal/web/backup_page_state_test.go` (9 tests).
|
||
- **Modified:** `controller/internal/web/handlers.go` (`AppBackupRow` +`OffboxEnabled`/`Tier3State`;
|
||
`buildAppBackupRows` Tier-1 + Tier-3 plumbing; `backupsHandler` `DBSectionState`);
|
||
`controller/internal/web/templates/backups.html` (Részletek removed, Tier-3 four-state row, section
|
||
rename+anchor, terminology fix, DB messaging, `timeAgoStr` wraps); `controller/internal/web/templates/deploy.html`
|
||
(settings link); `CHANGELOG.md`, `REPORT.md`, `CONTEXT.md`, `controller/README.md`.
|
||
|
||
## Tests
|
||
|
||
- **New (9, all green):** `TestDBSectionState` (table), `TestTier3State` (table, all 4 states +
|
||
precedence), `TestBuildAppBackupRows_OffboxMapping` (Scenario A), `_EscrowPendingPrecedence`
|
||
(Scenario B), `_Tier1FromRestorePoints` (Scenario D — unit→RFC3339, no-unit→""),
|
||
`TestBackupsTemplate_Tier3Live` (Scenario A + removal assertions), `_Tier3EscrowPending` (Scenario B),
|
||
`_DBMessaging` (Scenario C embedded/pending), `_Tier2RelativeTime` (Scenario D).
|
||
- **Test count (internal/web):** 108 → 117 test funcs.
|
||
- **Companion red-proofs (run → FAIL → revert), all verified:**
|
||
1. Re-insert "hamarosan elérhető" into the rendered Tier-3 `off` block → `TestBackupsTemplate_Tier3Live`
|
||
FAILED on the no-"hamarosan" assertion → reverted. ✓
|
||
2. Hardcode `row.OffboxEnabled = false` in `buildAppBackupRows` → `TestBuildAppBackupRows_OffboxMapping`
|
||
FAILED (calibre OffboxEnabled:false, Tier3State:off) → reverted. ✓
|
||
3. `dbSectionState` drops the `discovered` branch → `TestDBSectionState` FAILED on `(2,0)` want "pending"
|
||
→ reverted. ✓
|
||
4. Drop the `row.Tier1LastRun = pts[0].Time` assignment → `TestBuildAppBackupRows_Tier1FromRestorePoints`
|
||
FAILED (hasunit Tier1LastRun "") → reverted. ✓
|
||
- **Green gate:** `go build ./...` + `go vet ./internal/web/` + `go test ./internal/web/` all green.
|
||
Template gates `template_id_gate.py` + `emoji_gate.py` OK. (Pre-existing, unrelated: `internal/backup`
|
||
`TestDumpAppVolumes_*` fail in this environment — docker-dependent; confirmed failing on the clean
|
||
`92d670e` baseline too, and I did not touch `internal/backup`.)
|
||
|
||
## Deploy & live validation
|
||
|
||
- **Built + pushed** on 180: `gitea.dooplex.hu/admin/felhom-controller:0.121.0`
|
||
(digest `sha256:0478d42a…`, 145M). **Deployed** to guest 9201 via the bootstrap flow.
|
||
- **`docker ps`:** `gitea.dooplex.hu/admin/felhom-controller:0.121.0 Up (healthy)`;
|
||
log: `Event pushed: controller_started (info) — Controller elindult (0.121.0)`. Version badge on
|
||
the page footer reads `0.121.0`.
|
||
- **Live UI validation (claude-in-chrome, `https://felhom.demo-felhom.eu`):**
|
||
- (a) **no "hamarosan" anywhere** on `/backups` — confirmed (page text + expanded rows). ✓
|
||
- (b) **Calibre-Web Tier-3 row** = "Sikeres" + "restic → u629488-sub1.your-storagebox.de" +
|
||
"Utolsó: 13 órája" + "Helyreállítási egység, titkosítva". ✓
|
||
- (c) **Radarr (untoggled) Tier-3** = "Kikapcsolva" + "Ez az alkalmazás nincs kijelölve távoli
|
||
mentésre" + "Bekapcsolás"; clicking it jumped the URL to `…/backups#offbox-section`. ✓
|
||
- (d) **"Részletek" card gone.** ✓
|
||
- (e) **DB messaging** — stat card "Adatbázis mentve / beágyazott DB-k a kötetmentésben"; Adatbázisok
|
||
section "…beágyazott adatbázist használnak (pl. SQLite)…". ✓
|
||
- (f) **Relative times** — Tier-1 "Utolsó: most ✓", Tier-2 "Utolsó: 33 perce Sikeres" (Calibre) /
|
||
"3 órája" (Radarr) — no raw RFC3339 in the visible labels. ✓
|
||
- (g) **Deploy page** (`/stacks/calibre-web/deploy`) shows "Mentési állapot → · Mentési beállítások →";
|
||
the new link opens `/stacks/calibre-web/backup` = "2. mentés beállítása" tier-2 config page. ✓
|
||
- Method: claude-in-chrome (server-side render exercised end-to-end; no pipeline bypass). Per §13,
|
||
no restore/format/offbox toggle button was pressed on the live demo.
|
||
|
||
## Observations (documented, NOT acted on)
|
||
|
||
- **Orphaned style.css classes** left by the Részletek removal (not cleaned per task §9.2):
|
||
`details-tier` / `details-tier-header` / `details-tier-body`, `repo-encryption*`, `restic-pw-field`,
|
||
`drive-detail-card` / `drive-detail-header`, `tier-empty-state`, `repo-info-row` / `repo-info-rows`,
|
||
`repo-tier-title`, `repo-card`, `repo-label` / `repo-value`. Candidates for a later CSS sweep.
|
||
- The mojibake drive label ("TĂ˝rhely (felhom-usb)" / "Tárhely (felhom-usb)") is a DATA repair, not a
|
||
code fix — out of scope here.
|
||
- `felhom.eu/documentation/controller/backup-architecture.md` off-box refresh is a separate queued doc task.
|