Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Admin UI design system

Audience: contributors changing anything served from internal/server/static/.

Aperture's admin UI shell follows the BERA Design System. These rules are not style preferences — several are load-bearing, and reviewers enforce them. Nothing here is derivable from the code, which is why it lives in the docs.

Voice

An analyst's tool: information density, analytical seriousness, proof-led copy. Address the reader in second person ("your grants"), never "users". Sentence case everywhere, with one exception — small form-field labels are uppercase with 0.06em letter-spacing.

Colour

Use named tokens, never raw hex.

  • BERA Blue ramp --bera-25--bera-900. Primary action is --bera-600, hover --bera-700.
  • AI-pink #ff3399 is reserved for AI affordances only — the assistant button, an "Ask BERA" pill, AI badges. It is forbidden for primary actions, alerts, and decoration. This one is load-bearing: a pink primary button is a bug, not a taste difference.
  • Data-visualisation families (grass, strawberry, blueberry, plum, rose, orange, apricot, bera) each carry a 25→900 ramp. A series keeps its colour identity across every chart it appears in. Never invent a chart colour.
  • Neutrals: page background --neutral-200 (#f8fafc), card #fff, body text #333333. Pure black is reserved for the wordmark.
  • Semantic roles: --color-primary / -success / -warning / -danger / -info, --color-bg / -surface, --color-fg / -muted, --color-border (slate-200), --color-focus-ring (bera-500).

Typography

  • Display: BwGradual (commercial). If the .otf is not shipped, fall back to the system sans — never substitute Inter or Roboto.
  • Body: IBM Plex Sans.
  • Mono: IBM Plex Mono, tabular numerals. Use it for every object-identity string, entity id, and token-like value — account:acme/project:atlas/document:42 is mono, always.
  • Scale --text-2xs--text-6xl; semantic classes .bera-h1.bera-h4, .bera-body, .bera-label, .bera-numeric.

Spacing, radius, motion

4px base unit; when in doubt take the tighter value (analyst density). Radius sm 4 / md 8 / lg 12 / xl 20 / full. Shadows: card, raised, floating, plus the focus ring. Motion is fade plus a 4–8px translate — no bounces, no springs. Durations: fast 150ms, base 250ms, chart 600ms.

Layout

Dashboard is a fixed left sidebar (~232px) plus a top utility bar (~52px) over flex content. 12-column grid, 8–12px gutters. Modals cap at 720px, or 1080px for heavy workflows.

Iconography

Lucide, stroke-only at 1.5px. 16px inline, 20px default. Always pair an icon with text. AI surfaces may use sparkles / bot / wand-2 in AI-pink.

Hard nos

  • No emoji anywhere — including ✅ and 🎯 in confirmations and empty states.
  • No exclamation points, no hype words, no "users".
  • No invented chart colours.
  • No gradients as decoration.
  • The primary button is not pink.

Vendored assets, and why there is no build step

Everything the UI needs is committed pre-built under internal/server/static/vendor/ and //go:embed-ed: Alpine, Tailwind, DaisyUI, and the Rete.js dist bundle (generated by rete-kit/rete-cli). There is no node build pipeline in development or CI — the binary ships self-contained, and CI is node-free by design. Regenerating a vendored bundle is an occasional, explicit, manual step, never something a build performs.

That node-free property is also why internal/server/static/js/rules-serializer.test.js never runs in the pipeline, and why rules/editor_js_contract_test.go — which reads the JavaScript from disk and diffs its tables against the Go rule AST — is the real parity gate. See Build, test & lint gates.