- FinishRollingUpdateIfPending() auf API-Startup: transitiert
updating-primary → done damit der UI-Flow nach Restart abschließt
- RollingUpdateStatus: setzt done nach Auslieferung auf idle zurück
(verhindert Stale-done bei Page-Reload)
- wasRollingActiveRef: reagiert auf done nur wenn rolling in DIESER
Session aktiv war — kein sofortiger Reload bei Stale-State
- UI-Fallback für updating-primary: poll auf /system/health version-flip
- Cluster-Erkennung via /cluster/status; Rolling-Update-Button nur im Cluster
- Update-Banner-Button nicht mehr gequetscht (flex-shrink:0 + nowrap)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
POST /cluster/rolling-update startet den gestaffelten Upgrade-Prozess:
1. Secondary via mTLS /agent/cluster/trigger-update anstoßen
2. /agent/cluster/version pollen bis Secondary Version-Flip zeigt (max 10 min)
3. Primary self-upgrade via systemd-run (identisch zu /system/upgrade)
State wird in /var/lib/edgeguard/rolling-update-state.json persistiert:
Phasen: updating-secondary → waiting-secondary → updating-primary.
"done" wird nicht geschrieben — Prozess stirbt beim Upgrade. UI erkennt
Abschluss via /system/health version-flip (analog Single-Node-Upgrade).
UI: UpdateBanner erkennt Cluster-Modus (/cluster/status mode="cluster")
und tauscht den "Install now"-Button gegen "Rolling Update (Cluster)" aus.
Multi-Step-Modal zeigt die drei Phasen; ab updating-primary wechselt der
Client auf /system/health polling.
Aggregator.PostPeer: neuer einzel-POST-Helper für mTLS-trigger-update.
WithVersion(): ClusterHandler bekommt Binary-Version für /agent/cluster/version.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
handler: edgeguard-User darf systemd-run nicht direkt aufrufen ("Inter-
active authentication required"). sudo -n + sudoers-Whitelist auf
exakt die Unit-Form für edgeguard-upgrade.service.
UI: UpdateBanner-Komponente neu — Pattern wie mail-gateway/enconf:
Banner mit Force-Check-Button + Popconfirm. Beim Apply zeigt full-
screen-Overlay mit animiertem Orbit (zwei Ringe + Dots), Versions-
sprung, vier Step-Indicators (Download/Install/Restart/Verify) und
Live-Timer. Poll auf /system/health detektiert Version-Flip ODER
"sah down dann up" und window.reload nach 1.5s. Sicherheits-Timeout
2 min schickt sonst auch reload.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Vorher: Update-Banner war eine Inline-Alert mit "Apply now"-Button —
ein Click → Hintergrund-Apt-Run, kein Feedback ob's durch ist.
Jetzt:
* Banner zeigt nur noch Hint + "Details anzeigen"-Button.
* Modal listet alle Pakete mit Upgrade (installed → available),
prominenter Warnhinweis dass edgeguard-api+scheduler restartet
werden (~2-5s Unterbrechung) — HAProxy/nft/WG/Squid/Unbound/Chrony
bleiben durch.
* "Jetzt anwenden" startet den apt-Run, Modal schaltet auf Apply-
Mode (kein Cancel mehr, Progress-Alert mit aktueller→Ziel-Version).
* Polling von /system/health auf 2s erhöht während Apply. Sobald
health.version == target → success-toast + auto-reload der UI
(1.5s delay damit das neue UI-Bundle gecached werden kann).
Pattern entlehnt von enconf/mail-gateway. Plus i18n-Erweiterung
für update.modalTitle / modalIntro / modalWarn / applyingHint /
applyingDetail / success.
Version 1.0.45.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Scaffold und Core-Infrastruktur 1:1 nach enconf-Pattern (netcell-
webpanel/management-ui), reduziert auf EdgeGuard-Scope (kein reseller/
customer-Roles, keine codemirror/extensions). Stack: React 19 + AntD 6
+ TS strict + Vite + TanStack-Query + zustand + react-i18next.
Layout: AppLayout (Sider+Header+Content), Sidebar (Dashboard/Domains),
Header (User-Dropdown + Logout). i18n mit de/en common.json.
Pages: Login (POST /auth/login), Setup-Wizard (POST /setup/complete),
Dashboard (Health-Polling + Statistics), Domains (volles CRUD via
TanStack-Query gegen /domains-API). UpdateBanner-Komponente
(/system/package-versions, alle 5 min poll, /system/upgrade trigger)
ist von Tag 1 wie vom User gefordert eingebaut.
API-Wiring: cmd/edgeguard-api/main.go mountUI() — gin StaticFS für
/usr/share/edgeguard/ui/ (overridebar via EDGEGUARD_UI_DIR), echte
Files werden direkt geserved, alle nicht-API-Pfade fallen via
NoRoute auf index.html für React-Router-SPA. Wenn dist/ fehlt:
HTML-Placeholder mit Build-Hinweis.
Verifiziert: bun install + npx tsc -b strict (0 errors) + bun run
build (12 chunks). End-to-end gegen /tmp/eg-api: / serviert echte
React-index.html, /domains SPA-Fallback, /api/v1/* JSON, /assets/*
direkt, /api/v1/nonexistent korrekt 404.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>