controller v0.121.0: backups page truth pass — remove dead Részletek card, real Tier-3 off-box state, SQLite-honest DB messaging

MinAgent: 0.81.0 (unchanged). Controller-only; no agent-API change, no backup-engine
behavior change. Fixes the self-contradicting /backups page (v0.120.0 live):

- Remove the dead "Részletek" card (redundant; kills never-set Tier2DriveGroups/
  ResticPassword fields + restic-pw element + toggleTier/toggleResticPw/copyResticPw JS).
- Per-app "3. mentés" row shows real off-box state via pure tier3State
  (unconfigured/off/escrow_pending/active) — "Hamarosan" placeholder gone.
- SQLite-honest DB messaging via pure dbSectionState (dumps/pending/embedded).
- Populate Tier1LastRun/Tier1LastStatus from ListRestorePoints; Tier-1/Tier-2 labels
  via timeAgoStr (relative), confirm() dialog keeps raw timestamp.
- Terminology split: "Távoli mentés (3. mentés)" (off-box, +#offbox-section anchor)
  vs "Távoli rendszermentés" (PBS whole-CT).
- Deploy page: add "Mentési beállítások →" link.

+9 internal/web tests (pure helper tables + buildAppBackupRows wiring + template
renders), 4 companion red-proofs run→fail→revert.
This commit is contained in:
2026-07-12 12:26:30 +02:00
parent 92d670e8a6
commit 9d05fa5c35
9 changed files with 604 additions and 174 deletions
+36 -1
View File
@@ -653,6 +653,10 @@ func (s *Server) backupsHandler(w http.ResponseWriter, r *http.Request) {
data["Backup"] = fullStatus
// DB-section state — honest messaging for embedded-DB-only boxes (SQLite etc.):
// "dumps" (real dumps) | "pending" (discovered, first run tonight) | "embedded".
data["DBSectionState"] = dbSectionState(len(fullStatus.DiscoveredDBs), len(fullStatus.DumpFiles))
// DB dump total size
var dbDumpTotalBytes int64
for _, f := range fullStatus.DumpFiles {
@@ -719,7 +723,7 @@ type AppBackupRow struct {
BackupContents string
// Tier 1: Nightly backup (always exists)
Tier1LastRun string // formatted time of last restic snapshot
Tier1LastRun string // RFC3339 time of the newest recovery-unit artifact ("" = no unit yet)
Tier1LastStatus string // "ok", "error", ""
Tier1DBStatus string // "ok", "error", "" — separate DB dump status for warning
@@ -742,6 +746,10 @@ type AppBackupRow struct {
// Tier2UserDisabled — customer turned Tier 2 off for this app from the config panel.
Tier2UserDisabled bool
// Tier 3: Off-box (NAS) restic-SFTP backup — the off-site 3-2-1 leg.
OffboxEnabled bool // this app toggled for off-box inclusion (IsAppOffbox)
Tier3State string // "unconfigured" | "off" | "escrow_pending" | "active" (see tier3State)
// Warnings accumulated for this app
Warnings []string
}
@@ -774,6 +782,14 @@ func (s *Server) buildAppBackupRows(status *backup.FullBackupStatus) []AppBackup
disconnectedPaths[dp.Path] = true
}
// Off-box (Tier 3) globals — resolved once for all rows. The per-app state is
// (global configured) × (global escrow) × (per-app toggle); see tier3State.
offboxConfigured := s.backupMgr != nil && s.backupMgr.OffboxConfigured()
offboxEscrowState := ""
if t := s.settings.GetOffboxTarget(); t != nil {
offboxEscrowState = t.EscrowState
}
var rows []AppBackupRow
for _, app := range status.AppDataInfo {
hasDB := dbStacks[app.StackName] || app.HasDBDump
@@ -818,6 +834,25 @@ func (s *Server) buildAppBackupRows(status *backup.FullBackupStatus) []AppBackup
Tier1DBStatus: tier1DBStatus,
}
// Tier 1: newest recovery-unit artifact time. ListRestorePoints does the correct
// per-drive namespace resolution (do NOT re-derive paths — the offbox DIAG trap).
// A known stack with no unit yet returns an empty list → no fabricated time.
if s.backupMgr != nil {
if pts, ok := s.backupMgr.ListRestorePoints(app.StackName); ok && len(pts) > 0 {
row.Tier1LastRun = pts[0].Time
// A unit exists: green unless the DB dump failed (keep tier1DBStatus as the source).
if status.LastDBDump != nil && !status.LastDBDump.Success {
row.Tier1LastStatus = "error"
} else {
row.Tier1LastStatus = "ok"
}
}
}
// Tier 3: off-box (NAS) inclusion state for this app.
row.OffboxEnabled = s.settings.IsAppOffbox(app.StackName)
row.Tier3State = tier3State(offboxConfigured, row.OffboxEnabled, offboxEscrowState)
// Status dot — app-data backup status
row.Status = "green"
row.StatusText = "Alkalmazás-adat mentés rendben"