Files
deploy-felhom-compose/TASK.md
T

11 KiB

TASK: Show all storage paths on dashboard + fix hub report (v0.15.3)

Two issues after introducing partitioned system drives (OS and user data on separate partitions):

  1. Dashboard & Monitoring pages only show "SSD tárhely" (root /) and "Külső HDD" (one default storage path). Missing: the data partition on the system drive (/mnt/sys_drive). All registered storage paths should appear as separate bars.
  2. Hub storage report only sends root / and one HDD entry (with wrong mount path — uses deprecated cfg.Paths.HDDPath which is ""). This causes the hub to display incorrect/stale storage info and a spurious "nem külön meghajtón van" warning.

Current state (demo-felhom)

sda1 ext4 → /mnt/sys_drive   (user data partition, 320G)
sda3 ext4 → /                 (OS partition, 139G)
sdb1 ext4 → /mnt/hdd_1        (external USB HDD, 916G)

Registered storage paths in settings.json:

"storage_paths": [
  {"path": "/mnt/hdd_1",     "label": "USB HDD 1TB",      "is_default": true},
  {"path": "/mnt/sys_drive",  "label": "SYS Storage 350G",  "schedulable": true}
]

Config controller.yaml:

  • paths.system_data_path: "/mnt/sys_drive"
  • paths.hdd_path: "" (deprecated, empty)

Health check already works correctly: IsMountPoint("/mnt/sys_drive") returns true inside container (Dev 2049 ≠ parent Dev 2051). No code changes needed in healthcheck.go.


Fix 1: Dashboard & Monitoring — show all storage paths

Root cause

SystemInfo struct only has fields for ONE SSD (root /) and ONE HDD. GetInfo(hddPath) takes a single HDD path. Templates hardcode "SSD tárhely" and "Külső HDD" labels.

Fix approach

Pass a separate StorageBars list to templates alongside SystemInfo (which keeps SSD/root info). Each storage bar has label, usage, and color.

Implementation steps

Step 1: Add StorageBarInfo type

In controller/internal/web/handlers.go (or a new small type near the top), add:

// StorageBarInfo holds data for rendering a storage usage bar on dashboard/monitoring.
type StorageBarInfo struct {
    Label       string  // e.g., "USB HDD 1TB", "SYS Storage 350G"
    Path        string  // e.g., "/mnt/hdd_1"
    TotalGB     float64
    UsedGB      float64
    Percent     float64
}

Step 2: Build storage bars in handlers

Create a helper method on Server:

func (s *Server) buildStorageBars() []StorageBarInfo {
    var bars []StorageBarInfo
    for _, sp := range s.settings.GetStoragePaths() {
        di := system.GetDiskUsage(sp.Path)
        if di == nil {
            continue
        }
        bars = append(bars, StorageBarInfo{
            Label:   sp.Label,
            Path:    sp.Path,
            TotalGB: di.TotalGB,
            UsedGB:  di.UsedGB,
            Percent: di.UsedPercent,
        })
    }
    return bars
}

In dashboardHandler() (~line 84-91), ADD after the SystemInfo line:

data["StorageBars"] = s.buildStorageBars()

In monitoringHandler() (~line 365), ADD:

data["StorageBars"] = s.buildStorageBars()

Step 3: Update dashboard template

File: controller/internal/web/templates/dashboard.html (~lines 58-91)

Replace the storage section. Keep the SSD bar as-is. Replace the single {{if .SystemInfo.HDDConfigured}} HDD block with a range over StorageBars:

Current code (lines 68-78):

{{if .SystemInfo.HDDConfigured}}
<div class="system-info-item">
    <div class="system-info-header">
        <span class="system-info-label">Külső HDD</span>
        <span class="system-info-value">{{fmtGB .SystemInfo.HDDUsedGB}} / {{fmtGB .SystemInfo.HDDTotalGB}} ({{printf "%.0f" .SystemInfo.HDDPercent}}%)</span>
    </div>
    <div class="system-bar">
        <div class="system-bar-fill system-bar-{{usageColor .SystemInfo.HDDPercent}}" style="width:{{printf "%.0f" .SystemInfo.HDDPercent}}%"></div>
    </div>
