Removes scaffolding pages from initial Paraglide setup that were never navigated to in production. Shrinks the measured coverage surface and removes dead code from the production bundle. CLAUDE.md route tables updated to drop the demo/ entry. Refs #496. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8.4 KiB
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
│ ├── aktivitaeten/ # Unified activity feed (Chronik)
│ ├── admin/ # User, group, tag, OCR, system management
│ ├── api/ # Internal API proxies (server-side only)
│ ├── geschichten/ # Stories (list, [id], [id]/edit, new)
│ ├── stammbaum/ # Family tree
│ ├── enrich/ # Enrichment workflow ([id], done)
│ ├── hilfe/transkription/ # Transcription help page
│ ├── profile/ # User profile settings
│ ├── users/[id]/ # Public user profile page
│ ├── login/ logout/ register/
│ └── forgot-password/ reset-password/
├── lib/ # Domain-based package structure (mirrors backend)
│ ├── document/ # Document domain: components, stores, services, utils
│ │ ├── annotation/ # Annotation overlay components
│ │ ├── comment/ # Comment thread components
│ │ └── transcription/ # Transcription editor + block logic
│ ├── person/ # Person domain: chips, typeahead, avatar, format
│ │ ├── relationship/ # Relationship form + chip components
│ │ └── genealogy/ # Stammbaum (family tree) components
│ ├── tag/ # Tag domain: TagInput, TagChipList, TagParentPicker
│ ├── geschichte/ # Geschichte (story) domain: editor + card
│ ├── notification/ # Notification bell + dropdown + store
│ ├── activity/ # Activity feed (Chronik) components
│ ├── conversation/ # Bilateral conversation (Briefwechsel) components
│ ├── ocr/ # OCR progress, training cards, trigger
│ ├── user/ # User profile/password/groups section components
│ ├── shared/ # Cross-domain utilities and primitives
│ │ ├── actions/ # Svelte actions (clickOutside, etc.)
│ │ ├── hooks/ # Reusable Svelte state hooks (useTypeahead, etc.)
│ │ ├── server/ # Server-only utilities (locale, session)
│ │ ├── services/ # Client-side service helpers
│ │ ├── utils/ # Pure utility functions (date, search, etc.)
│ │ ├── primitives/ # Generic UI primitives (BackButton, ProgressRing, etc.)
│ │ ├── dashboard/ # Dashboard stat components
│ │ ├── discussion/ # CommentThread + shared discussion UI
│ │ ├── help/ # Help/FAQ page components
│ │ ├── api.server.ts # Typed API client factory
│ │ ├── errors.ts # Error code mapping (mirrors backend ErrorCode)
│ │ ├── types.ts # Shared TypeScript types
│ │ ├── relativeTime.ts # Relative time formatting
│ │ └── utils.ts # Top-level shared utilities
│ ├── generated/ # Auto-generated API types (openapi-typescript)
│ └── paraglide/ # Generated i18n code
├── hooks/ # SvelteKit hooks (handle, handleFetch)
└── ... # Other SvelteKit config files
For per-domain component inventories, see the domain READMEs in src/lib/<domain>/README.md.
API Client Pattern
→ See CONTRIBUTING.md §Frontend API client
LLM reminder: check !result.response.ok (not result.error — breaks when spec has no error responses); cast errors as result.error as unknown as { code?: string }; use result.data! after an ok check. For multipart/form-data (file uploads), bypass the typed client and use raw fetch.
Form Actions Pattern
// +page.server.ts
export const actions = {
default: async ({ request, fetch }) => {
const formData = await request.formData();
const name = formData.get('name') as string; // cast needed — FormData returns FormDataEntryValue
// ...
return fail(400, { error: 'message' }); // on error
throw redirect(303, '/target'); // on success
}
};
Date Handling
→ See CONTRIBUTING.md §Date handling
LLM reminder: always append T12:00:00 when constructing new Date() from an ISO date string — prevents UTC timezone off-by-one errors. Forms use German dd.mm.yyyy format via handleDateInput() with a hidden ISO input.
Styling Conventions (Tailwind CSS 4)
Brand color tokens (defined in layout.css):
| Token / Utility | CSS variable | Usage |
|---|---|---|
brand-navy |
--palette-navy |
Tailwind utility — buttons, headers, primary text |
brand-mint |
--palette-mint |
Tailwind utility — accents, hover underlines, icons |
--palette-sand |
--palette-sand |
Palette constant only — use bg-canvas or bg-surface |
Typography:
font-serif(Tinos) — body text, document titles, namesfont-sans(Montserrat) — labels, metadata, UI chrome
Card pattern for content sections:
<div class="rounded-sm border border-line bg-surface shadow-sm p-6">
<h2 class="text-xs font-bold uppercase tracking-widest text-ink-3 mb-5">Section</h2>
<!-- content -->
</div>
Key UI Components
→ See per-domain READMEs: src/lib/person/README.md, src/lib/tag/README.md, src/lib/document/README.md, src/lib/shared/README.md
LLM reminder: BackButton is at $lib/shared/primitives/BackButton.svelte — use it for all back navigation; never a static <a href>. API client is at $lib/shared/api.server.
How to Run
Development
cd frontend
npm install
npm run dev # Dev server on port 5173
Build & Preview
npm run build # Production build
npm run preview # Preview production build
Code Quality
npm run lint # Prettier + ESLint check
npm run format # Auto-fix formatting
npm run check # svelte-check (type checking)
Testing
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:
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:
npx @inlang/paraglide-js compile --project ./project.inlang --outdir ./src/lib/paraglide
Or let the Vite plugin handle it automatically during dev/build.