Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 3m31s
CI / OCR Service Tests (pull_request) Successful in 35s
CI / Backend Unit Tests (pull_request) Failing after 3m16s
CI / Unit & Component Tests (push) Failing after 3m23s
CI / OCR Service Tests (push) Successful in 30s
CI / Backend Unit Tests (push) Failing after 3m19s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
196 lines
8.5 KiB
Markdown
196 lines
8.5 KiB
Markdown
# 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/
|
|
│ └── demo/ # Dev-only demos
|
|
├── 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](../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
|
|
|
|
```typescript
|
|
// +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](../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, names
|
|
- `font-sans` (Montserrat) — labels, metadata, UI chrome
|
|
|
|
Card pattern for content sections:
|
|
|
|
```svelte
|
|
<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/person/README.md), [`src/lib/tag/README.md`](src/lib/tag/README.md), [`src/lib/document/README.md`](src/lib/document/README.md), [`src/lib/shared/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
|
|
|
|
```bash
|
|
cd frontend
|
|
npm install
|
|
npm run dev # Dev server on port 5173
|
|
```
|
|
|
|
### 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.
|