From ae47af52b9d5f65cc7202172d53ee46e6474c6c6 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 29 Mar 2026 16:55:24 +0200 Subject: [PATCH] docs: add persons section Concept A spec (Enriched Directory) Wireframe spec for the Persons section redesign (issue #157): - Enriched person cards with alias, life dates, document count - 2-column detail layout (person info sidebar + activity area) - Dedicated /persons/[id]/edit route with sticky save bar - Danger Zone accordion for merge (collapsed by default) - All fields on new person form (birth year, death year, notes) - Full coverage: list, detail, edit, new, edge cases, implementation notes Co-Authored-By: Claude Sonnet 4.6 --- .../persons-concept-a-enriched-directory.html | 1645 +++++++++++++++++ 1 file changed, 1645 insertions(+) create mode 100644 docs/specs/persons-concept-a-enriched-directory.html diff --git a/docs/specs/persons-concept-a-enriched-directory.html b/docs/specs/persons-concept-a-enriched-directory.html new file mode 100644 index 00000000..0b4bb411 --- /dev/null +++ b/docs/specs/persons-concept-a-enriched-directory.html @@ -0,0 +1,1645 @@ + + + + + +Persons Section — Concept A Specification · Familienarchiv + + + +
+ + +
+

Persons Section — Concept A: Enriched Directory

+

Complete developer-ready screen spec for the Persons section redesign. Covers the person list, detail view (2-column layout), edit form (dedicated route), new person form, and all edge cases. Every screen, state, and entity is specified. A developer should be able to implement the full feature from this spec alone.

+
Familienarchiv · Persons Spec · Concept A · v1.0 · 2026-03
+
+ + +
+
+
0
+
+ Architecture +
Routes, Layout Model & Breakpoints
+
Four routes. 2-column detail layout on desktop. Dedicated edit route with sticky save bar. Merge panel hidden in Danger Zone accordion.
+
+
+ +
+
+
Route map
+
+ + + + + + + + +
RoutePurposeKey state
/personsPerson directory — 4-column grid, search, stats barsearch query param
/persons/newCreate new person — all 6 fieldsform validation
/persons/[id]Person detail — 2-col layout, activity areaperson id in path
/persons/[id]/editEdit form — sticky save bar, Danger Zone accordiondirty state, merge
+
+
+
+
Breakpoint behaviour
+
+ + + + + + + +
ViewportList layoutDetail layoutEdit layout
<640px Mobile1-col listStacked single colFull-page form
640–1023px Tablet2-col gridStacked single colFull-page form
≥1024px Desktop4-col grid2-col sidebar+mainFull-page form
+
+
+
+ + +
+
+
2-column detail layout anatomy ≥1024px
+
+
+ +
+ +
+ +
+
PERSON CARD · 35%
+
+
+
+
OF
+
Otto Fischer
+
„Großvater Otto"
+
✦ 1882  †  1944
+
+
Notes
+
Patriarchal figure of the Fischer family…
+
+
Edit person
+
+
+
+ +
+
ACTIVITY AREA · 65%
+
+
+
Frequent Correspondents
+
+
HM
Hans Müller ×4
+
AS
Anna Schmidt ×2
+
+
+
+
Sent Documents
5
+
Brief an den König
12 Nov 1938
Uploaded
+
Grundbucheintrag Hof Fischer
3 Mar 1922
Archived
+
Show 3 more…
+
+
+
Received Documents
3
+
Scan ohne Titel
25 Nov 1938
Scan pending
+
+
+
+
+
+
+
+
+ +
+
📐 Key design decisions
+
    +
  • Edit moved to /persons/[id]/edit — removes in-place toggle; PersonCard is view-only; edit state no longer lives in $state on the detail page.
  • +
  • Merge panel moved inside a collapsible Danger Zone accordion at the bottom of the edit page — reduces cognitive load on the detail view.
  • +
  • "Full Name" label removed from view mode — the <h1> / PC-name already shows the name; duplicate removed per audit finding.
  • +
  • Stats bar on list page: persons.length + totalDocs — requires documentCount field on PersonDTO (or computed client-side from separate query).
  • +
  • New person form gains birth year, death year, notes — brings parity with edit form.
  • +
+
+
+ + +
+
+
1
+
+ List +
Person Directory /persons
+
4-column card grid on desktop. Stats bar. Search. Each card shows initials circle, full name, alias, life dates, doc count chip. Hover: mint left-border + shadow.
+
+
+ + +
+
+
1-A · Desktop full list 1440px default
+
/persons
+
+
+ +
+ +
+
+
Persons
+
+
4
Persons
+
·
+
14
Documents
+
+
+
+
🔍 Search persons…
+
+ New person
+
+
+ +
+ +
+
OF
+
Otto Fischer
+
„Großvater Otto"
+
✦ 1882 · † 1944
+
8 docs
+
+ +
+
HM
+
Hans Müller
+
✦ 1890 · † 1962
+
2 docs
+
+ +
+
AS
+
Anna Schmidt
+
„Oma Anna"
+
✦ 1905
+
8 docs
+
+ +
+
MW
+
Maria Weber
+
no dates
+
1 doc
+
+
+
+
+
Card 1 shown in hover state (mint left border + shadow). No alias shown for Hans Müller and Maria Weber — those fields are simply omitted when empty. "no dates" placeholder shown in muted italic when both fields absent.
+
+
+ + +
+
+
1-B · Tablet 768px
+
/persons
+
+
+ +
+
+
+
Persons
+
+
4
Persons
+
·
+
14
Docs
+
+
+
+ New
+
+
🔍 Search persons…
+
+
+
OF
+
Otto Fischer
+
„Großvater Otto"
+
✦ 1882 · † 1944
+
8 docs
+
+
+
HM
+
Hans Müller
+
✦ 1890 · † 1962
+
2 docs
+
+
+
AS
+
Anna Schmidt
+
„Oma Anna"
+
✦ 1905
+
8 docs
+
+
+
MW
+
Maria Weber
+
no dates
+
1 doc
+
+
+
+
+
+
+
1-C · Mobile 375px
+
/persons
+
+
+ +
+
+
+
Persons
+
4 persons · 14 docs
+
+
+ New
+
+
🔍 Search…
+ +
+
+
OF
+
+
Otto Fischer
+
„Großvater Otto"
+
+
✦ 1882 · † 1944
+
8 docs
+
+
+
+
+
+
HM
+
+
Hans Müller
+
+
✦ 1890 · † 1962
+
2 docs
+
+
+
+
+
+
AS
+
+
Anna Schmidt
+
„Oma Anna"
+
+
✦ 1905
+
8 docs
+
+
+
+
+
+
MW
+
+
Maria Weber
+
+
1 doc
+
+
+
+
+
+
+
+
Mobile: cards switch to horizontal row layout (initials left, text right, chevron right). Touch-friendly min-height. No centered text.
+
+
+ + +
+
+
1-D · Empty state desktop empty
+
/persons
+
+
+ +
+
+
+
Persons
+
0 persons · 0 documents
+
+
+ New person
+
+
+
👤
+
No persons yet
+
Add the first family member to begin building the archive's person directory.
+
Add the first family member
+
+
+
+
+
+
1-E · Search results desktop filtered
+
/persons?q=Fischer
+
+
+ +
+
+
+
Persons
+
+
+
🔍 Fischer
+
+ New person
+
+
+
1 result for "Fischer" Clear ×
+
+
+
OF
+
Otto Fischer
+
„Großvater Otto"
+
✦ 1882 · † 1944
+
8 docs
+
+
+
+
+
Search filters by first name, last name, or alias. Result count shown below header. "Clear ×" resets query param. Search box has focus ring when active.
+
+
+
+ + +
+
+
2
+
+ Detail +
Person Detail /persons/[id]
+
2-column layout on desktop. Left sidebar: Person Card (35%). Right: Activity Area — Frequent Correspondents, Sent Documents, Received Documents (65%). Stacked on tablet/mobile.
+
+
+ + +
+
+
2-A · Desktop detail — Otto Fischer 1440px view
+
/persons/a1b2c3d4
+
+
+ +
+ + +
+ +
+
+
+
+
OF
+
Otto Fischer
+
„Großvater Otto"
+
✦ 1882  ·  † 1944
+
+
Notes
+
Patriarchal figure of the Fischer family. Farmer from Baden-Württemberg. Married to Helene Fischer (née Braun).
+
✏ Edit person
+
+
+
+ +
+ +
+
+
Frequent Correspondents
+
(click to view conversation)
+
+
+
+
HM
+ Hans Müller + ×4 + 💬 +
+
+
AS
+ Anna Schmidt + ×2 + 💬 +
+
+
+ +
+
+
Sent Documents
+
+
5
+
Date ▾
+
+
+
+
+
+
Brief an den König
+
Berlin · 12 Nov 1938
+
+
Uploaded
+
+
+
+
+
Grundbucheintrag Hof Fischer
+
Freiburg · 3 Mar 1922
+
+
Archived
+
+
+
+
+
Pachtvertrag Südfeld
+
Karlsruhe · 14 Jul 1910
+
+
Archived
+
+
Show 2 more…
+
+ +
+
+
Received Documents
+
+
3
+
Date ▾
+
+
+
+
+
+
Scan ohne Titel
+
Hamburg · 25 Nov 1938
+
+
Scan pending
+
+
+
+
+
Scan ohne Titel
+
Hamburg · 25 Nov 1938
+
+
Scan pending
+
+
+
+
+
Scan ohne Titel
+
Hamburg · 25 Nov 1938
+
+
Scan pending
+
+
+
+
+
+
+
Left sidebar has 2px navy top accent bar. Avatar 80px. No "Full Name" label — name shown directly as PC-name h1. Notes section only rendered when notes field is non-empty. Edit button navigates to /persons/[id]/edit.
+
+
+ + +
+
+
2-B · Tablet stacked 768px
+
/persons/a1b2c3d4
+
+
+ +
+ + +
+
+
+
OF
+
+
Otto Fischer
+
„Großvater Otto"
+
✦ 1882 · † 1944
+
+
✏ Edit
+
+
+ +
+
Frequent Correspondents
+
+
HM
Hans Müller ×4
+
AS
Anna Schmidt ×2
+
+
+
+
Sent Documents
5
+
Brief an den König
Uploaded
+
Grundbucheintrag Hof Fischer
Archived
+
Show 3 more…
+
+
+
Received Documents
3
+
Scan ohne Titel
Scan pending
+
Scan ohne Titel
Scan pending
+
+
+
+
+
+
2-C · Mobile 375px
+
/persons/a1b2c3d4
+
+
+ +
+ +
+
+
+
OF
+
Otto Fischer
+
„Großvater Otto"
+
✦ 1882 · † 1944
+
✏ Edit person
+
+
+
+
Correspondents
+
+
HM
Hans M. ×4
+
AS
Anna S. ×2
+
+
+
+
Sent
5
+
Brief an den König
+
Grundbucheintrag…
+
Show 3 more…
+
+
+
Received
3
+
Scan ohne Titel ×3
+
+
+
+
+
+ + +
+
+
2-D · Minimal data person — Hans Müller desktop no alias · no notes · no death year
+
/persons/b2c3d4e5
+
+
+ +
+ +
+
+
+
+
+
HM
+
Hans Müller
+ +
✦ 1890
+ +
+
No notes added
+
+
✏ Edit person
+
+
+
+
+ +
+
Sent Documents
1
+
+
+
Brief an den König
Berlin · 12 Nov 1938
+
Uploaded
+
+
+
+
Received Documents
1
+
+
+
Scan ohne Titel
Hamburg · 25 Nov 1938
+
Scan pending
+
+
+
+
+
+
+
Optional sections (alias, notes, Frequent Correspondents) collapse gracefully when empty. Death year omitted — only birth year shown. "No notes added" placeholder in muted italic; entire Notes card section still renders but with placeholder text. Correspondents section not shown when no co-correspondents exist.
+
+
+
+ + +
+
+
3
+
+ Edit +
Edit Person /persons/[id]/edit
+
Dedicated route. Full-bleed sticky save bar at bottom. 2-column field grid. Danger Zone accordion at the very bottom. Merge panel lives here, not on detail view.
+
+
+ + +
+
+
3-A · Desktop edit form 1440px edit
+
/persons/a1b2c3d4/edit
+
+
+ +
+
+ +
Edit person: Otto Fischer
+
+
Personal Details
+ +
+
+
First name *
+
Otto
+
+
+
Last name *
+
Fischer
+
+
+ +
+
Nickname / Alias (optional)
+
Großvater Otto
+
+ +
+
+
Birth year (optional)
+
1882
+
+
+
Death year (optional)
+
1944
+
+
+ +
+
Notes (optional)
+
Patriarchal figure of the Fischer family. Farmer from Baden-Württemberg. Married to Helene Fischer (née Braun).
+
+
+ +
+
+
⚠ Danger Zone Destructive actions
+
+
+ +
+
+ Merge with another person… + +
+
+
+
+ +
+
Discard changes
+
Save changes
+
+
+
+
Back link says "← Back to Otto Fischer" — links to /persons/[id]. Page heading uses person full name. Danger Zone accordion collapsed by default; only the "Merge with another person…" affordance is visible. Sticky save bar uses full-bleed pattern from CLAUDE.md.
+
+
+ + +
+
+
3-B · Validation error desktop error
+
/persons/a1b2c3d4/edit
+
+
+ +
+
+ +
Edit person: Otto Fischer
+
+
Personal Details
+
+
+
First name *
+
+
First name is required
+
+
+
Last name *
+
Fischer
+
+
+
+
Nickname / Alias
+
Großvater Otto
+
+
+
+
Birth year
+
1882
+
+
+
Death year
+
1944
+
+
+
+
+
+
Discard changes
+
Save changes
+
+
+
+
Errors shown on submit — not live. Affected field gets red border + error message below. Save button remains enabled (not disabled). Multiple fields can show errors simultaneously.
+
+ + +
+
3-C · Danger Zone expanded — Merge panel desktop
+
/persons/a1b2c3d4/edit
+
+
+ +
+
+ +
Edit person: Otto Fischer
+ +
+
Personal Details
+
+
First name *
Otto
+
Last name *
Fischer
+
+
… more fields above …
+
+ +
+
+
⚠ Danger Zone Destructive actions
+
+
+
+
Merge with another person
+
Select a target person. All documents and links from Otto Fischer will be transferred to the target, and this person will be permanently deleted. This action cannot be undone.
+
+
Search for person to merge into…
+
Search persons…
+
+
+
Merge Otto Fischer →
+
Cancel
+
+
⚠ This action cannot be undone. All documents linked to Otto Fischer will be reassigned.
+
+
+
+
+
Discard changes
+
Save changes
+
+
+
+
Danger Zone expanded by clicking the header row (Svelte $state boolean toggle). Merge typeahead uses PersonTypeahead component. Red "Merge" button disabled until a target person is selected. Warning banner always visible inside expanded panel.
+
+
+ + +
+
+
3-D · Mobile edit 375px edit
+
/persons/a1b2c3d4/edit
+
+
+ +
+
+ +
Edit: Otto Fischer
+
+
Personal Details
+ +
+
First name *
+
Otto
+
+
+
Last name *
+
Fischer
+
+
+
Nickname / Alias
+
Großvater Otto
+
+
+
Birth year
+
1882
+
+
+
Death year
+
1944
+
+
+
Notes
+
Patriarchal figure of the Fischer family…
+
+
+ +
+
+
⚠ Danger Zone
+
+
+
+
+
+
Discard
+
Save changes
+
+
+
+
Mobile: 2-column field grid collapses to 1-column. All fields stack vertically. Sticky save bar remains full-bleed. Danger Zone always at very bottom, collapsed by default.
+
+
+
+ + +
+
+
4
+
+ New +
New Person /persons/new
+
Centered max-w-2xl form. All 6 fields (fixes the 3-field inconsistency). Card-style save bar (not sticky). "Create person" green primary button.
+
+
+ +
+ +
+
4-A · Desktop new person 1440px new
+
/persons/new
+
+
+ +
+ +
New person
+ +
+
+
Person details
+
+
+
First name *
+
+
+
+
Last name *
+
+
+
+
+
Nickname / Alias (optional)
+
+
+
+
+
Birth year (optional)
+
+
+
+
Death year (optional)
+
+
+
+
+
Notes (optional)
+
+
+
+ +
+
Cancel
+
Create person
+
+
+
+
+
Save bar uses card-style (not sticky full-bleed) — form is short enough to always be visible. "Cancel" navigates back to /persons. "Create person" green primary. All empty fields shown — no pre-fill.
+
+ + +
+
4-B · Mobile new person 375px new
+
/persons/new
+
+
+ +
+ +
New person
+
+
Person details
+
+
First name *
+
+
+
+
Last name *
+
+
+
+
Nickname / Alias
+
+
+
+
Birth year
+
+
+
+
Death year
+
+
+
+
Notes
+
+
+
+
+
Cancel
+
Create person
+
+
+
+
Mobile: all fields in single column. Save bar card-style (not sticky). Same 6 fields as desktop.
+
+
+
+ + +
+
+
5
+
+ Edge Cases +
Edge Cases & Error States
+
Person with no documents. Unsaved changes guard. Save API error.
+
+
+ + +
+
+
5-A · Person with no documents — Maria Weber desktop no documents
+
/persons/d4e5f6g7
+
+
+ +
+ +
+
+
+
+
+
MW
+
Maria Weber
+
No alias · No dates
+
✏ Edit person
+
+
+
+
+ + +
+
+
Sent Documents
+
0
+
+
+
📄
+
No sent documents yet
+
+
+ +
+
+
Received Documents
+
0
+
+
+
📄
+
No received documents yet
+
+
+
+
+
+
+
When both sent and received document counts are 0, empty-state dashed boxes are shown. Correspondent section is entirely absent (not rendered). Count badge shows 0 in grey, not navy.
+
+
+ + +
+
+
5-B · Unsaved changes guard edit page dirty form
+
/persons/a1b2c3d4/edit
+
+
+ +
+
+ + +
+
⚠ You have unsaved changes. Save or discard before leaving.
+
+
Save
+
Discard
+
+
+
Edit person: Otto Fischer
+
+
Personal Details
+
+
+
First name *
+
Ott 
+
+
+
Last name *
+
Fischer
+
+
+
Form is dirty — first name partially edited
+
+
+
+
Discard changes
+
Save changes
+
+
+
+
Banner triggers when user clicks the back link or uses browser navigation while form isDirty (track with Svelte $derived). [Save] in banner = same action as save bar. [Discard] resets form and navigates away. SvelteKit beforeNavigate() hook handles browser back/forward.
+
+ +
+
5-C · Save error — API failure edit page error
+
/persons/a1b2c3d4/edit
+
+
+ +
+
+ + +
+
✕ Save failed — First name is required.
+
+
Edit person: Otto Fischer
+
+
Personal Details
+
+
+
First name *
+
+
First name is required
+
+
+
Last name *
+
Fischer
+
+
+
+
+
Birth year
+
1882
+
+
+
Death year
+
1944
+
+
+
+
+
+
Discard changes
+
Save changes
+
+
+
+
API error shown in red banner below the back link. Specific field also highlighted with inline error. Error message uses backend ErrorCode translation via getErrorMessage(). Page stays on edit route — user can correct and retry.
+
+
+
+ + +
+
+
6
+
+ Implementation +
Implementation Notes
+
Numbered rules covering every required code change. Follow these in order to implement the full Concept A redesign.
+
+
+ +
+
Implementation rules — Concept A: Enriched Directory
+
+
+
+
Rule 1 — Route change
+
Add /persons/[id]/edit as a new SvelteKit route (+page.svelte + +page.server.ts). Move the update form action from /persons/[id]/+page.server.ts to the edit route's server file. PersonCard.svelte edit-mode $state can be removed — the card is now view-only. The [Edit person] button navigates to /persons/{id}/edit.
+
+
+
Rule 2 — New person form fields
+
Add birthYear, deathYear, and notes fields to /persons/new/+page.svelte and the corresponding create server action. These fields are already on the PersonDTO and the backend PersonService; only the frontend form was missing them. Use parseInt(formData.get('birthYear')) — handle empty string as undefined.
+
+
+
Rule 3 — Card enrichment on list page
+
The list +page.server.ts already returns persons[]. No backend change needed — alias, birthYear, deathYear are already on the PersonDTO. Update the card template in +page.svelte to render these fields. Render alias only {#if person.alias}. Life dates: ✦ {birthYear} and † {deathYear} joined with · ; omit when null.
+
+
+
Rule 4 — Stats bar
+
Compute persons.length (person count) and totalDocs = persons.reduce((acc, p) => acc + (p.documentCount ?? 0), 0) (total documents). This requires backend to return documentCount: number on PersonDTO — add this field to the Java Person entity response (computed via @Formula or a JPQL query in PersonService.findAll()). Mark it @Schema(requiredMode = REQUIRED) and run npm run generate:api.
+
+
+
Rule 5 — 2-column detail layout
+
Replace the current vertical stack in /persons/[id]/+page.svelte with a CSS grid: class="grid md:grid-cols-[35fr_65fr] gap-5 items-start". Left child = PersonCard. Right child = Activity wrapper containing the three ACT sections. On mobile/tablet (<md:) the grid collapses to single column (PersonCard above, Activity below).
+
+
+
Rule 6 — Merge panel relocation
+
PersonMergePanel.svelte must be moved from /persons/[id]/+page.svelte to /persons/[id]/edit/+page.svelte. Wrap it in a collapsible accordion: let dangerOpen = $state(false); the accordion header toggles dangerOpen; the body uses a CSS transition on max-height or a simple {#if dangerOpen} block.
+
+
+
+
+
Rule 7 — "Full Name" duplication fix
+
Remove the <div class="FL">Full Name</div> label and associated value row from PersonCard.svelte view mode. The <h1> (PC-name class) already displays the full name. This was flagged in the audit as a direct duplication.
+
+
+
Rule 8 — Sticky save bar
+
The edit route uses the full-bleed sticky pattern from CLAUDE.md: class="sticky bottom-0 z-10 -mx-4 px-6 py-4 bg-white border-t border-brand-sand shadow-[0_-2px_8px_rgba(0,0,0,0.06)] flex items-center justify-between". The new person form uses the card-style save bar (not sticky): class="mt-4 flex items-center justify-between rounded-sm border border-brand-sand bg-white px-6 py-4 shadow-sm".
+
+
+
Rule 9 — Co-correspondents tooltip
+
Add title="Click to view conversation" to each correspondent chip element. Optionally add a small 💬 chat icon inside the chip (Unicode or a 12px SVG). The chip's href should navigate to /conversations?person1={currentId}&person2={corrId}. This clarifies the navigation target which was previously ambiguous.
+
+
+
Rule 10 — Document status labels
+
Map raw status enums to human-readable i18n labels using the existing Paraglide system: PLACEHOLDER → m.status_scan_pending(), UPLOADED → m.status_uploaded(), TRANSCRIBED → m.status_transcribed(), REVIEWED → m.status_reviewed(), ARCHIVED → m.status_archived(). Add keys to messages/de.json, en.json, es.json. Add DOCUMENT_STATUS_INVALID to ErrorCode.java and errors.ts for unknown values.
+
+
+
Rule 11 — Unsaved changes guard
+
In /persons/[id]/edit/+page.svelte, track a isDirty = $derived(...) boolean by comparing current field values to the loaded person. Use SvelteKit's beforeNavigate(({ cancel }) => { if (isDirty) cancel() }) to block browser navigation. Show the inline warning banner (yellow, above the form) when isDirty and user attempts to leave. The banner [Save] button submits the form; [Discard] resets fields and calls invalidate().
+
+
+
Rule 12 — Mobile card layout
+
On mobile (<640px) the person grid cards switch from centered column layout to horizontal row layout: initials circle on the left (36×36px), text block in the middle (name + alias + dates + doc count), chevron on the right. Use sm:flex-col sm:items-center vs base flex-row items-center in Tailwind. This improves scannability on narrow screens.
+
+
+
+
+ + +
+
📋 Document status label map (Rule 10)
+
    +
  • PLACEHOLDER → "Scan pending" — Scan pending (amber chip)
  • +
  • UPLOADED → "Uploaded" — Uploaded (navy chip)
  • +
  • TRANSCRIBED → "Transcribed" — Transcribed (blue chip)
  • +
  • REVIEWED → "Reviewed" — Reviewed (mint chip)
  • +
  • ARCHIVED → "Archived" — Archived (green chip)
  • +
+
+ + +
+
Files to create / modify
+ + + + + + + + + + + + + + + + +
FileActionRelated rule(s)
frontend/src/routes/persons/+page.svelteAdd alias, dates, doc count to card template; add stats bar; switch to 4-col grid; mobile row layout3, 4, 12
frontend/src/routes/persons/new/+page.svelteAdd birth year, death year, notes fields2
frontend/src/routes/persons/new/+page.server.tsHandle new fields in create action2
frontend/src/routes/persons/[id]/+page.svelte2-col grid layout; view-only PersonCard; remove edit toggle state; remove merge panel1, 5, 6, 7
frontend/src/routes/persons/[id]/+page.server.tsRemove update action (moved to edit route)1
frontend/src/routes/persons/[id]/edit/+page.svelteCREATE: edit form, sticky save bar, danger zone accordion, unsaved guard1, 6, 8, 11
frontend/src/routes/persons/[id]/edit/+page.server.tsCREATE: load person, update action1
frontend/src/lib/components/PersonCard.svelteRemove edit mode toggle; remove "Full Name" label row; make view-only1, 7
frontend/src/lib/components/PersonMergePanel.svelteMove to edit route; add tooltip to chips6, 9
backend/src/main/java/…/model/Person.javaAdd documentCount computed field or handle in service4
frontend/src/lib/errors.tsAdd DOCUMENT_STATUS_INVALID error code10
frontend/src/lib/messages/de.json + en.json + es.jsonAdd status label keys10
+
+
+ +
+ +