Getting started
Stack
| Framework | SvelteKit™ |
| UI runtime | Svelte™ 5 (runes mode exclusively) |
| Language | TypeScript® (strict) |
| Component primitives | Shadcn-Svelte™ (vendored in src/lib/components/ui/) |
| Styling | Tailwind CSS™ |
| Package manager | pnpm |
| Test runner | Vitest |
| i18n | Custom Paraglide-based message store in src/lib/i18n/ |
Commands
| Install | pnpm install |
| Dev server | pnpm run dev (port 5173) |
| Typecheck | pnpm run check |
| Build | pnpm run build |
| Tests | pnpm run test |
| Component extraction | pnpm extract-docs |
pnpm extract-docs regenerates docs/user-guide/_extracted/components.json
from every .svelte file under src/lib/components/ using sveld. Run it
whenever component props change before refreshing the API reference page.
Project layout
Code
Verify the dev server
After pnpm install and pnpm run dev, open http://localhost:5173 in your
browser. You should see the login page. The frontend talks to the backend at
http://localhost:3001 — if the backend is not running, the page still loads
but the login form will show a connection error.
To verify the typecheck passes:
Code
To regenerate the component API extraction (needed before refreshing the API reference page when component props change):
Code
Svelte 5 conventions
This repo uses runes exclusively. The key rules (enforced in AGENTS.md):
- State:
let x = $state<Type>(value) - Props: typed destructuring from
$props()—let { name }: { name: string } = $props(); - Derived:
$derived(expr)(no anonymous functions) or$derived.by<Type>(() => { ... }) - Events: callback props, never
createEventDispatcher - Children/snippets: typed as
Snippet
Composable state exposure pattern
All use* composables consolidate internal $state into a single _state
object and expose it read-only via a get state() getter returning
DeepReadonly<typeof _state>. Mutations happen only through exposed mutator
functions. $derived values are exposed via individual getters, never inside
the $state object.
Code
Error notifications
Never call toast.*() directly. Use pushNotification(...) from
$lib/errors/app-errors so errors appear in both the topbar error badge /
errors sheet and as a toast with correct impact styling.
Data model conventions
All TS types, component props, and store shapes use snake_case matching
the backend JSON response. No DTO layer renames fields between the API
response and the TS model. See .devin/rules/data-model-conventions.md for
the full rule.
Next steps
- App shell & sidebar
- Authentication & sessions
- Entity list table
- Component catalog — every custom/wrapped component
- UI stack — the five layered UI technologies