Skip to content

SCRUM-246 — AdminUI design system

Plan ref: UI-1 (docs/11-admin-plane-plan.md).

What exists

Piece Notes
src/theme/tokens.css the only file with colour values: --ds-* roles (bg, surface, border, text, accent, status ok/warn/danger/info/neutral + -soft), 4 px spacing scale, type scale, radii, elevation, mono font; light on :root, dark via prefers-color-scheme and Ionic's dark-palette class; mapped onto Ionic's --ion-* variables
src/components/ui/ PageHeader, Toolbar, Grid, Panel, DataTable (generic, cell slots, sticky header, scrolls inside its own box), StatTile, StatusDot (label always rendered unless compact), EmptyState (moved here), ErrorPanel (COM-5/ApiError, request id), CopyableId
Views every view, the shell and the JSON editor rebuilt on the primitives; behaviour, text and test ids unchanged. The namespace name in the Config list is now a real link (keyboard reachable); a row click still opens it
Guard rail tests/unit/design-tokens.spec.ts fails on any colour literal outside tokens.css and on any var(--ds-…) that tokens.css does not define
CodeMirror syntax colours come from tokens via @codemirror/language + @lezer/highlight, now declared dependencies (same versions the lockfile already had) and pre-bundled in dev (optimizeDeps.include)

How to verify

cd services/adminui
npm ci
npm run typecheck && npm run lint && npm run format:check && npx vitest run && npm run build
npx playwright test          # mock API; run twice with `rm -rf node_modules/.vite` first
npm run dev:mock             # look at /admin/dashboard, /admin/config in light and dark, at 1280 and 400 px

Results at time of writing

  • typecheck, lint (0 warnings), prettier, vitest (215 tests), build: pass.
  • Playwright sign-in suite: 5/5, including from a cold Vite cache.
  • Screenshots checked: dashboard at 1280 and 400 px (no horizontal scroll), config list in dark mode.

How it was built

DeepSeek run scoped (Landlock) to services/adminui (389 s, ~67k output tokens, reasoning effort low). Claude review: - the Playwright sign-in test failed: the namespace names were no longer headings (now a table), and on a cold dev server Vite discovered the new CodeMirror imports late and reloaded mid-navigation. Fixed by making the name a link (test asserts the link) and pre-bundling the three packages; - declared @codemirror/language and @lezer/highlight, which the editor now imports directly, instead of relying on them being transitive.