# Frontend — Familienarchiv ## Overview SvelteKit 2 application providing the Familienarchiv web UI. Server-side rendered (SSR) where beneficial, with client-side interactivity for document viewing, transcription, annotation, and admin workflows. ## Tech Stack - **Framework**: SvelteKit 2 with Svelte 5 (runes mode) - **Language**: TypeScript 5.9 - **Styling**: Tailwind CSS 4.1 + custom brand utilities - **Build Tool**: Vite 7 - **Adapter**: `@sveltejs/adapter-node` (Node.js server, not static) - **i18n**: Paraglide.js 2.5 (`@inlang/paraglide-js`) — German (default), English, Spanish - **API Client**: `openapi-fetch` + `openapi-typescript` (generated from backend OpenAPI spec) - **PDF Rendering**: `pdfjs-dist` (PDF.js) - **Testing**: - Unit/Server: Vitest 4 (Node environment) - Component: Vitest Browser Mode with Playwright (Chromium) - E2E: Playwright (`frontend/e2e/`) ## Project Structure ``` src/ ├── routes/ # SvelteKit file-based routing │ ├── +layout.svelte # Global layout: header, nav, auth state │ ├── +layout.server.ts # Loads current user, injects auth cookie │ ├── +page.svelte # Home / document search dashboard │ ├── documents/ # Document CRUD, detail, edit, upload │ ├── persons/ # Person directory, detail, edit, merge │ ├── briefwechsel/ # Bilateral conversation timeline │ ├── chronik/ # Unified activity feed │ ├── admin/ # User, group, tag, OCR, system management │ ├── api/ # Internal API proxies (server-side only) │ ├── login/ logout/ # Auth pages │ └── ... ├── lib/ │ ├── components/ # Reusable Svelte components │ │ ├── document/ # Document-specific components │ │ ├── chronik/ # Activity feed components │ │ └── user/ # User-related components │ ├── generated/ # Auto-generated API types (openapi-typescript) │ ├── server/ # Server-only utilities (db, auth helpers) │ ├── services/ # Client-side service logic │ ├── stores/ # Svelte stores (global state) │ ├── types.ts # Shared TypeScript types │ ├── errors.ts # Error code mapping (mirrors backend ErrorCode) │ ├── api.server.ts # Typed API client factory │ ├── utils.ts # Shared utilities │ ├── relativeTime.ts # Time formatting │ ├── search.ts # Search utilities │ └── paraglide/ # Generated i18n code ├── hooks/ # SvelteKit hooks (handle, handleFetch) └── actions/ # Custom Svelte actions (click outside, etc.) ``` ## API Client Pattern All server-side API calls use the typed client from `$lib/api.server.ts`: ```typescript const api = createApiClient(fetch); const result = await api.GET('/api/persons/{id}', { params: { path: { id } } }); // Always check via response.ok, NOT result.error if (!result.response.ok) { const code = (result.error as unknown as { code?: string })?.code; throw error(result.response.status, getErrorMessage(code)); } return { person: result.data! }; ``` Key rules: - Use `!result.response.ok` for error checking (not `if (result.error)` — breaks when spec has no error responses defined) - Cast errors as `result.error as unknown as { code?: string }` to extract backend error code - Use `result.data!` after an ok check For multipart/form-data (file uploads), bypass the typed client and use raw `fetch`. ## Form Actions Pattern ```typescript // +page.server.ts export const actions = { default: async ({ request, fetch }) => { const formData = await request.formData(); const name = formData.get('name') as string; // ... return fail(400, { error: 'message' }); // on error throw redirect(303, '/target'); // on success } }; ``` ## Date Handling - **Forms**: German format `dd.mm.yyyy` with auto-dot insertion via `handleDateInput()`. A hidden `` sends ISO to the backend. - **Display**: Always use `Intl.DateTimeFormat` with `T12:00:00` suffix to prevent UTC off-by-one: ```typescript new Intl.DateTimeFormat('de-DE', { day: 'numeric', month: 'long', year: 'numeric' }).format( new Date(doc.documentDate + 'T12:00:00') ); ``` ## Styling Conventions (Tailwind CSS 4) Brand color utilities (defined in `layout.css`): | Class | Value | Usage | | ------------ | --------- | -------------------------------- | | `brand-navy` | `#002850` | Primary text, buttons, headers | | `brand-mint` | `#A6DAD8` | Accents, hover underlines, icons | | `brand-sand` | `#E4E2D7` | Page background, card borders | Typography: - `font-serif` (Merriweather) — body text, document titles, names - `font-sans` (Montserrat) — labels, metadata, UI chrome Card pattern for content sections: ```svelte

Section

``` ## Key UI Components | Component | Props | Description | | -------------------- | ---------------------------------------------------- | ------------------------------------- | | `PersonTypeahead` | `name`, `label`, `value`, `initialName`, `on:change` | Single-person selector with typeahead | | `PersonMultiSelect` | `selectedPersons` (bind) | Chip-based multi-person selector | | `TagInput` | `tags` (bind), `allowCreation?`, `on:change` | Tag chip input with typeahead | | `PdfViewer` | `url`, `annotations`, `on:annotation` | PDF rendering with annotation overlay | | `TranscriptionBlock` | `block`, `mode` | Read/edit transcription block | | `DocumentTopBar` | `document` | Responsive document metadata header | ## How to Run ### Development ```bash cd frontend npm install npm run dev # Dev server on port 5173 (or 3000 if --port 3000) ``` ### Build & Preview ```bash npm run build # Production build npm run preview # Preview production build ``` ### Code Quality ```bash npm run lint # Prettier + ESLint check npm run format # Auto-fix formatting npm run check # svelte-check (type checking) ``` ### Testing ```bash npm run test # Vitest unit + server tests (headless) npm run test:coverage # Coverage report (server project only) npm run test:e2e # Playwright E2E tests npm run test:e2e:headed # Playwright E2E with visible browser npm run test:e2e:ui # Playwright UI mode ``` ### Regenerate API Types Requires backend running with `--spring.profiles.active=dev`: ```bash npm run generate:api ``` ## Vite Proxy During development, `/api` calls are proxied to the Spring Boot backend. The proxy injects the `Authorization` header from the `auth_token` cookie automatically (see `vite.config.ts`). ## i18n (Paraglide) Translations live in `messages/{de,en,es}.json`. The compiler generates type-safe helpers in `src/lib/paraglide/`. Run compilation manually with: ```bash npx @inlang/paraglide-js compile --project ./project.inlang --outdir ./src/lib/paraglide ``` Or let the Vite plugin handle it automatically during dev/build.