</div>
{{end}}

Replace with:

{{range .StorageBars}}
<div class="system-info-item">
    <div class="system-info-header">
        <span class="system-info-label">{{.Label}}</span>
        <span class="system-info-value">{{fmtGB .UsedGB}} / {{fmtGB .TotalGB}} ({{printf "%.0f" .Percent}}%)</span>
    </div>
    <div class="system-bar">
        <div class="system-bar-fill system-bar-{{usageColor .Percent}}" style="width:{{printf "%.0f" .Percent}}%"></div>
    </div>
</div>
{{end}}

Step 4: Update monitoring template

File: controller/internal/web/templates/monitoring.html (~lines 53-63)

Same pattern — replace the {{if .HDDConfigured}} block:

Current code (lines 53-63):

{{if .HDDConfigured}}
<div class="storage-item">
    <div class="storage-header">
        <span class="storage-label">Külső HDD</span>
        <span class="storage-value">{{fmtGB .HDDUsedGB}} / {{fmtGB .HDDTotalGB}} ({{printf "%.0f" .HDDPercent}}%)</span>
    </div>
    <div class="system-bar">
        <div class="system-bar-fill {{usageColor .HDDPercent | printf "system-bar-%s"}}" style="width:{{printf "%.1f" .HDDPercent}}%"></div>
    </div>
</div>
{{end}}

Replace with (note: this block is inside {{with .SystemInfo}} so we need to access root data with $):

{{range $.StorageBars}}
<div class="storage-item">
    <div class="storage-header">
        <span class="storage-label">{{.Label}}</span>
        <span class="storage-value">{{fmtGB .UsedGB}} / {{fmtGB .TotalGB}} ({{printf "%.0f" .Percent}}%)</span>
    </div>
    <div class="system-bar">
        <div class="system-bar-fill {{usageColor .Percent | printf "system-bar-%s"}}" style="width:{{printf "%.1f" .Percent}}%"></div>
    </div>
</div>
{{end}}

IMPORTANT: The monitoring template uses {{with .SystemInfo}} context (line 43), so $.StorageBars is needed to access the root template data. Check the exact template context before editing.

Step 5: Template function access

The fmtGB and usageColor template functions are already registered in funcmap.go. The StorageBarInfo fields (TotalGB, UsedGB, Percent) are float64 — same types used by the existing SSD/HDD fields. No funcmap changes needed.


Fix 2: Hub storage report — include all storage paths

Root cause

In controller/internal/report/builder.go lines 62-72:

r.Storage = []StorageReport{
    {Mount: "/", TotalGB: sysInfo.DiskTotalGB, UsedGB: sysInfo.DiskUsedGB, Percent: sysInfo.DiskPercent},
}
if sysInfo.HDDConfigured {
    r.Storage = append(r.Storage, StorageReport{
        Mount:   cfg.Paths.HDDPath,  // BUG: empty string "", not the actual path
        TotalGB: sysInfo.HDDTotalGB,
        ...
    })
}

Two bugs:

  1. Mount: cfg.Paths.HDDPath is "" (deprecated field), so the hub receives an empty mount path
  2. Only ONE extra storage entry is sent — misses additional storage paths like /mnt/sys_drive

Fix

File: controller/internal/report/builder.go

Step 1: Add Label field to StorageReport

File: controller/internal/report/types.go (~line 39-44)

Add a Label field:

type StorageReport struct {
    Mount   string  `json:"mount"`
    Label   string  `json:"label,omitempty"`
    TotalGB float64 `json:"total_gb"`
    UsedGB  float64 `json:"used_gb"`
    Percent float64 `json:"percent"`
}

Step 2: Replace storage section in BuildReport

File: controller/internal/report/builder.go (~lines 62-72)

Replace:

// Storage
r.Storage = []StorageReport{
    {Mount: "/", TotalGB: sysInfo.DiskTotalGB, UsedGB: sysInfo.DiskUsedGB, Percent: sysInfo.DiskPercent},
}
if sysInfo.HDDConfigured {
    r.Storage = append(r.Storage, StorageReport{
        Mount:   cfg.Paths.HDDPath,
        TotalGB: sysInfo.HDDTotalGB,
        UsedGB:  sysInfo.HDDUsedGB,
        Percent: sysInfo.HDDPercent,
    })
}

