# 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.