Files
felhom-controller/REPORT.md
T
2026-06-15 21:53:09 +02:00

5.7 KiB
Raw Blame History

REPORT — two UI cleanups + M3 live re-verification (2026-06-15)

Deployed: controller v0.68.3 on guest 9201 / felhom-pve (bootstrap-managed; healthy). Commits: 37ed757 (v0.68.2 CSS) · a821a9d (v0.68.3 refresh fix). Trunk-based, pushed to main.


Part 1 — stack-card state-badge clipping fix (v0.68.2, CSS-only)

Symptom: on the /stacks page, an unhealthy app's state badge clipped — "Nem egészséges" rendered as "Ner…". Healthy / not-deployed cards were fine.

Root cause (confirmed): .stack-detail-header is flex / space-between holding .stack-title-row (logo + title + subdomain link + the route-unpublished warning) and .stack-state-badge. Only on an unhealthy app does the long "⚠ URL nem elérhető útvonal nincs publikálva" warning render, inflating the title-row. The title-row had no min-width:0 (so it wouldn't shrink below its content) and the white-space:nowrap badge had no flex-shrink:0 (so the flexbox compressed the badge instead → clip).

Fix (internal/web/templates/style.css):

.stack-title-row   { flex: 1; min-width: 0; }   /* shrinks + wraps its own content */
.stack-state-badge { flex-shrink: 0; }          /* never compressed */

Browser-verified on /stacks (demo, guest 9201):

  • BEFORE (v0.68.1): komga badge clipped to "Ner…" at the card's right edge (screenshot captured live).
  • AFTER (v0.68.2): komga badge reads the full "Nem egészséges"; the "⚠ URL nem elérhető…" warning wraps within the title column (screenshot captured live).
  • Regression: Mealie ("Fut", healthy) and all "Nincs telepítve" cards visually unchanged.

Defensive note (not applied): the spec offered adding flex-shrink:0 to .badge-missing-storage/.badge-orphaned if a card showing BOTH unhealthy AND a missing-storage/ orphaned badge still clipped. No such card exists live right now, and the primary fix's mechanism (title-row min-width:0 absorbing all shrink) already shields sibling badges, so it was left out — a one-liner if that combo ever appears.


Part 2 — M3 live re-verification (no code change — the migrate path is correct)

Goal: prove the migrate merge-walk re-asserts the 2775-setgid/gid-1000 convention on a pre-existing STALE dir (the B3 calibre case), which the acceptance audit had only covered by unit test + static convention.

Method: two full migrate-all runs driven through the dashboard UI (the real /api/storage/migrate endpoint, all 8 flash apps: audiobookshelf, calibre-web, immich, jellyfin, komga, paperless-ngx, radarr, romm): flash→usb, then usb→flash (restoring apps to the default drive). Before each, the migrate target was pre-seeded host-side with deliberately-stale 0755, non-setgid userdata dirs; stat recorded.

Result — PASS (clean, non-hollow):

  • Pre-seeded userdata/documents at 755 gid1000 — a dir no app mounts — became 2775 gid1000 after migrate (the EnsureUserdataDir re-assert in walkMerge, migrate.go:854-859). Same for the seeded userdata root and userdata/import. Whole target userdata tree = 2775.
  • Integrity: static seeded files (b3-document.txt, b3-movie.txt, b3-photo.txt, demo.jpg) had identical sha256 before/after.
  • All 8 apps redeployed healthy on the target (komga "unhealthy" = its pre-existing /api/v1/actuator/health 401 — serving, unrelated to migration).

Secondary finding — the import/calibre 755 is an APP clobber, not a migrate bug. In both runs userdata/import/calibre ended at 755. Isolated live: calibre-web (CWA) bind-mounts ${USERDATA_PATH}/import/calibre as /cwa-book-ingest and chmods it to 755 (strips setgid) on every startup — proven by setting it to 2775 and restarting calibre-web alone (reverted to 755, no migration). The merge-walk does re-assert 2775 during copy; calibre-web re-clobbers it during the flip/redeploy phase (this is also why the source flash calibre was already 755 pre-migration). migrate.go was therefore NOT modified — the M3 path works. If the convention must hold for that single-app ingest dir, the fix belongs in the catalog/app layer (an umask/entrypoint wrapper for CWA), not in migrate.


Part 3 — Beállítások endless-refresh loop fix (v0.68.3) — found during Part 2

Symptom (user-reported): after any migration finished, the settings page reloaded itself every ~1.5 s, forever.

Root cause: MigrationStatus keeps returning the last done job indefinitely (never cleared). The settings page's resume-view IIFE called migWatch() for any returned job, and migWatch's done branch does setTimeout(()=>location.reload(),1500). So every load saw the persisted done job → watched it → reloaded → saw it again → endless loop.

Fix (internal/web/templates/settings.html): the resume-view now starts the watcher only for an in-progress job (phase!=='done' && phase!=='aborted'). The one-time post-completion reload still fires from the active watcher started by storageMigrateAll, so a real migration refreshes drive state once when it finishes — but a stale terminal job no longer triggers the loop.

Browser-verified on v0.68.3: with a persisted done job present in the journal, the settings page stayed put for 25 s (navType:navigate, planted marker survived, migration panel idle) — no reload.


Resting state

  • Apps healthy on felhom-flash (the default drive); felhom-usb cleaned/empty.
  • Controller v0.68.3 deployed live on guest 9201.
  • Build/deploy: built+pushed on 192.168.0.180, deployed via the bootstrap mechanism (docker pull/etc/felhom-controller-image → restart felhom-controller-bootstrap.service).