With:

// Storage — root filesystem + all registered storage paths
r.Storage = []StorageReport{
    {Mount: "/", Label: "SSD", TotalGB: sysInfo.DiskTotalGB, UsedGB: sysInfo.DiskUsedGB, Percent: sysInfo.DiskPercent},
}
for _, sp := range storagePaths {
    di := system.GetDiskUsage(sp.Path)
    if di == nil {
        continue
    }
    r.Storage = append(r.Storage, StorageReport{
        Mount:   sp.Path,
        Label:   sp.Label,
        TotalGB: di.TotalGB,
        UsedGB:  di.UsedGB,
        Percent: di.UsedPercent,
    })
}

Note: This requires adding "gitea.dooplex.hu/admin/felhom-controller/internal/system" to the imports in builder.go (it may already be imported — check first).


Summary of files to modify

File Change
controller/internal/web/handlers.go Add StorageBarInfo type, buildStorageBars() method, pass StorageBars to dashboard/monitoring handlers
controller/internal/web/templates/dashboard.html Replace hardcoded HDD bar with {{range .StorageBars}}
controller/internal/web/templates/monitoring.html Replace hardcoded HDD bar with {{range $.StorageBars}}
controller/internal/report/builder.go Replace storage section to iterate over all storagePaths with system.GetDiskUsage()
controller/internal/report/types.go Add Label field to StorageReport

Build & Deploy

Version: v0.15.3

Build workflow

SSH=/c/Windows/System32/OpenSSH/ssh.exe
# 1. Commit & push
cd e:/git/deploy-felhom-compose
git add -A && git commit -m "v0.15.3: Show all storage paths on dashboard/monitoring + fix hub report" && git push
# 2. Build
$SSH kisfenyo@192.168.0.180 "cd ~/build/felhom-controller && git -C ~/git/deploy-felhom-compose pull && ./build.sh v0.15.3 --push"
# 3. Deploy
$SSH kisfenyo@192.168.0.162 "cd /opt/docker/felhom-controller && sudo docker pull gitea.dooplex.hu/admin/felhom-controller:v0.15.3 && sudo sed -i 's|image: gitea.dooplex.hu/admin/felhom-controller:.*|image: gitea.dooplex.hu/admin/felhom-controller:v0.15.3|' docker-compose.yml && sudo docker compose up -d"
# 4. Verify
$SSH kisfenyo@192.168.0.162 "docker ps --filter name=felhom-controller --format '{{.Image}} {{.Status}}'"

Compile check

Always run go build ./... in controller/ before committing to ensure no compile errors.

Documentation

Add a CHANGELOG.md entry at the top (under ## Changelog). Read the first 30 lines to see the format, then insert a new entry. Example:

### vX.X.X (2026-02-19 session XX)
- **v0.15.3 — Show all storage paths on dashboard + fix hub report:**

  Dashboard ("Vezérlőpult") and monitoring ("Rendszermonitor") pages now show usage bars for ALL registered storage paths instead of just one hardcoded "Külső HDD" bar. Each bar displays the storage label and usage from settings.

  Hub storage report now correctly includes all registered storage paths with proper mount paths and labels. Previously it sent only root `/` and one HDD entry with an empty mount path (used deprecated `cfg.Paths.HDDPath`).

  **Files modified:** `internal/web/handlers.go`, `internal/web/templates/dashboard.html`, `internal/web/templates/monitoring.html`, `internal/report/builder.go`, `internal/report/types.go`

Update version in C:\Users\User\.claude\projects\e--git\memory\MEMORY.md to v0.15.3.

Verification

After deploying v0.15.3:

  1. Navigate to / (Vezérlőpult) — should show three bars: "SSD tárhely" + "USB HDD 1TB" + "SYS Storage 350G"
  2. Navigate to /monitoring (Rendszermonitor) — same three bars in Tárhely section
  3. Check hub at hub.felhom.eu/customers/demo-felhom — Health section should show no storage warnings; Storage should list all three mounts
  4. No health warning about "nem külön meghajtón van" should appear (IsMountPoint already returns true for /mnt/sys_drive)