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>
195 lines
8.4 KiB
Markdown
195 lines
8.4 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/
|
|
├── 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.
|