diff --git a/CLAUDE.md b/CLAUDE.md index b3a5b189..e902c469 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -192,7 +192,8 @@ frontend/src/routes/ ├── persons/ │ ├── [id]/ Person detail │ ├── [id]/edit/ Person edit form -│ └── new/ Create person form +│ ├── new/ Create person form +│ └── review/ Triage view — confirm/rename/merge/delete provisional persons ├── briefwechsel/ Bilateral conversation timeline (Briefwechsel) ├── aktivitaeten/ Unified activity feed (Chronik) ├── geschichten/ Stories — list, [id], [id]/edit, new diff --git a/docs/architecture/c4/l3-backend-3e-persons.puml b/docs/architecture/c4/l3-backend-3e-persons.puml index 47c884aa..f424168d 100644 --- a/docs/architecture/c4/l3-backend-3e-persons.puml +++ b/docs/architecture/c4/l3-backend-3e-persons.puml @@ -7,12 +7,12 @@ Container(frontend, "Web Frontend", "SvelteKit") ContainerDb(db, "PostgreSQL", "PostgreSQL 16") System_Boundary(backend, "API Backend (Spring Boot)") { - Component(personCtrl, "PersonController", "Spring MVC — /api/persons", "Lists and searches family members. Returns documents sent by or received by a person, correspondent suggestions, and person summary with document counts.") + Component(personCtrl, "PersonController", "Spring MVC — /api/persons", "Filtered, paginated directory (type/familyOnly/hasDocuments/provisional + page/size -> PersonSearchResult). Returns documents sent/received, correspondent suggestions, person summaries with counts. PATCH /{id}/confirm clears provisional; DELETE /{id} removes a person (both WRITE_ALL).") Component(relCtrl, "RelationshipController", "Spring MVC — /api/network, /api/persons/{id}/relationships", "CRUD for explicit person relationships and the full family network graph (nodes + edges) used by the Stammbaum view.") - Component(personSvc, "PersonService", "Spring Service", "Person CRUD, alias management, and merge operations (reassigns all document sender/receiver references before deleting duplicate persons).") + Component(personSvc, "PersonService", "Spring Service", "Person CRUD, alias management, filtered paged search (PersonFilter -> paired slice/count), confirm (clears provisional), delete (detaches document refs first), and merge operations (reassigns all document sender/receiver references before deleting duplicate persons).") Component(relSvc, "RelationshipService", "Spring Service", "Manages explicit directional family relationships (PARENT_OF, SPOUSE_OF, SIBLING_OF, etc.) with optional date ranges and notes.") Component(relInference, "RelationshipInferenceService", "Spring Service", "Computes transitive family relationships from explicit edges to infer grandparent/grandchild, aunt/uncle, and other extended-family links for the network graph.") - Component(personRepo, "PersonRepository", "Spring Data JPA", "Queries persons with name search (including aliases), correspondent discovery, person summaries with document counts, and merge/reassignment helpers.") + Component(personRepo, "PersonRepository", "Spring Data JPA", "Queries persons with name search (including aliases), correspondent discovery, person summaries with document counts, paired filter-aware slice + COUNT queries (one shared WHERE clause), and merge/reassignment helpers.") Component(relRepo, "PersonRelationshipRepository", "Spring Data JPA", "Reads and writes PersonRelationship records. Supports lookup by person ID, by relation type, and existence checks for deduplication.") } diff --git a/docs/architecture/c4/l3-frontend-3c-people-stories.puml b/docs/architecture/c4/l3-frontend-3c-people-stories.puml index 49526211..2ba3e454 100644 --- a/docs/architecture/c4/l3-frontend-3c-people-stories.puml +++ b/docs/architecture/c4/l3-frontend-3c-people-stories.puml @@ -7,8 +7,9 @@ Person(user, "User") Container(backend, "API Backend", "Spring Boot") System_Boundary(frontend, "Web Frontend (SvelteKit / SSR)") { - Component(personsPage, "/persons and /persons/[id]", "SvelteKit Routes", "Person directory and detail. Detail: metadata, document list sent/received, correspondents, explicit and inferred family relationships.") + Component(personsPage, "/persons and /persons/[id]", "SvelteKit Routes", "Person directory (server-side filtered + paginated) and detail. Directory: type/family/has-documents chips, reader default (familyMember OR documentCount > 0), writer-only show-all toggle. Detail: metadata, document list sent/received, correspondents, family relationships.") Component(personEdit, "/persons/[id]/edit and /persons/new", "SvelteKit Routes", "Create and edit person forms. Edit: metadata, aliases, explicit relationships. Actions: PUT/POST /api/persons.") + Component(personReview, "/persons/review", "SvelteKit Route", "Transcriber triage view (WRITE-gated link). Lists provisional persons; per-row Merge / Umbenennen / Bestätigen / Löschen. Actions: POST /merge, PUT /{id}, PATCH /{id}/confirm, DELETE /{id}.") Component(briefwechsel, "/briefwechsel", "SvelteKit Route", "Bilateral conversation timeline. Selects two persons via PersonTypeahead, fetches GET /api/documents/conversation, displays chronological exchange.") Component(aktivitaeten, "/aktivitaeten", "SvelteKit Route", "Unified activity feed (Chronik). Loader: GET /api/dashboard/activity and GET /api/notifications?read=false.") Component(geschichten, "/geschichten and /geschichten/[id]", "SvelteKit Routes", "Story list and detail pages. Loader: GET /api/geschichten?status=PUBLISHED.") @@ -19,8 +20,9 @@ System_Boundary(frontend, "Web Frontend (SvelteKit / SSR)") { } Rel(user, personsPage, "Browses family members", "HTTPS / Browser") -Rel(personsPage, backend, "GET /api/persons, GET /api/persons/{id}", "HTTP / JSON") +Rel(personsPage, backend, "GET /api/persons (filter + page params -> PersonSearchResult), GET /api/persons/{id}", "HTTP / JSON") Rel(personEdit, backend, "GET /api/persons/{id}, PUT /api/persons/{id}, POST /api/persons", "HTTP / JSON") +Rel(personReview, backend, "GET /api/persons?provisional=true, PATCH /api/persons/{id}/confirm, DELETE /api/persons/{id}, POST /api/persons/{id}/merge", "HTTP / JSON") Rel(briefwechsel, backend, "GET /api/documents/conversation", "HTTP / JSON") Rel(aktivitaeten, backend, "GET /api/dashboard/activity, GET /api/notifications", "HTTP / JSON") Rel(geschichten, backend, "GET /api/geschichten", "HTTP / JSON") diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md index 3699350f..92ae7396 100644 --- a/frontend/CLAUDE.md +++ b/frontend/CLAUDE.md @@ -28,7 +28,7 @@ src/ │ ├── +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 +│ ├── persons/ # Person directory (filtered, paginated), detail, edit, merge, review (triage) │ ├── briefwechsel/ # Bilateral conversation timeline │ ├── aktivitaeten/ # Unified activity feed (Chronik) │ ├── admin/ # User, group, tag, OCR, system management