# 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//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.