--- description: SvelteKit static SPA — derived tool list, telemetry, DaisyUI, no server side paths: - "dashboard/src/**" --- # Dashboard — static SPA (SvelteKit 2 / Svelte 5 / Tailwind 4 + DaisyUI 5) `npm run check` (svelte-check) is the gate — run it after editing any `.svelte` or `.ts` and report the result. **Static SPA (`adapter-static`) served by FastAPI from `dashboard/build` — no Node at runtime, no server side:** - **No `+page.server.ts`, no `$lib/server`, no form actions, no private `$env`.** The dashboard only talks to `/api/*` (and `/mcp` is for external MCP clients, not the dashboard). Secrets live in the backend. - **`npm run build` is required before FastAPI can serve `/`** — an unbuilt dashboard makes the index route return a 503 with build instructions. In dev, the Vite dev server (`:5173`) proxies `/api` and `/mcp` to `:8000`. - **The tool list is derived, not hardcoded.** `/tools` fetches `/api/tools` (which the backend builds from `mcp.list_tools()`), so it stays in sync with the registered MCP tools automatically. Don't hand-maintain a tool list in the frontend — render whatever `/api/tools` returns, including the `premium` flag. - **Two routes:** `/` (status: cache/API/MCP health cards, followed teams, tools list, request log) and `/tools` (interactive runner → `POST /api/run`). Shared fetch/types live in `src/lib/api.ts` / `src/lib/types.ts` — update types alongside backend response shape changes. **Runes & types:** - Runes mode (`$state`, `$derived`, `$props`, `$effect`); `$derived` for computed, `$effect` only for genuine side effects. Props via `let { … } = $props()` (typed), no `export let`. - `onMount` cleanup must be synchronous. **Browser telemetry:** report JS errors to `POST /api/v1/telemetry` (the unprotected sink) so browser failures surface in Loki at WARNING — don't let them be silently lost (`red_panda_standards.md`). Styling: Tailwind 4 + DaisyUI 5 components. No new CSS frameworks. No emojis in the UI — use an icon set.