fleet-manager: checkpoint 6 — the admin SPA (fleet command deck)
The themed single-page admin UI (serving/fleet-manager/ui/), embedded into the binary and served same-origin over the admin plane. - Svelte 5 + Tailwind 4 + Vite; a sibling of serving/kiosk-app. Theme = LYSANDRA 'restricted-violet' (high-security evolution of the kiosk's flight-deck DNA): amber deck, VIOLET reserved for privileged/destructive + auth surfaces, teal telemetry, red alert, clearance chrome (corner-reticle panels, scanlines, mono clearance labels, secure-link status bar). - Passkey gate: Login (usernameless discoverable WebAuthn) + Enrol (from the register-admin one-time link) via navigator.credentials, with base64url<->buffer helpers and the go-webauthn response shapes. - Three pillars over the JSON API: Monitor (fleet roster + version-drift + health + per-host detail with bespoke SVG telemetry charts), Authorise (pending queue: fingerprint cross-check, approve+bind in violet, deny), Lifecycle (desired-state form; drain/reboot confirm-gated). Session-aware fetch client (cookie + CSRF). - go:embed behind the build tag (spa_embed.go / spa_stub.go) so the default go build/test need no dist/; mounted at / (api/auth/healthz win). Verified: npm build clean (71KB JS / 33KB CSS + self-hosted fonts); default + -tags embedspa go builds; smoke test serves index + assets + API through the SPA origin. Against an insecure+seeded backend the deck renders passkey-free for theme work. dist/ + node_modules gitignored.
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
# fleet-manager UI — the fleet command deck
|
||||
|
||||
The admin SPA for `fleet-manager`. **Svelte 5 + Tailwind 4 + Vite**, themed
|
||||
**LYSANDRA / restricted-violet** (a high-security evolution of the kiosk-app's
|
||||
LYSANDRA flight-deck: amber deck, **violet reserved for privileged/destructive +
|
||||
auth surfaces**, teal telemetry, red alert, clearance chrome). A sibling of
|
||||
`serving/kiosk-app`, kept in-repo for now (may graduate to its own submodule).
|
||||
|
||||
Three pillars over the manager's JSON API, plus the passkey gate:
|
||||
|
||||
- **Login / Enrol** — WebAuthn ceremonies (`navigator.credentials`). Enrol is
|
||||
reached via the one-time link from `fleet-manager register-admin`.
|
||||
- **Monitor** — fleet roster (online / version-drift / health) + per-host detail
|
||||
with bespoke SVG telemetry charts (from `/api/hosts/{serial}/metrics`).
|
||||
- **Authorise** — pending-enrolment queue: cross-check the fingerprint, approve
|
||||
(violet) + bind, or deny.
|
||||
- **Lifecycle** — per-host desired-state (version pin, kiosk URL, reboot, drain);
|
||||
destructive changes are confirm-gated.
|
||||
|
||||
## Build / embed
|
||||
|
||||
The built SPA is embedded into the `fleet-manager` binary via `go:embed` and
|
||||
served same-origin over the admin plane.
|
||||
|
||||
```bash
|
||||
npm ci
|
||||
npm run build # -> dist/ (gitignored)
|
||||
cd .. && go build -tags embedspa # embeds dist/ into the binary
|
||||
```
|
||||
|
||||
The default `go build` (no tag) ships a stub instead, so Go builds/tests don't
|
||||
require `dist/`. The Dockerfile does the two-stage build (npm → dist → go build
|
||||
`-tags embedspa`).
|
||||
|
||||
## Dev
|
||||
|
||||
```bash
|
||||
npm run dev # Vite on :5173, proxies /api + /auth to :9500
|
||||
```
|
||||
|
||||
Point it at a locally-running manager. Against an **insecure+seeded** manager
|
||||
(`FLEET_MGR_ADMIN_INSECURE=true FLEET_MGR_SEED=true`), `/api/whoami` returns
|
||||
`dev-insecure`, so the SPA renders the pillars **without a passkey** — handy for
|
||||
theme/layout work. Passkey login/enrol need the manager in secure mode with a
|
||||
valid RP origin + a WebAuthn authenticator.
|
||||
Reference in New Issue
Block a user