Operator sets a minimum controller version (FLOOR), per-customer defaulting to a
global floor; the report ACK returns the effective floor + latest_version so the
controller auto-updates to the floor when below it (latest stays the opt-in button).
- store: min_controller_version column + hub_settings global floor + Effective/
Get/SetGlobal/SetMin resolution + config/env DEFAULT_MIN_CONTROLLER_VERSION
- handler: report ACK {min_controller_version, latest_version}; LatestVersionProvider
- web: global floor editor + per-customer override form + Floor column (English)
- tests: floor resolution + ACK + render; override-precedence red-proof verified
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FSZmmSFVzGwEzhYmxbkgBK
3.0 KiB
felhom.eu — task reports
Overwrite this file with a summary of the most recent task only (uniform with the other repos; not cumulative). The cumulative hub history lives in hub/CHANGELOG.md.
hub v0.15.0 — Phase 2 managed updates: per-customer controller-version floor (2026-06-27)
Why. Phase 1 gave enthusiasts an opt-in "update to latest" button. Phase 2 adds the managed default: the operator sets a per-customer minimum controller version (defaulting to a global floor), and any box below it auto-updates on its next report — so the household that never clicks stays current and patched. Floor = the operator's enforced minimum and the auto-target; latest stays the customer's manual opt-in.
Files changed
internal/store/store.go—customer_configs.min_controller_versioncolumn;hub_settingsKV table;defaultMinControllerVersion+SetDefaultMinControllerVersion;Get/SetGlobalMinControllerVersion,SetMinControllerVersion,EffectiveMinControllerVersion.internal/api/handler.go—LatestVersionProviderinterface +SetLatestVersionProvider; report ACK returns{min_controller_version, latest_version}(both omitted when empty).internal/web/configs.go,server.go,templates/configs.html,templates/customer_unified.html— operator UI: global floor editor + per-customer override form + Floor column / below-floor markers; routesPOST /configs/global-floor,POST /customers/{id}/floor.cmd/hub/main.go—Config.ControllerUpdates.DefaultMinVersion(yamldefault_min_version, envDEFAULT_MIN_CONTROLLER_VERSION); seeds the store default; wires the version checker as latest provider.
Design
- Effective floor = per-customer override if non-empty, else global (hub_settings → config/env default), else "" (Phase 2 inert for that customer).
- Rides the existing report cycle — no new floor-polling endpoint. The actual swap is the
controller's Phase 1 flow (in-guest pull → agent
POST /controller/swap→ rollback); the hub only advertises the floor. No agent change.
Tests (go test ./... green)
internal/store/floor_test.go— empty-when-unset; global-default fallback; DB-overrides-default; override-beats-global (companion red-proof); set-and-preserve-across-save.internal/api/floor_ack_test.go— ACK carries effective floor (override beats global) + latest; omits both when unset.internal/web/render_test.go— template render smoke (catchestemplate.Mustpanics + floor fields).- Companion red-proof (verified): making
EffectiveMinControllerVersionignore the override →TestEffectiveFloor_OverrideBeatsGlobalANDTestReportACK_FloorAndLatestFAIL → restored → green.
Green gate
go build ./... && go vet ./... && go test ./... → all pass.
Deploy
Built + pushed gitea.dooplex.hu/admin/felhom-hub:0.15.0, manifest bumped + synced (see hub/CHANGELOG
and the live-test summary in felhom-controller/REPORT.md for the end-to-end floor auto-update result).