v0.51.0: offsite-backup UI (felhom-pbs DR) + Model-A double-nest fix

- Backups page: whole-guest backup shown as real DR — target label "Biztonsági szerver –
  külön hardver (PBS)"; app-data "Távoli mentés" card now reflects the PBS offsite tier
  (guestBackupView.Offsite) instead of "nincs beállítva".
- Model-A double-nest fix: appbackup path helpers take a felhom-data NAMESPACE ROOT (no
  internal felhom-data join); backup.Manager.namespaceRoot/AppNamespaceRoot resolve
  HDD-vs-systemDataPath provenance so a drive-resident app's backups land single-nested
  (<drive>/backups/... on the guest = <drive>/felhom-data/backups/... on the host) instead
  of .../felhom-data/felhom-data/.... Writes, deletion (GetStackBackupData/RemoveStack/
  ProtectedHDDPaths), wipe-warning scan, and export updated coherently; legacy double-nest
  dirs kept protected. New appbackup test asserts no doubled segment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-12 20:26:52 +02:00
parent 1e82eebc5e
commit 63484a0bd4
12 changed files with 221 additions and 58 deletions
+16 -7
View File
@@ -31,7 +31,8 @@ type guestBackupView struct {
Success bool
StartedAt time.Time
SizeBytes int64
Target string // human label: "Biztonsági szerver (PBS)" / "Helyi tároló (local)"
Target string // human label: "Biztonsági szerver külön hardver (PBS)" / "Helyi tároló (local)"
Offsite bool // the whole-guest backup landed on the PBS offsite tier (separate hardware)
Archive string
Mode string // snapshot | stop
StopMode bool // mode == stop → full app downtime during the backup (warn)
@@ -73,6 +74,7 @@ func (s *Server) loadGuestBackup(ctx context.Context) *guestBackupView {
v.Mode = st.Backup.Mode
v.StopMode = st.Backup.Mode == "stop"
v.Target = backupTargetLabel(st.Backup)
v.Offsite = backupIsPBS(st.Backup)
if t, perr := time.Parse(time.RFC3339, st.Backup.StartedAt); perr == nil {
v.StartedAt = t
}
@@ -97,13 +99,20 @@ func (s *Server) loadGuestBackup(ctx context.Context) *guestBackupView {
return v
}
// backupTargetLabel maps the agent's backup target to a customer-facing Hungarian label, surfacing
// whether the backup landed on the PBS offsite tier or local host storage (from the archive volid /
// target id — "felhom-pbs"/"pbs:" ⇒ PBS, else local host storage).
func backupTargetLabel(b *agentapi.BackupRecord) string {
// backupIsPBS reports whether a whole-guest backup landed on the PBS offsite tier (separate
// hardware), inferred from the target id / archive volid ("felhom-pbs"/"pbs:" ⇒ PBS).
func backupIsPBS(b *agentapi.BackupRecord) bool {
id := strings.ToLower(b.TargetID)
if strings.Contains(id, "pbs") || strings.HasPrefix(strings.ToLower(b.Archive), "felhom-pbs") || strings.Contains(strings.ToLower(b.Archive), "pbs:") {
return "Biztonsági szerver (PBS)"
arc := strings.ToLower(b.Archive)
return strings.Contains(id, "pbs") || strings.HasPrefix(arc, "felhom-pbs") || strings.Contains(arc, "pbs:")
}
// backupTargetLabel maps the agent's backup target to a customer-facing Hungarian label. The PBS
// case calls out that the backup is on SEPARATE HARDWARE (real disaster recovery — survives a host
// disk/hardware failure), which is the whole point of re-pointing the backup offsite.
func backupTargetLabel(b *agentapi.BackupRecord) string {
if backupIsPBS(b) {
return "Biztonsági szerver külön hardver (PBS)"
}
if b.TargetID != "" {
return "Helyi tároló (" + b.TargetID + ")"