From 52e97b15ca6bd5d8d27ab553b6ca2f23228b9ac9 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Thu, 2 Jul 2026 15:04:10 +0200 Subject: [PATCH] docs: CHANGELOG v0.96.0 + REPORT (TASK-D0) + CONTEXT + README design-system section --- CHANGELOG.md | 44 ++++++++++++ CONTEXT.md | 23 +++++- REPORT.md | 165 +++++++++++++++++++++++++++++++------------ controller/README.md | 11 ++- 4 files changed, 194 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 721f795..65ae561 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,49 @@ ## Changelog +### v0.96.0 — TASK-D0: design system v2 re-skin (appearance only) (2026-07-02) + +Full customer-UI re-skin to the approved Felhom design system v2 — navy token palette, exception-based +status color, vendored fonts/icons, flat metadata. **Appearance only:** no route/handler/IA changes; +every page keeps its URL, sections, forms and behavior. Canonical reference: +`felhom.eu/documentation/design/design-system.md`. Four commits (b073cc4, 5dc277f, f100cef, 7df061c) ++ a bug-fix (4906524). + +- **Vendored assets (`internal/web/static/fonts/`, `templates/icons.html`, `embed.go`, `server.go`):** + Plus Jakarta Sans + JetBrains Mono as variable woff2 (latin + latin-ext — ő/ű), embedded and served + from `/static/fonts/` (font/woff2, immutable cache); Google Fonts `@import` removed (CDN silently + broke offline nodes). Vendored 30-icon Lucide sprite included at top of ``; all emoji replaced + by sprite icons or plain text (templates AND JS-built strings). +- **Setup CSS fix (`internal/setup/handlers.go`):** `handleCSS` served a dataDir-derived filesystem + path that never exists in the container — production setup mode silently fell back to `minimalCSS`. + Now serves the embedded `web.StyleCSS()` (new accessor); minimalCSS only if the embedded read errors + (logged). `minimalCSS` retokened to v2. +- **`templates/style.css` (rewritten in place):** v2 `:root` tokens; single 2px radius; every + `box-shadow` + the bg grid overlay deleted; new components — `.meter` (3px hairline track, blue + nominal fill, neutral 70/85 ticks, warn/crit `.meter-flag` „Fogyóban a hely" / „Kritikusan kevés + hely"), `.tag` (square state chip + dot, pulse on progress, reduced-motion respected), `.metarow`, + `.panel`/`.list`/`.section-h`, boxless `.stats`, buttons (danger = crit outline until confirm), + `:focus-visible` outlines. +- **funcmap (`internal/web/funcmap.go`):** `stateColor` → `run/progress/warn/neutral/off` + (**stopped/exited is neutral, NOT red** — operator-approved exception-color change; restarting = + warn); `usageColor`/`tempColor` → `nominal/warn/crit` (thresholds unchanged); `stateLabel` + Hungarian copy untouched (byte-identity guarded by test). New `timeAgoStr` (see fix below). +- **All 19 web templates + setup templates:** bars → meters (template + JS-generated markup), + badges/pills → tags, informational pills → metarows with icons, legacy `var(--*)` names in inline + styles/JS renamed to v2 tokens, monitoring Chart.js palette (cpu `#2EA8F5`, memory `#8E7CE8`, temp + `#E0A93E`, load `#5EC4B6`; v2 tooltip/grid/tick literals), deploy 3-step progress → sprite icons, + catchall page (standalone) fully retokened with inline SVGs, login two-tone H1. +- **fix(backups) 4906524:** `OffboxTarget.LastRun` is an RFC3339 *string*; backups.html passed it to + `timeAgo` (expects `time.Time`) → GET /backups 500'd on any node where an off-box backup had ever + run. Pre-existing since v0.93.0, exposed by the D0 click-through; fixed with `timeAgoStr`. +- **Tests (+7):** §8 truth tables for stateColor/usageColor/tempColor + stateLabel guard (red-proven + vs the old funcmap), font route + `StyleCSS()` accessor, setup embedded-CSS (Scenario E, red-proven + vs the old handler). Grep gate: 34 banned patterns (old hexes, 999px, box-shadow, CDN import, + legacy class names, emoji) at **zero** in `internal/{web,setup}` (baseline: 143 hits). +- Live-validated on guest 9201 via claude-in-chrome: full click-through, no Google Fonts requests, + `document.fonts.check` true, ő/ű render in PJS latin-ext, dashboard Scenario-A assertions + (0 green fills, 0 shadows, 0 radii >2px) DOM-verified. NOT live-validated: setup wizard rendering + (unit-tested only), warn/crit meter states on real hardware (demo node healthy; unit-tested). + ### v0.95.0 — enrollment wizards use the raw-device scan `/disks/candidates` (Impl-2b) (2026-07-01) Final drive-enrollment piece: both enrollment wizards now source candidates from the agent's Impl-2a diff --git a/CONTEXT.md b/CONTEXT.md index 1160ecf..a45230d 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -7,7 +7,28 @@ > > Ask Claude Code: "Please update CONTEXT.md with what we did today" -Last updated: 2026-07-01 (v0.95.0 — enrollment wizards use the raw-device scan; end-to-end raw enrollment live) +Last updated: 2026-07-02 (v0.96.0 — TASK-D0 design system v2 re-skin; live on 9201) + +> **2026-07-02 — v0.96.0 (deployed on 9201): TASK-D0 — design system v2 re-skin (appearance only).** +> The whole customer UI (dashboard AND setup wizard) now renders in the approved v2 language: navy +> token palette (`--bg-0/1/2, --line, --text-1/2/3, --blue, --warn, --crit`), single 2px radius, no +> shadows; **exception-based status color** — nominal is blue/neutral, amber/red only on deviation; +> zone bars → the hairline `.meter` (neutral 70/85 ticks, warn/crit flag „Fogyóban a hely" / +> „Kritikusan kevés hely"); pills → `.tag` / `.metarow`. **Decisions:** (a) `stateColor` semantics +> changed — **stopped/exited = neutral, NOT red** (operator-approved; failures surface via unhealthy +> + alerts); restarting = warn; outputs are now `run/progress/warn/neutral/off` and +> `nominal/warn/crit` — any new template MUST use these suffixes (truth tables guarded by unit tests, +> `stateLabel` copy frozen byte-identical). (b) Fonts (PJS + JBM variable woff2, latin+latin-ext) and +> a 30-icon Lucide sprite are **vendored in the binary** (`/static/fonts/`, `templates/icons.html`) +> — no CDN; `fonts.googleapis.com`, `box-shadow`, 999px and the emoji set are banned strings (grep +> gate in REPORT §5, 143→0). (c) Setup wizard `handleCSS` bug fixed: it read a dataDir-derived path +> that never exists in the container → always served minimalCSS in production; now serves embedded +> `web.StyleCSS()`. (d) Found+fixed pre-existing v0.93.0 bug: `/backups` 500'd once an off-box backup +> had run (`OffboxTarget.LastRun` is an RFC3339 string fed to `timeAgo`; new `timeAgoStr`). +> Canonical reference: `felhom.eu/documentation/design/design-system.md`. **Next: D1** (settings IA +> split + Tárhely main-nav promotion; also migrate the remaining native `confirm()` dialogs to the +> type-to-confirm overlay and finish badge→tag markup on secondary pages). NOT live-validated: setup +> wizard visuals (unit-only), warn/crit meters on real hardware (demo healthy). > **2026-07-01 — v0.95.0 (deployed on 9201): Impl-2b — raw-drive enrollment wizards.** Both enrollment > wizards (`storage_init.html` / `storage_attach.html`) now fetch candidates from the agent's raw-device diff --git a/REPORT.md b/REPORT.md index c5aa799..3e751a8 100644 --- a/REPORT.md +++ b/REPORT.md @@ -1,62 +1,133 @@ -# REPORT — Impl-2b: enrollment wizards → `/disks/candidates` + end-to-end raw enrollment (controller v0.95.0) +# REPORT — TASK-D0: Controller UI re-skin foundation (design system v2) → v0.96.0 -**Date:** 2026-07-01 · **Repo:** `felhom-controller` · **Class:** Risky/supervised (first live raw -enrollment runs the Impl-1 guarded mkfs inside a real enroll). Companion agent work: v0.55.0→**v0.58.0**. +**Date:** 2026-07-02 · **Deployed:** guest 9201 (`gitea.dooplex.hu/admin/felhom-controller:0.96.0`, healthy) -Final piece of the drive-enrollment series: both enrollment wizards now source candidates from the -agent's raw-device scan, so a brand-new (non-PVE-storage) drive is discoverable + enrollable end-to-end. +## 1. Baselines -## 1. Baseline → target +- felhom-controller `main` @ `a390e6be293ec70e56d81f90852bc8c2278981e7` (v0.95.0) — **exactly matched + the spec; main had NOT moved past a390e6b** at session start. +- felhom.eu `main` @ `8c8196e82b69592bd5c0f2166de0987134921590` — matched. -felhom-controller `6ce61e8` (v0.94.0) → **v0.95.0**. Agent v0.55.0 → **v0.58.0** (separate repo — the -raw-drive path needed agent fixes the spec's "N/A agent" premise didn't anticipate; see agent REPORT). +## 2. Commits pushed to `main` -## 2. Files changed + commits +| Commit | Content | +|---|---| +| `b073cc4` | Part 1: vendored fonts + Lucide sprite + setup CSS fix + tests | +| `5dc277f` | Part 2: v2 tokens/components, funcmap remap, layout + dashboard + stacks | +| `f100cef` | Part 3: deploy + backups + monitoring; template-wide var() rename | +| `7df061c` | Part 4: settings visual pass + remaining pages; grep gate zero | +| `4906524` | fix(backups): off-box `LastRun` RFC3339-string 500 (pre-existing, found in click-through) | +| felhom.eu `a336fe3` | docs: `documentation/design/design-system.md` (canonical v2 reference) | -- `internal/agentapi/client.go` — `ListCandidates` + `CandidatesResult`/`DiskCandidate` (mirror the - agent's `/disks/candidates`). -- `internal/web/agent_disk_handlers.go` — `GET /api/disks/candidates` passthrough proxy. -- `templates/storage_init.html` / `storage_attach.html` — fetch `/api/disks/candidates`; render - `initialize` / `attach`; dropped the client-side "already-managed" filter. -- `internal/web/storage_handlers.go` — **`resolveEnrollUUID`**: a raw candidate isn't in `/disks`, so - resolve its fs-UUID from `/disks/candidates` (the enroll blocker the "reuse unchanged" premise missed). - Both `runStorageInit` + `runStorageAttach` use it. -- Tests: `agentapi` `TestListCandidates`(+`_Error`), `web` `TestRunStorageAttach_RawCandidate`(+red-proof). -- `CHANGELOG.md`, `README.md`. Commits **`feab92c`** (wiring) + **`bea05ea`** (resolveEnrollUUID) on `main`. +## 3. Files created / modified -## 3. Green gate +**Created:** `controller/internal/web/static/fonts/{pjs-latin.woff2 27.3K, pjs-latin-ext.woff2 21.7K, +jbm-latin.woff2 31.4K, jbm-latin-ext.woff2 11.6K}` (4 variable-font files, ~92 KB total — Google now +serves variable fonts, so one file covers all weights per subset instead of the estimated ~14 files); +`templates/icons.html` (30-icon Lucide sprite); `internal/web/fonts_test.go`, +`internal/web/funcmap_test.go`, `internal/setup/css_test.go`; +`felhom.eu/documentation/design/design-system.md`. -`go build ./...`, `go vet ./...`, `go test ./...` — clean. Image `felhom-controller:0.95.0` built on 180, -deployed to guest 9201 (golden/bootstrap), `Up (healthy)`. +**Modified:** `internal/web/{embed.go (fonts FS + StyleCSS()), server.go (/static/fonts/ route), +funcmap.go (stateColor/usageColor/tempColor remap + timeAgoStr)}`; +`internal/setup/handlers.go` (handleCSS → embedded CSS; minimalCSS retokened); +`templates/style.css` (rewritten in place); all 19 web templates; setup templates (v2 token +fallbacks); CHANGELOG.md, CONTEXT.md, controller/README.md, REPORT.md. -## 4. End-to-end live validation (real UI, claude-in-chrome, felhom.demo-felhom.eu) +## 4. Tests + red-proofs -| Step | Result | -|------|--------| -| **Discovery (init wizard)** | ✅ `/dev/sdd` (SD/MMC/MS PRO, 59 GB, ext4) offered as the **sole** candidate; sda/sdb/sdc NOT shown. | -| **Format via Impl-1 guard** | ✅ enroll ran the guarded mkfs on /dev/sdd (`formatted device … fstype=ext4`) — the first real customer-flow guarded format. | -| **Discovery (attach wizard)** | ✅ the ext4 /dev/sdd offered under `attach`. | -| **Enroll end-to-end** | ✅ wizard attach → `resolveEnrollUUID` → mount (`/mnt/teszt_enroll`) → bind (`/mnt/felhom-drives/teszt_enroll`) → intent `enrolled` → guest-bind recorded → registered. UI shows **"Aktív"** (USB), alongside felhom-usb + felhom-flash, all Active — no false detach. | -| **Health-tracked** | ✅ the watchdog (RegistryKnownTargets) detected + self-healed a drop of the drive during testing. | +- `go build ./... && go vet ./... && go test ./...` **green after every commit**; final full run exit 0, + 18 packages ok. Test functions 256 → **263** (+7). +- **funcmap red-proof:** truth-table tests run against the stashed pre-change funcmap **failed exactly + as required** — `stateColor("stopped") = "red", want "neutral"` and `usageColor(0) = "green", want + "nominal"` (plus tempColor). Restored; all pass. +- **setup-CSS red-proof:** Scenario E test against the pre-fix `handleCSS` **failed** with + `body length = 3592, want > 10000` (minimalCSS served). With the fix: passes, and asserts the + `--bg-0: #0A1220` literal + byte-equality with `web.StyleCSS()`. +- Template-parse tests (`TestTemplatesParse`, `TestTemplatesParseWithFuncmap`) already existed and + cover Group G; they pass with the new funcmap + icons partial. -**Note on the init slow-format path:** a *slow* device (the 60 GB SD card, ~25 s mkfs) exceeds the -controller→agent request timeout; `runStorageInit` calls `FormatDisk` synchronously and does NOT poll the -agent's detached-format status (`/disks/format/status`), so on a slow device it aborts after the format -detaches and the mount/bind back-half doesn't run. **Pre-existing** (F20-BUG3-adjacent; not the Impl-2b -wiring). The end-to-end above was completed via the **attach** path (no mkfs) — which fully exercises the -candidate→enroll→active pipeline. Follow-up: make `runStorageInit` poll the detached-format status. +## 5. Grep gate (Test Group F) — counts before → after -## 5. NOT done / follow-ups +All 34 patterns measured identically over `controller/internal/{web,setup}` (*.go, *.html, *.css): -- **Init slow-format polling** (above) — `runStorageInit` should poll `/disks/format/status` so a - slow-device format completes the enroll in one flow. -- **Impl-3** — the shared-box operator gate for self-serve format (raw-passthrough blind spot). The demo - is a dedicated box, so self-serve format is appropriate there. -- The throwaway `/dev/sdd` (SD card) is left **enrolled + Aktív** as living proof; the operator can eject - it via the UI (Leválasztás) and unplug when done. +| Pattern | Before | After | Pattern | Before | After | +|---|---|---|---|---|---| +| fonts.googleapis.com | 1 | 0 | system-bar-green | 4 | 0 | +| border-radius: 999px | 5 | 0 | system-bar-yellow | 4 | 0 | +| box-shadow | 31 | 0 | system-bar-red | 4 | 0 | +| #0d1117 | 3 | 0 | state-text-green | 9 | 0 | +| #161b22 | 1 | 0 | state-text-red | 7 | 0 | +| #1c2128 | 4 | 0 | state-text-yellow | 3 | 0 | +| #30363d | 6 | 0 | state-text-orange | 1 | 0 | +| #238636 | 5 | 0 | ⚙ / ✏ / ✕ / ⏳ | 1/2/1/2 | 0 | +| #da3633 | 4 | 0 | ✅ / ❌ | 14/5 | 0 | +| #d29922 | 3 | 0 | ⚠ | 18 | 0 | +| #db6d28 | 2 | 0 | ℹ️ | 3 | 0 | -## 6. Observations +**Total: 143 → 0.** (🔧🔒📦🔗🔴🟡💾 were 0 in both.) Beyond the gate, related glyphs (✓✗⟳⏸🔄🔍) were +also swept, and pre-existing never-defined `var(--success/--danger/--primary/--warning/--accent)` +references in templates were mapped to v2 tokens. -- The spec's premise ("just wire the wizards; the enroll flow already works") was optimistic: the entire - enroll + tracking machinery assumed a PVE-storage drive (`Observe()`), so making raw drives first-class - required `resolveEnrollUUID` here + a chain of agent fixes (see agent REPORT). All shipped + validated. +## 6. Deployment + live validation (claude-in-chrome) + +``` +gitea.dooplex.hu/admin/felhom-controller:0.96.0 Up 8 seconds (healthy) +``` +Startup logs clean (hub report pushed, 5 health probes ok). Sidebar shows 0.96.0. + +Chrome checks performed on `https://felhom.demo-felhom.eu` (screenshots taken per page; ő-glyph zoom +saved to disk): + +1. **Full click-through:** dashboard, Alkalmazások (filters render, grid kept), app-info (calcom), + deploy page for actualbudget (**opened only — not deployed**; two-segment memory meter renders: + solid-blue committed + 35%-opacity new), backups, monitoring (charts render in the new palette — + cpu sky-blue, memory violet; JS-generated host-storage meters blue), logs (mono, blue Élő dot), + settings (all sections; drive cards with pencil icons, run/USB tags, crit-outline danger buttons). +2. **Type-to-confirm dialog:** opened the drive-list eject („Meghajtó leválasztása", type-to-confirm + input, disabled crit-outline Megerősítés) and **cancelled** it; verified afterward the drive is + still mounted and zero disconnect/eject calls hit the API. +3. **Scenario D:** zero requests to fonts.googleapis.com/gstatic; `/static/fonts/*.woff2` → 200 + (pjs-latin, pjs-latin-ext, jbm-latin loaded); `document.fonts.check("1em 'Plus Jakarta Sans'")` + and JBM both `true`; „…rendszermentéstől" ő renders in the brand face (zoom screenshot saved). +4. **Scenario A (DOM-asserted via JS):** 0 elements with green (35,134,54) backgrounds, 0 elements + with box-shadow, 0 border-radius values other than 0/2px/50%; „Leállítva 0" stat renders muted; + running rows blue tag + blue 2px edge. +5. **Login/logout:** NOT exercisable live — the demo node runs with auth disabled (`/login` is 404, + no logout link; the known pre-existing unauth-demo state). Login page covered by template-parse + tests; the two-tone H1 was added (`Otthoni vezérlőpult`). + +## 7. Bug found & fixed during validation + +`GET /backups` returned **500** on first visit: `backups.html` passed `OffboxTarget.LastRun` (an +RFC3339 **string** persisted in settings.json) to `timeAgo` (expects `time.Time`). Pre-existing since +v0.93.0 (NAS Part B) — it fires on any node where an off-box backup has ever run; the demo node +qualified. Fixed in `4906524` with a `timeAgoStr` funcmap helper (parses RFC3339, falls back to the +raw string); 0.96.0 image rebuilt + redeployed, /backups now renders („Rendben … tegnap"). + +## 8. NOT yet live-validated + +- **Setup wizard visual rendering** — cannot be exercised without re-provisioning; covered by the + Scenario E unit test (embedded v2 CSS served). Await the next supervised reinstall. +- **warn/crit meter states on real hardware** — the demo node is healthy (all meters nominal); + covered at unit level (usageColor thresholds) and by the meter-flag template logic. +- **`.meter-flag` strings live** — same reason (no disk over 70%). + +## 9. Observations (structural, NOT acted on — appearance-only scope) + +1. **settings.html remains monolithic** (~1450 lines, duplicated drive views: template-rendered + registered-storage cards + JS-rendered agent drive list) — D1 scope. ~50 inline `style="…"` + attributes remain there and across pages (reduced only where a v2 class covered them). +2. **Native `confirm()` dialogs** in settings storage actions (`storageDisconnect`, stale-data + delete) vs the custom type-to-confirm overlay elsewhere — inconsistent UX and they block + browser automation; suggest migrating to the overlay in D1. +3. Old `stat-running`/`stat-stopped` class names still appear in backups.html markup (now no-op — + CSS deleted); harmless, cleanable in D1. +4. `badge`/`meta-badge`/`db-type-badge`/`validation-badge` markup survives on secondary pages, + restyled flat by the v2 CSS (2px, dim tokens) — full tag/metarow markup migration on those pages + can complete in D1–D2. +5. The catchall + setup pages are standalone (no sprite); they use inline SVGs / plain text. If + icon needs grow there, consider embedding the sprite per-page. +6. Baseline grep showed 🔧 at 0 despite layout.html's `🔧 Debug` — some emoji encodings differ from + the gate's literals; the gate was still measured identically before/after, and independent broader + sweeps confirmed no emoji remain. diff --git a/controller/README.md b/controller/README.md index 843dd11..8630143 100644 --- a/controller/README.md +++ b/controller/README.md @@ -101,6 +101,15 @@ backups, monitoring and notifications. All Proxmox/disk operations are delegated - **`StackDataProvider` interface** — Breaks circular import between the backup packages and stacks. Defined in `internal/appbackup` (and re-exposed via a type alias in `internal/backup`). Implemented by `stackAdapter` in `main.go`. Provides `GetStackHDDPath()` for per-drive backup routing. - **Atomic file writes** — All persistent state (`settings.json`, `app.yaml`) written to `.tmp` then `os.Rename` for crash safety. - **`go:embed` templates** — All HTML/CSS/JS compiled into the binary. No runtime file dependencies. +- **Design system v2 (v0.96.0, TASK-D0)** — The whole UI renders in the Felhom v2 language (canonical + reference: `felhom.eu/documentation/design/design-system.md`): navy token palette, single 2px radius, + no shadows, exception-based status color (nominal = blue/neutral; amber/red only on deviation — + `stateColor` emits `run/progress/warn/neutral/off`, `usageColor`/`tempColor` emit + `nominal/warn/crit`; a stopped app is neutral, NOT red). Capacity bars are the hairline `.meter` + component; state chips are `.tag`; informational pills are `.metarow`. **Fonts (Plus Jakarta Sans + + JetBrains Mono, variable woff2, latin+latin-ext) and a 30-icon Lucide sprite are vendored in the + binary** (`internal/web/static/fonts/` served at `/static/fonts/`; `templates/icons.html`) — no CDN, + no emoji. The setup wizard serves the same embedded stylesheet via `web.StyleCSS()`. - **Europe/Budapest timezone** — All scheduled jobs, timestamps, and UI labels use Hungarian timezone. ### Module Map @@ -1961,7 +1970,7 @@ controller/ │ ├── alerts.go # State-based alert generation │ ├── funcmap.go # Template functions (state colors, Hungarian formatting) │ ├── embed.go # go:embed for templates + Chart.js -│ └── templates/ # 15 HTML files + style.css (Hungarian UI, incl. debug.html, catchall.html) +│ └── templates/ # 19 HTML files + style.css + icons.html sprite (Hungarian UI, design system v2) ├── configs/ │ ├── controller.yaml.example # Full config reference │ └── example-felhom-metadata.yml # .felhom.yml format reference