Files
familienarchiv/docs/architecture/c4/l3-backend-3g-supporting.puml
marcel 0780c09bb4
All checks were successful
CI / Unit & Component Tests (pull_request) Successful in 3m20s
CI / OCR Service Tests (pull_request) Successful in 22s
CI / Backend Unit Tests (pull_request) Successful in 3m48s
CI / fail2ban Regex (pull_request) Successful in 45s
CI / Semgrep Security Scan (pull_request) Successful in 22s
CI / Compose Bucket Idempotency (pull_request) Successful in 1m6s
feat(geschichte): JourneyItem CRUD API — append, updateNote, delete, reorder (#751) (#788)
## Summary

Implements the backend JourneyItem CRUD API on top of the data model from #750, building towards the full Lesereisen feature (#751).

**Completed in this PR:**
- `jackson-databind-nullable` 0.2.6 + `JacksonConfig` (`@Bean Module`) for three-way PATCH semantics (`JsonNullable`)
- `AuditKind`: `JOURNEY_ITEM_ADDED`, `JOURNEY_ITEM_REMOVED`, `JOURNEY_ITEMS_REORDERED` (last is rollup-eligible)
- `ErrorCode`: `JOURNEY_ITEM_NOT_FOUND`, `JOURNEY_ITEM_POSITION_CONFLICT`
- V73 migration: `UNIQUE (geschichte_id, position) DEFERRABLE INITIALLY DEFERRED` + `CHECK (position > 0)` on `journey_items`
- `JourneyItemConstraintsTest`: verifies deferrable flag via `pg_constraint` query; position check; duplicate position rejection (3 passing tests)
- Read models: `DocumentSummary`, `JourneyItemView`, `GeschichteView` (with `AuthorView` to prevent AppUser email leak)
- `DocumentService.getSummaryById` — lean lookup without tag-color resolution
- `JourneyItemRepository`: extended with `findByGeschichteIdOrderByPosition`, `findByIdAndGeschichteId` (IDOR-safe), `findIdsByGeschichteId`, `findMaxPositionByGeschichteId`, `countByGeschichteId`
- DTOs: `JourneyItemCreateDTO`, `JourneyItemUpdateDTO` (`JsonNullable<String> note`), `JourneyReorderDTO`

**Still in progress (WIP):**
- `JourneyItemService` — `append`, `updateNote`, `delete`, `reorder`, `toSummary`, `toView` (Task 6)
- `GeschichteService.getById` → returns `GeschichteView` (Task 7)
- New endpoints on `GeschichteController` + slice tests (Task 8)
- Frontend error codes + i18n + `npm run generate:api` (Task 9)

## Commits

- `0b177247` feat(config): add jackson-databind-nullable for JsonNullable PATCH DTO support
- `408ae334` feat(audit,error): add JourneyItem AuditKind values and ErrorCodes
- `7b06c3ad` feat(migration): V73 adds UNIQUE DEFERRABLE and CHECK position > 0 on journey_items
- `160ca1c3` feat(geschichte): add DocumentSummary, JourneyItemView, GeschichteView read models
- `2ad5c36e` feat(geschichte): extend JourneyItemRepository and add item DTOs

## Test plan

- [ ] `./mvnw test -Dtest=JourneyItemConstraintsTest` — all 3 constraint tests pass
- [ ] `./mvnw clean package -DskipTests` — builds clean after remaining tasks are merged
- [ ] Frontend: `npm run generate:api` after Task 9 endpoint additions

Co-authored-by: Marcel <marcel@familienarchiv>
Reviewed-on: #788
2026-06-08 22:15:10 +02:00

4.8 KiB

Component Diagram: API Backend — Supporting DomainsComponent Diagram: API Backend — Supporting DomainsAPI Backend (Spring Boot)[system]«component»AuditService[Spring Service â€” @Async] Writes audit log entriesasynchronously via adedicated TaskExecutor,with transaction-awarelogging to preventdeadlocks on concurrentsaves.«component»AuditLogQueryService[Spring Service] Queries audit logs foractivity feeds, pulse stats,recent contributors, andper-document history.Facade overAuditLogRepository.«component»DashboardController[Spring MVC â€” /api/dashboard] REST endpoints for the userdashboard: recentdocument resume(/resume), weeklytranscription pulse stats(/pulse), and activity feed(/activity) with kind filteringand pagination.«component»StatsController[Spring MVC â€” /api/stats] Returns aggregate counts(total persons, totaldocuments) for the UI statsbar.«component»StatsService[Spring Service] Queries aggregate counts:total persons and totaldocuments.«component»DashboardService[Spring Service] Assembles the userdashboard: recentdocument resume (callsDocumentService +TranscriptionService),weekly transcription pulsestats, and activity feed withcontributor avatars.«component»NotificationController[Spring MVC â€”/api/notifications] REST and SSE endpoints fornotification stream, historywith filtering, read/unreadstate, and per-userpreference management.«component»NotificationService[Spring Service] Creates REPLY andMENTION notifications,optionally sends email,marks as read, and pushesevents to connected clientsvia SseEmitterRegistry.«component»SseEmitterRegistry[Spring Component] In-memoryConcurrentHashMap ofSpring SseEmitter instancesper user. Handlesregistration, deregistration,and JSON event broadcasts.«component»GeschichteController[Spring MVC â€”/api/geschichten] CRUD for publishablestories (STORY) and readingjourneys (JOURNEY).ReturnsGeschichteSummaryprojections for list; fullGeschichte withJourneyItems for detail.Requires BLOG_WRITEpermission for writeoperations.«component»GeschichteService[Spring Service] Manages story lifecycle(DRAFT â†’ PUBLISHED withtimestamp). Supports twosubtypes: STORY (prose)and JOURNEY (orderedJourneyItem sequence).Sanitizes HTML body withan allowlist policy.«component»GeschichteQueryService[Spring Service] Read-only facade overGeschichteRepository.Exposes existsById() andfindById() to preventJourneyItemService fromcrossing domainboundaries.«component»JourneyItemService[Spring Service] Manages journey itemlifecycle: append (100-itemcap), updateNote(three-way PATCH), delete,and reorder (DEFERRABLEposition swap). EnforcesJOURNEY-type guard onappend.«component»GlobalExceptionHandler[Spring @RestControllerAdvice] Converts DomainException,validation errors, andgeneric exceptions toErrorResponse JSON withmachine-readableErrorCode and HTTP status.«container»Web Frontend[SvelteKit]«container»PostgreSQL[PostgreSQL 16]«component»DocumentService[Spring Service] See diagram 3b. Called byDashboardService to fetchdocument titles and resumedata.«component»TranscriptionService[Spring Service] See diagram 3c. Called byDashboardService to fetchtranscription block progressfor resume.Dashboard requests[HTTP / JSON]GET /api/stats[HTTP / JSON]Notification streamand history[HTTP / JSON / SSE]Story requests[HTTP / JSON]Delegates toDelegates toReads aggregatecounts[JDBC]Fetches activity feedand pulse statsFetches documenttitles and resumedataFetches transcriptionblock progress forresumeDelegates toRegisters client SSEconnectionBroadcasts events toconnected clientsDelegates toDelegates journeyitem CRUDChecks Geschichteexistence and typeReads geschichten[JDBC]Reads / writesjourney_items[JDBC]Writes audit_log[JDBC]Reads audit_log[JDBC]Reads / writesnotifications[JDBC]Reads / writesgeschichten[JDBC]