## Changelog ### What was just completed (2026-02-18 session 49) - **v0.14.2 — Backup Bug Fixes (4 fixes from code review):** **Bug 1 (HIGH):** rsync `--delete` was destroying `_db/` and `_config/` directories on every single-mount run. Fixed by adding `--exclude _*` to the rsync command in `runRsyncBackup()`. Controller-managed directories (underscore prefix) are now excluded from `--delete` cleanup. (`crossdrive.go`) **Bug 2 (MEDIUM):** Scheduled backups (`RunBackup`, `RunDBDumps`) did not set `m.running`, so UI showed "not running" during nightly jobs and restore could overlap. Fixed by extracting `acquireRunning()` / `releaseRunning()` helpers and `runDBDumpsInternal()` / `runBackupInternal()` internal methods. All three public entry points now guard with the running flag; `RunFullBackup()` calls the internal methods directly to avoid deadlock. (`backup.go`) **Bug 3 (MEDIUM):** `ValidateDestination` silently succeeded when `GetDiskUsage` returned nil (exotic filesystems, FUSE, NFS). Fixed by logging `[WARN]` and returning nil (backward-compatible). (`crossdrive.go`) **Bug 4 (MEDIUM):** Empty `systemDataPath` produced relative dump paths. Fixed with: startup `[WARN]` in `NewManager()`, `[ERROR]` log in `GetAppDrivePath()`, and explicit guard in `DumpStackDB()` that returns an error when path is empty or non-absolute. (`backup.go`) **Files modified (2):** `internal/backup/backup.go`, `internal/backup/crossdrive.go` ### What was just completed (2026-02-18 session 48) - **v0.13.1 — UI Polish Fixes Round 2 (4 fixes):** **Fix 1:** Deploy page "Biztonsági mentés" section now has proper card border. Root cause: `.deploy-cross-drive` used undefined CSS variables `--card-bg` and `--border` (only `--bg-secondary` and `--border-color` exist). Fixed by using correct vars (`style.css`). **Fix 2:** Auto-generated env values section cleaned up (`deploy.html`, `style.css`). Badge moved inline with label. "Másolás" buttons removed (native select+copy sufficient). Secret fields keep show/hide toggle. Non-secret fields now plain readonly input without button wrapper. Removed `copyAutoField()` JS. CSS updated: `.form-group-auto` now block layout (was flex row), label uses `display: flex; gap: .5rem`, badge downsized to `0.75rem / normal weight`, readonly inputs get muted background. **Fix 3:** Snapshot table n/a → 0 (`backups.html`). Replaced `n/a` with plain `0` in all three stats columns. Removed `.col-na` CSS class (no longer used). **Fix 4:** Disk warnings moved from top banner to inline under storage bars (`alerts.go`, `layout.html`, `handlers.go`, `dashboard.html`, `monitoring.html`, `style.css`). Added `Inline bool` field to `Alert` struct. Disk-related warnings set `Inline: true`. Layout banner skips inline alerts. New `GetInlineAlerts(page)` method on `AlertManager`. Dashboard and monitoring handlers pass `DiskWarnings`. Inline warning block rendered below storage bars. New `.inline-warning*` CSS classes (compact, subtle, colored). **Files modified (8):** `alerts.go`, `handlers.go`, `templates/style.css`, `templates/dashboard.html`, `templates/backups.html`, `templates/deploy.html`, `templates/monitoring.html`, `templates/layout.html` ### What was just completed (2026-02-18 session 47) - **v0.13.0 — UI Polish Fixes (8 independent fixes):** **Fix 1:** backup-status-card border already correct (verified same styling as system-info-card). **Fix 2:** Deploy page auto-generated fields now show actual values for deployed apps (`deploy.html`, `handlers.go`). Secrets show as password fields with show/hide toggle; domain/plain values show as readonly text with copy button. JS helpers `toggleAutoField()` / `copyAutoField()` added. **Fix 3:** Temperature display made more prominent (`dashboard.html`, `style.css`). Dot enlarged to 11px; value wrapped in colored pill badge (`.temp-value-pill` / `.temp-pill-{green|yellow|red}`). **Fix 4:** Dashboard backup card reworked (`dashboard.html`, `handlers.go`). Removed "Mentés most" button and `triggerBackup()` JS. Removed "Tároló méret" line. Added Tier 2 status line (configured/total apps) + warning row for failed cross-drive backups. Handler now computes `CrossDriveTotal`, `CrossDriveConfigured`, `CrossDriveFailed`. **Fix 5:** HDD warning banner scoped to dashboard + monitoring pages only (`alerts.go`, `layout.html`, `funcmap.go`). Added `PageOnly []string` field to `Alert` struct. Disk-related warnings (keywords "meghajtón", "adattároló") get stable ID `"disk-not-separate"` + `PageOnly: ["dashboard", "monitoring"]`. `pageMatch()` template function added. Layout renders alerts conditionally. **Fix 6:** Tárhely section moved up in Rendszermonitor — now appears right after "Rendszer áttekintés", before "Távoli monitoring" (`monitoring.html`). **Fix 7:** Snapshot table improvements (`backups.html`, `style.css`). "MÉRET" renamed to "HOZZÁADOTT (új adat)". `–` for unavailable data replaced with `n/a` (with tooltip explaining restic limitations). New `.col-subtitle` and `.col-na` CSS classes. **Fix 8:** Tároló section restructured into tiers (`backups.html`, `handlers.go`, `style.css`). Tier 1 (restic local), Tier 2 (cross-drive, only shown if configured), DB dump directory + total size. Removed "Távoli másolat: Nincs beállítva" placeholder. Handler passes `DBDumpDir`, `DBDumpTotalBytes`, `Tier2Dests` (deduplicated). New `.repo-tier` / `.repo-tier-title` CSS. **Files modified (9):** `alerts.go`, `funcmap.go`, `handlers.go`, `templates/style.css`, `templates/dashboard.html`, `templates/backups.html`, `templates/deploy.html`, `templates/monitoring.html`, `templates/layout.html` ### What was just completed (2026-02-18 session 46) - **v0.12.9 — Tier 2 for All Apps + Status Dot Update:** **Fix 1: Tier 2 now configurable for ALL apps — not just HDD apps (`crossdrive.go`)** - Removed `len(mounts) == 0` error gate from `RunAppBackup()` — empty mounts = config-only backup - rsync: DB dump copy (`_db/`) + config rsync (`_config/`) still runs even with zero HDD mounts - restic: config dir + DB dump dir still appended even without mount paths - Non-HDD apps (Mealie, Gokapi, etc.) can now be protected against drive failure via Tier 2 **Fix 2: Status dot logic updated, HasHDDData gate removed (`handlers.go`)** - `buildAppBackupRows()`: "auto" (gray) status removed — all apps start yellow ("Csak helyi mentés") - Green requires Tier 2 configured + last status "ok" (not just "configured but never run") - Tier2 section is now unconditional — no `if app.HasHDDData` gate - Cross-drive summary loop: removed `if !app.HasHDDData { continue }` — all apps in summary **Fix 3: Backup page template updates (`backups.html`)** - Tier 2 row shown for all apps (removed `{{if .HasHDDData}}` gate) - Meta badge: non-HDD apps show "Konfig" or "Konfig + DB" instead of "Auto" - Tier 3 placeholder row added (grayed out "Hamarosan / távoli offsite") - Button text: "Összes HDD mentés" → "Összes 2. mentés futtatása most" **Fix 4: Deploy page cross-drive section visible for all deployed apps (`deploy.html`)** - Removed `{{if .StorageInfo}}` double-gate — section now shows for all deployed apps - Updated heading: "Másolat másik meghajtóra (felhasználói adatok)" → "2. mentés — másolat másik meghajtóra" - Updated hint: "mint az alkalmazás adattárolója" → "a meghibásodás elleni védelem érdekében" **Files modified (4):** `internal/backup/crossdrive.go`, `internal/web/handlers.go`, `internal/web/templates/backups.html`, `internal/web/templates/deploy.html` ### What was just completed (2026-02-18 session 45) - **v0.12.8 — Complete Cross-Drive Backup + Per-Tier UI:** **Fix 1: Cross-drive backup now includes DB dumps + app config (`crossdrive.go`, `main.go`)** - `CrossDriveRunner` gets `dbDumpDir` field + `SetDBDumpDir(dir string)` setter - `copyStackDBDumps()` helper copies `_*.sql` files to `_db/` subfolder in rsync dest - `runRsyncBackup()`: after HDD mount rsync loop, copies DB dumps to `_db/` and rsyncs config dir to `_config/` — both non-fatal on error - `runResticBackup()`: appends config dir and full DB dump dir to restic paths (restic deduplicates) - rsync destination layout: `backups/rsync//_db/` (dumps) + `_config/` (compose+yaml) + user data - `main.go`: `crossDriveRunner.SetDBDumpDir(cfg.Paths.DBDumpDir)` wired after runner init **Fix 2: UI restructured from per-layer to per-tier (`handlers.go`, `backups.html`, `style.css`)** - `AppBackupRow` struct rebuilt: dropped old `DBLastRun/Status`, `VolumeLastRun/Status`, `HasUserData`, `UserDataConfigured/Method/Dest/Schedule/LastRun/LastStatus/LastError/StatusBadge` fields - New fields: `BackupContents` (e.g., "DB + Konfig + Adatok"), `Tier1LastRun/LastStatus/DBStatus`, `Tier2Configured/Method/MethodLabel/Dest/Schedule/LastRun/LastStatus/LastError/StatusBadge/SizeHuman/Browsable` - `buildAppBackupRows()` rewritten: destination health now via `s.crossDriveRunner.ValidateDestination()` instead of `system.CheckBackupDestination()` - `backups.html`: two tier rows (1. mentés / 2. mentés) replace the old three layer rows (DB / Konfig / Userdata) - `style.css`: added `.tier-label`, `.tier-location`, `.tier-contents`, `.tier-size`, `.tier-browsable` classes **Fix 3: Cleanup (`router.go`)** - `filterSnapshotsByPaths()` and `pathCovers()` deleted (were unused since v0.12.7a) **Files modified (6):** `internal/backup/crossdrive.go`, `cmd/controller/main.go`, `internal/web/handlers.go`, `internal/web/templates/backups.html`, `internal/web/templates/style.css`, `internal/api/router.go` ### What was just completed (2026-02-18 session 44) - **v0.12.7a — Post-deploy fixes:** **Fix A: Restore now shows snapshots for all apps (`internal/api/router.go`)** - Root cause: `filterSnapshotsByPaths` filtered older snapshots (pre-v0.12.7) by HDD paths. Older snapshots don't contain HDD paths (backup wasn't mandatory yet), so Immich got zero snapshots. - Fix: removed HDD path filtering entirely from `backupSnapshots`. All snapshots contain config + DB dumps and are useful for any app. `RestoreApp` extracts whatever paths are available from the chosen snapshot. - `filterSnapshotsByPaths` and `pathCovers` functions kept (unused, no compile error). **Fix B: Clarified "no cross-drive" warning (`internal/web/handlers.go`, `backups.html`, `style.css`)** - Root cause: "Nincs beállítva" / red dot implied no backup at all — misleading since nightly restic now always covers HDD data. - `handlers.go`: status `"red"` → `"yellow"`, StatusText → `"Nincs második másolat (csak helyi mentés)"` - `backups.html`: added `✓ Helyi mentés auto` badge before the `⚠ Nincs 2. másolat` warning - `style.css`: `.layer-auto-ok` class added (green text for the auto badge) **Files modified (3):** `internal/api/router.go`, `internal/web/handlers.go`, `internal/web/templates/backups.html`, `internal/web/templates/style.css` ### What was just completed (2026-02-18 session 43) - **v0.12.7 — Backup Architecture Overhaul (mandatory HDD backup, pre-dump, restore for all apps):** **Fix 1: HDD data backup now mandatory (`backup.go`, `appdata.go`, `settings.go`)** - `resolveAppBackupPaths()` rewrote to iterate ALL deployed stacks via `ListDeployedStacks()` — no longer reads `GetAppBackupMap()` or checks `Enabled` flag - `DiscoverAppData()` signature simplified: dropped `backupPrefs map[string]bool` parameter; `BackupEnabled` is now derived from `HasHDDData` (if app has HDD data, it's always backed up) - `RefreshCache()` updated to call new `DiscoverAppData(m.stackProvider, status.DiscoveredDBs)` signature - 5 dead settings methods deleted: `IsAppBackupEnabled`, `SetAppBackup`, `GetAppBackupMap`, `SetAppBackupBulk`, `GetAppBackupPrefs` — `AppBackupPrefs.Enabled` field kept in struct for backward-compat JSON loading **Fix 2: Cross-drive backup triggers fresh DB dump first (`crossdrive.go`, `backup.go`, `main.go`)** - New `DBDumper` interface with `DumpStackDB(ctx, stackName)` in `crossdrive.go` - `CrossDriveRunner` gets `dbDumper` field + `SetDBDumper(d DBDumper)` setter - `Manager.DumpStackDB()` discovers containers for that stack via `DiscoverDatabases()`, runs `DumpAll()`, persists validation cache — same logic as nightly dump but scoped to one stack - `RunAppBackup()` calls `DumpStackDB()` before `ValidateDestination()` — non-fatal on failure (logs warn, proceeds with user data) - `main.go` wires `crossDriveRunner.SetDBDumper(backupMgr)` after both are initialized **Fix 3: Restore dropdown shows ALL deployed apps (`backups.html`, `restore.go`, `router.go`)** - `restore.go` rewritten: no `IsAppBackupEnabled()` check; resolves `GetStackComposePath` + `DBDumpDir` + HDD mounts; always restores config+DB, adds user data if `hasHDD`; logs restore type (`config+DB` vs `full (config+DB+userdata)`) - Restore dropdown template: removed `{{if and .HasHDDData .BackupEnabled}}` filter; every app gets an `