Replaces the localStorage-only LLM settings with a persisted catalogue backed by /api/v1/admin/llm-configurations. The Settings → LLM screen now has two cards: - "Saved configurations" — full CRUD against the server. Each row shows provider/model/secret/published per-1M-token costs. Add wizard auto-fills costs from the curated catalog. One-click "Import local" button promotes any pre-existing localStorage settings into a server row, then clears the local store. - "Active LLM (this session)" — the existing LLMProvidersSettingsCard, scoped down to "what does the Assistant use right now" (still localStorage; per-operator). Spend (30d) tile in the configurations card header reads /api/v1/ai/llm/usage/summary and surfaces total cost / requests / tokens. First visible cost roll-up in the admin UI. New module app/lib/arcadia/llm-configs.ts: typed CRUD client, catalog lookup, computeCostCents helper (mirrors the server's LlmConfiguration.compute_cost_cents/3), and getUsageSummary. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
components/
Component layers in this project.
ui/ shadcn primitives — token-driven, reskinnable per design system
forms/ composed form widgets
data/ data display (tables, filters, empty states)
layout/ app shell, page chrome, navigation wrappers
marketing/ landing and marketing blocks
[system]/ design-system-specific components (e.g. m3/, apple/)
The one rule
Custom components import from ui/, never the reverse.
ui/ is the primitive layer. It must stay reskinnable by swapping tokens in
app/themes/*.css alone. If a component can't be expressed that way (M3
ripple, Apple segmented control, etc.), it belongs in a system-specific
folder — not ui/ and not the shared folders above.
Tokens, not values
Every custom component should reference semantic tokens:
- Colors:
bg-primary,text-muted-foreground,border-border - Radius:
rounded-md,rounded-lg - Fonts:
font-sans,font-heading
Hardcoded hex, oklch, or px values are a bug — they break theming.