v0.56.0: Phase 4 — FileBrowser scoping + deploy DB-on-SSD note + monitoring descriptions

4A: scope FileBrowser bind to <drive>/appdata (recovery units + Tier 2 copies under
backups/ are no longer mounted into FileBrowser — customer can't browse/delete the
thing that restores them). 4B: deploy storage-selection step states the chosen drive
holds files while the DB runs on the fast internal SSD + is backed up with the app.
4C: buildStorageBars stable sort + purpose description on the monitoring storage list.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-13 13:35:43 +02:00
parent 88ca1178ae
commit 476a97376f
4 changed files with 46 additions and 3 deletions
+23 -3
View File
@@ -8,6 +8,7 @@ import (
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
"time"
@@ -31,13 +32,21 @@ var protectedStackSubdomains = map[string]string{
type StorageBarInfo struct {
Label string // e.g., "USB HDD 1TB", "SYS Storage 350G"
Path string // e.g., "/mnt/hdd_1"
Purpose string // Hungarian explanation of what this drive holds (monitoring page)
TotalGB float64
UsedGB float64
Percent float64
Disconnected bool
}
// buildStorageBars returns usage bars for all registered storage paths.
// storageBarPurpose is the Hungarian description for the registered user-data drives shown in the
// monitoring "Tárolók kapacitása" list. These are all external/user-data drives (the agent's
// system/PBS storage is not in the controller's storage-path registry), matching the user-data
// purpose text on the storage-management page (Phase 4C).
const storageBarPurpose = "Külső adattároló — a telepített alkalmazások nagy méretű fájljai (média, dokumentumok) ide kerülnek; az adatbázisok a belső SSD-n vannak."
// buildStorageBars returns usage bars for all registered storage paths, in a stable order
// (by path) with a purpose description.
func (s *Server) buildStorageBars() []StorageBarInfo {
var bars []StorageBarInfo
for _, sp := range s.settings.GetStoragePaths() {
@@ -49,6 +58,7 @@ func (s *Server) buildStorageBars() []StorageBarInfo {
bars = append(bars, StorageBarInfo{
Label: sp.Label,
Path: sp.Path,
Purpose: storageBarPurpose,
Disconnected: true,
})
continue
@@ -60,11 +70,14 @@ func (s *Server) buildStorageBars() []StorageBarInfo {
bars = append(bars, StorageBarInfo{
Label: sp.Label,
Path: sp.Path,
Purpose: storageBarPurpose,
TotalGB: di.TotalGB,
UsedGB: di.UsedGB,
Percent: di.UsedPercent,
})
}
// Deterministic order regardless of registry insertion order.
sort.Slice(bars, func(i, j int) bool { return bars[i].Path < bars[j].Path })
return bars
}
@@ -1369,11 +1382,18 @@ func (s *Server) syncFileBrowserMounts(resetDBOnChange bool) {
return
}
// Build volume mount lines
// Build volume mount lines. SCOPE to the drive's `appdata/` subtree only (Phase 4A): the customer
// browses their userdata, but the recovery units + Tier 2 copies under `backups/` are NOT mounted
// into FileBrowser at all — so the thing that restores them can't be browsed or (even read-only)
// surfaced. mkdir the appdata dir first so the bind source exists with sane ownership.
var storageMounts []string
for _, sp := range paths {
mountName := filepath.Base(sp.Path) // "/mnt/hdd_1" → "hdd_1"
line := fmt.Sprintf(" - %s:/srv/%s", sp.Path, mountName)
appdataSrc := filepath.Join(sp.Path, "appdata")
if err := os.MkdirAll(appdataSrc, 0755); err != nil {
s.logger.Printf("[WARN] [web] FileBrowser: could not ensure appdata dir %s: %v", appdataSrc, err)
}
line := fmt.Sprintf(" - %s:/srv/%s", appdataSrc, mountName)
storageMounts = append(storageMounts, line)
}