Documentation

Developer handbook

How this codebase is organised: the token layer and two skins, how routing splits marketing, auth, and the real app, where the data layer points, and how dense Figma exports are quarantined so the rest of the code stays hand-written and readable.

Framework and sources of truth

  • SvelteKit with TypeScript, served through adapter-node. Fonts are self-hosted via @fontsource (Inter, Urbanist, Geist).
  • No Tailwind in application code. Every design token, reset rule, and base type style lives in src/app.css; component-local styling uses Svelte's auto-scoped <style> blocks.
  • Two visual skins are selected with a data-skin attribute — "marketing" for the public site and "app" for the authenticated product.

Routing map

Route groups keep the three surfaces separate while sharing one deployment.

SegmentURLPurpose
src/routes/(marketing)/, /pricing, …Public site; shared header + footer chrome.
src/routes/(auth)/signinSign-in; no marketing chrome.
src/routes/app/appAuthenticated product, guarded in +layout.server.ts.

Group folders in parentheses set layout and grouping without adding a URL segment, so (marketing)/pricing still resolves to /pricing.

Tokens and theming

src/app.css is the single source of truth for colour, spacing, radius, shadow, and typography. Marketing-specific values (section padding, header offsets, the hero gradient, stat/heading sizes) sit alongside the core palette.

  • Reach for a token before a literal: var(--color-accent), var(--section-gutter-x), var(--header-stack-height).
  • The header is fixed, so full-bleed pages clear it with calc(var(--header-stack-height) + …) rather than a magic number.
  • Switching data-skin re-points the same semantic tokens, so components don't hard-code skin colours.

Data layer

UI never calls fetch directly. A typed client in $lib/api talks to PUBLIC_API_BASE_URL. In development that points at the local mock; in production it points at the real backend — a one-variable swap, no code change.

backend/ — FastAPI over file-based SQLite (db.py + mock_data.py)
$lib/api — typed request helpers, shared response types
PUBLIC_API_BASE_URL — dev: http://localhost:8000 · prod: real API

Authentication

  • Sign-in works without JavaScript (progressive enhancement) and with it.
  • The session is an httpOnly cookie; a CSRF token guards state-changing posts.
  • The app/ segment is guarded server-side, so an unauthenticated request never renders the shell — it redirects to /signin.

The legacy quarantine

Two kinds of UI live in this repo. Genuine, clean interface is hand-written against tokens. A few Figma exports are too dense to re-hand-write faithfully — those are isolated instead of omitted.

  • The source React component is server-rendered once to static HTML and stored under src/lib/legacy.
  • A thin Svelte wrapper injects that snapshot with {@html …}.
  • Tailwind is precompiled only for those snapshots (legacy-utilities.css), with no global preflight, so it can't leak into the hand-written surface.

This keeps pixel fidelity on the hard artboards (the footer illustration, the workspace dashboard) without dragging their complexity into the rest of the codebase. Anything interactive — the scrollspy catalogs, the billing toggle — is rebuilt cleanly in Svelte, since a static snapshot can't carry behaviour.

Marketing section system

Pages in $lib/marketing compose small primitives: a section shell and header, hero variants, the closing CTA, and testimonials. Catalog pages (use-cases, teams) share one scrollspy pattern built on IntersectionObserver — the observer sets the active tab as each panel enters a centred band, and tab clicks scroll their panel into view behind a short scroll-lock so the two never fight.

Running it locally

# backend (mock API)
cd backend && uvicorn mock_data:app --reload

# frontend
npm install
npm run dev

Type-check and build with npx svelte-check and npm run build; the production server runs via node build.

Fortal