# geschichte (frontend)

UI for family stories (Geschichte) and reading journeys (Lesereise): the rich-text editor, story/journey readers, type badge, and list rows.

## What this domain owns

Components: `GeschichteEditor.svelte`, `GeschichteSidebar.svelte`, `JourneyEditor.svelte`, `JourneyItemRow.svelte`, `JourneyAddBar.svelte`, `GeschichtenCard.svelte`, `GeschichteListRow.svelte`, `StoryReader.svelte`, `JourneyReader.svelte`, `JourneyItemCard.svelte`, `JourneyInterlude.svelte`.
Utilities: `utils.ts`.

## What this domain does NOT own

- Comment/discussion UI — shared via `shared/discussion/` (same component used for document comments)
- Person display — `person/PersonChip.svelte` is used inside story content (cross-domain import)
- Document display — document references in stories use components from `document/`

## Key components

| Component                  | Used in                                      | Notes                                                                                                      |
| -------------------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `GeschichteEditor.svelte`  | `/geschichten/new`, `/geschichten/[id]/edit` | Rich-text editor (TipTap) for STORY type; delegates sidebar to `GeschichteSidebar`                         |
| `GeschichteSidebar.svelte` | `GeschichteEditor`, `JourneyEditor`          | Status badge + PersonMultiSelect sidebar; `<details>` mobile collapsibles with 44px touch targets          |
| `JourneyEditor.svelte`     | `/geschichten/[id]/edit` (JOURNEY branch)    | Curator editing surface: title, intro textarea, ordered item list with drag/reorder, add bar, save/publish |
| `JourneyItemRow.svelte`    | `JourneyEditor.svelte`                       | Item row: drag handle, move-up/down, note textarea (PATCH on blur), inline remove confirm                  |
| `JourneyAddBar.svelte`     | `JourneyEditor.svelte`                       | Two add buttons: document picker (`DocumentPickerDropdown`) and interlude draft form                       |
| `GeschichtenCard.svelte`   | Person-detail sidebar                        | Sidebar card showing the 3 most recent stories linked to a person — NOT the list page                      |
| `GeschichteListRow.svelte` | `/geschichten` (list)                        | Row component for the list; shows JOURNEY type badge (`text-xs` orange pill)                               |
| `StoryReader.svelte`       | `/geschichten/[id]` (STORY branch)           | Renders sanitised rich-text body, persons section, documents section, and author actions                   |
| `JourneyReader.svelte`     | `/geschichten/[id]` (JOURNEY branch)         | Renders intro paragraph, ordered items list, empty-state; delegates to ItemCard/Interlude                  |
| `JourneyItemCard.svelte`   | `JourneyReader.svelte`                       | Whole-card `<a>` for a document item; dated/undated aria-label, ✎ annotation glyph                         |
| `JourneyInterlude.svelte`  | `JourneyReader.svelte`                       | Typographic aside between letters; ❦ glyph, `aria-label="Kuratorennotiz"`                                  |

## utils.ts

`formatAuthorName(author)` — joins `firstName + lastName`, falls back to `email` (for list/summary shapes).
`formatAuthorDisplayName(author)` — returns `displayName` (for detail `AuthorView` shape).
`formatPublishedAt(publishedAt, style)` — wraps `formatDate` with null check; `style` is `'short'` (list) or `'long'` (detail).

## Public list is PUBLISHED-only

`GET /api/geschichten` constrains `status=PUBLISHED`, so DRAFT journeys never appear in the list.
The REISE badge is only ever seen for published journeys.
Empty-state and draft-preview paths are reachable ONLY via the **detail route** (`/geschichten/[id]`), not the list.
Wire empty-state E2E tests through the detail route, not by expecting a draft journey in the list.

## TypeSelector route component

`TypeSelector.svelte` lives in `src/routes/geschichten/new/` (single-use route UI).
It is NOT in `$lib/geschichte/` — route-specific, not reused elsewhere.
`StoryCreate.svelte` (also in `new/`) wraps `GeschichteEditor` so tree-shaking excludes TipTap from the JOURNEY placeholder path.

## Audience note

The `/geschichten` route primarily serves readers (younger family members on mobile). Cards must have ≥ 44 px touch targets. Status must not rely on color alone. JourneyReader mobile layout is Critical; TypeSelector is Minor.

## Cross-domain imports

- `person/PersonChip.svelte` — inline person references in story content
- `document/DocumentThumbnail.svelte` — inline document references
- `shared/discussion/` — comment thread below published stories

## Backend counterpart

`backend/src/main/java/org/raddatz/familienarchiv/geschichte/README.md`
