docs(c4): accuracy audit — split L3 diagrams, add 6 new sub-diagrams, fix all stale content #448
@@ -1,6 +1,8 @@
|
||||
# Familienarchiv — C4 Architecture Diagrams
|
||||
|
||||
> For domain terminology used in these diagrams, see [docs/GLOSSARY.md](../GLOSSARY.md).
|
||||
>
|
||||
> **Cross-diagram stubs:** Components placed outside a `System_Boundary` block with a "See diagram X" annotation are reference stubs — they represent a component fully defined in another sub-diagram and appear here only to show the cross-domain dependency without duplicating the full definition.
|
||||
|
||||
## Level 1 — System Context
|
||||
|
||||
@@ -10,13 +12,15 @@ Who uses the system and what external systems does it interact with.
|
||||
C4Context
|
||||
title System Context: Familienarchiv
|
||||
|
||||
Person(admin, "Administrator", "Manages users, triggers bulk imports, reviews documents")
|
||||
Person(member, "Family Member", "Searches, browses, and reads archived documents")
|
||||
Person(admin, "Administrator", "Manages users, triggers bulk imports, reviews and transcribes documents")
|
||||
Person(member, "Family Member", "Access by administrator invite. Searches, browses, reads, and transcribes archived documents.")
|
||||
|
||||
System(familienarchiv, "Familienarchiv", "Web application for digitising, organising, and searching family documents")
|
||||
System_Ext(mail, "Email Service", "SMTP server. Delivers notification emails (mentions, replies) and password-reset links.")
|
||||
|
||||
Rel(admin, familienarchiv, "Manages via browser", "HTTPS")
|
||||
Rel(member, familienarchiv, "Searches and views via browser", "HTTPS")
|
||||
Rel(member, familienarchiv, "Searches, reads, and transcribes via browser", "HTTPS")
|
||||
Rel(familienarchiv, mail, "Sends notification and password-reset emails (optional)", "SMTP")
|
||||
```
|
||||
|
||||
---
|
||||
@@ -30,9 +34,10 @@ C4Container
|
||||
title Container Diagram: Familienarchiv
|
||||
|
||||
Person(user, "User", "Admin or family member")
|
||||
System_Ext(mail, "Email Service", "SMTP server. Delivers notification and password-reset emails.")
|
||||
|
||||
System_Boundary(archiv, "Familienarchiv (Docker Compose)") {
|
||||
Container(frontend, "Web Frontend", "SvelteKit / Node.js", "Server-side rendered UI. Handles session cookies, search UI, document viewer, and admin panel.")
|
||||
Container(frontend, "Web Frontend", "SvelteKit / Node.js", "Server-side rendered UI. Handles auth session cookies, document search and viewer, transcription editor, annotation layer, family tree (Stammbaum), stories (Geschichten), activity feed (Chronik), enrichment workflow, and admin panel.")
|
||||
|
||||
Container(backend, "API Backend", "Spring Boot 4 / Java 21 / Jetty", "REST API. Implements document management, search, user auth, file upload/download, transcription, OCR orchestration, and SSE notifications.")
|
||||
|
||||
@@ -51,6 +56,7 @@ C4Container
|
||||
Rel(backend, db, "Reads and writes metadata and sessions", "JDBC / SQL")
|
||||
Rel(backend, storage, "Uploads and streams document files", "HTTP / S3 API (AWS SDK v2)")
|
||||
Rel(backend, ocr, "OCR job requests with presigned MinIO URL", "HTTP / REST / JSON")
|
||||
Rel(backend, mail, "Sends notification and password-reset emails (optional)", "SMTP")
|
||||
Rel(ocr, storage, "Fetches PDF via presigned URL", "HTTP / S3 presigned")
|
||||
Rel(mc, storage, "Creates bucket on startup", "MinIO Client CLI")
|
||||
```
|
||||
@@ -59,149 +65,444 @@ C4Container
|
||||
|
||||
## Level 3 — Components: API Backend
|
||||
|
||||
The internal structure of the Spring Boot backend.
|
||||
The internal structure of the Spring Boot backend, split into seven focused sub-diagrams.
|
||||
|
||||
### 3a — Security & Authentication
|
||||
|
||||
How requests are authenticated and write operations are authorised.
|
||||
|
||||
```mermaid
|
||||
C4Component
|
||||
title Component Diagram: API Backend
|
||||
title Component Diagram: API Backend — Security & Authentication
|
||||
|
||||
Container(frontend, "Web Frontend", "SvelteKit")
|
||||
ContainerDb(db, "PostgreSQL")
|
||||
|
||||
System_Boundary(backend, "API Backend (Spring Boot)") {
|
||||
Component(secFilter, "Security Filter Chain", "Spring Security", "Enforces authentication on all requests. Parses Basic Auth header and constructs an Authentication token; delegates credential validation to DaoAuthenticationProvider via BCrypt. Permits password-reset, invite, and register endpoints without authentication.")
|
||||
Component(permAspect, "PermissionAspect", "Spring AOP", "Intercepts methods annotated with @RequirePermission. Checks user's granted authorities against the required permission. Throws 401/403 if denied.")
|
||||
Component(secConf, "SecurityConfig", "Spring @Configuration", "Configures filter chain: all routes require authentication, CSRF disabled, BCrypt password encoder, DaoAuthenticationProvider with CustomUserDetailsService.")
|
||||
Component(userDetails, "CustomUserDetailsService", "Spring Security UserDetailsService", "Loads AppUser by email from DB. Converts group permissions to Spring GrantedAuthority objects. Logs unknown permissions.")
|
||||
}
|
||||
|
||||
Rel(frontend, secFilter, "All requests", "HTTP / Basic Auth header")
|
||||
Rel(secFilter, permAspect, "Authenticated requests reach guarded service methods", "")
|
||||
Rel(secConf, userDetails, "Wires as UserDetailsService", "")
|
||||
Rel(userDetails, db, "Loads user by email", "JDBC")
|
||||
```
|
||||
|
||||
### 3b — Document Management & Import
|
||||
|
||||
Document management, file storage, and bulk Excel/ODS import.
|
||||
|
||||
```mermaid
|
||||
C4Component
|
||||
title Component Diagram: API Backend — Document Management & Import
|
||||
|
||||
Container(frontend, "Web Frontend", "SvelteKit")
|
||||
ContainerDb(db, "PostgreSQL")
|
||||
ContainerDb(minio, "MinIO")
|
||||
|
||||
System_Boundary(backend, "API Backend (Spring Boot)") {
|
||||
Component(docCtrl, "DocumentController", "Spring MVC — /api/documents", "CRUD for documents: search, get by ID, update metadata, upload/download file, conversation thread, and batch metadata updates.")
|
||||
Component(adminCtrl, "AdminController", "Spring MVC — /api/admin", "Triggers asynchronous Excel/ODS mass import (requires ADMIN permission). Reports import state (IDLE/RUNNING/DONE/FAILED).")
|
||||
|
||||
Component(secFilter, "Security Filter Chain", "Spring Security", "Enforces authentication on all requests. Parses Basic Auth header and validates credentials via BCrypt.")
|
||||
Component(permAspect, "PermissionAspect", "Spring AOP", "Intercepts methods annotated with @RequirePermission. Checks user's granted authorities against the required permission. Throws 401/403 if denied.")
|
||||
Component(docSvc, "DocumentService", "Spring Service", "Core document business logic: store, update, search. Resolves persons and tags, delegates file I/O to FileService, builds dynamic JPA Specifications, and integrates with audit logging.")
|
||||
Component(fileSvc, "FileService", "Spring Service", "Wraps AWS SDK v2 S3Client. Uploads files with UUID-keyed paths, computes SHA-256 hash, downloads with content-type detection, and generates presigned URLs for OCR access.")
|
||||
Component(massImport, "MassImportService", "Spring Service — @Async", "Reads Excel/ODS files from /import mount. Tracks import state (IDLE/RUNNING/DONE/FAILED) and delegates to ExcelService. Returns immediately; processing runs asynchronously.")
|
||||
Component(excelSvc, "ExcelService", "Spring Service", "Parses Excel/ODS workbooks (Apache POI). Column indices configurable via application.properties. Creates/updates document records per row.")
|
||||
Component(minioConf, "MinioConfig", "Spring @Configuration", "Creates the S3Client and S3Presigner beans with path-style access for MinIO. Validates MinIO connectivity on startup.")
|
||||
|
||||
Component(docCtrl, "DocumentController", "Spring MVC — /api/documents", "CRUD for documents. Endpoints: search, get by ID, update metadata, upload file, download file, get conversation thread.")
|
||||
Component(personCtrl, "PersonController", "Spring MVC — /api/persons", "Lists and searches family members. Also returns all documents sent by a person.")
|
||||
Component(userCtrl, "UserController", "Spring MVC — /api/users", "Returns current user (/me). Creates and deletes users (requires ADMIN_USER permission).")
|
||||
Component(adminCtrl, "AdminController", "Spring MVC — /api/admin", "Triggers asynchronous Excel mass import (requires ADMIN permission).")
|
||||
Component(groupCtrl, "GroupController", "Spring MVC — /api/groups", "Lists and manages permission groups.")
|
||||
Component(tagCtrl, "TagController", "Spring MVC — /api/tags", "Lists tags for typeahead.")
|
||||
|
||||
Component(docSvc, "DocumentService", "Spring Service", "Core business logic: store, update, search documents. Resolves persons and tags. Delegates file I/O to FileService. Builds JPA Specifications for dynamic search queries.")
|
||||
Component(fileSvc, "FileService", "Spring Service", "Wraps AWS SDK v2 S3Client. Uploads files with UUID-keyed paths. Downloads with content-type detection (PDF, JPEG, PNG, octet-stream).")
|
||||
Component(excelSvc, "ExcelService", "Spring Service", "Parses Excel workbooks (Apache POI). Column indices are configurable via application.properties. Creates/updates document records per row.")
|
||||
Component(massImport, "MassImportService", "Spring Service — @Async", "Reads Excel files from /import mount. Delegates to ExcelService. Runs asynchronously so the HTTP response returns immediately.")
|
||||
Component(userSvc, "UserService", "Spring Service", "User CRUD. Encodes passwords with BCrypt. Assigns users to permission groups.")
|
||||
Component(dataInit, "DataInitializer", "CommandLineRunner", "On startup: creates default admin user and groups if none exist. Seeds test data (persons, documents) if DB is empty.")
|
||||
|
||||
Component(docRepo, "DocumentRepository", "Spring Data JPA", "Queries documents. Supports Specification-based dynamic search, conversation thread queries (bidirectional sender/receiver), and filename lookups.")
|
||||
Component(docSpec, "DocumentSpecifications", "JPA Criteria API", "Factory for composable query predicates: hasText (full-text across title/filename/transcription/location), hasSender, hasReceiver (join), isBetween (date range), hasTags (subquery AND logic).")
|
||||
Component(personRepo, "PersonRepository", "Spring Data JPA", "Lists all persons sorted by last name. Supports name search for typeahead.")
|
||||
Component(userRepo, "AppUserRepository", "Spring Data JPA", "Finds users by username. Used by Spring Security and UserService.")
|
||||
Component(tagRepo, "TagRepository", "Spring Data JPA", "Finds or creates tags by name (case-insensitive).")
|
||||
Component(groupRepo, "UserGroupRepository", "Spring Data JPA", "Manages permission groups.")
|
||||
|
||||
Component(minioConf, "MinioConfig", "Spring @Configuration", "Creates the S3Client bean with path-style access for MinIO. Validates MinIO connectivity on startup.")
|
||||
Component(secConf, "SecurityConfig", "Spring @Configuration", "Configures filter chain: all routes require authentication, CSRF disabled, BCrypt password encoder, DaoAuthenticationProvider with CustomUserDetailsService.")
|
||||
Component(userDetails, "CustomUserDetailsService", "Spring Security UserDetailsService", "Loads AppUser by username from DB. Converts group permissions to Spring GrantedAuthority objects.")
|
||||
Component(docRepo, "DocumentRepository", "Spring Data JPA", "Queries documents with Specification-based dynamic search, bidirectional conversation thread queries, full-text search with ranking and match highlighting, and transcription pipeline queue projections.")
|
||||
Component(docSpec, "DocumentSpecifications", "JPA Criteria API", "Factory for composable predicates: hasText (full-text), hasSender, hasReceiver, isBetween (date range), hasTags (subquery AND/OR logic).")
|
||||
}
|
||||
|
||||
Rel(frontend, secFilter, "All requests", "HTTP / Basic Auth header")
|
||||
Rel(secFilter, permAspect, "Authenticated requests proceed", "")
|
||||
|
||||
Rel(secFilter, docCtrl, "Routes to", "")
|
||||
Rel(secFilter, personCtrl, "Routes to", "")
|
||||
Rel(secFilter, userCtrl, "Routes to", "")
|
||||
Rel(secFilter, adminCtrl, "Routes to", "")
|
||||
|
||||
Rel(permAspect, docCtrl, "Guards", "AOP @Around")
|
||||
Rel(permAspect, userCtrl, "Guards", "AOP @Around")
|
||||
Rel(permAspect, adminCtrl, "Guards", "AOP @Around")
|
||||
Component(personSvc, "PersonService", "Spring Service", "See diagram 3e. Called by DocumentService to resolve sender / receiver persons by ID.")
|
||||
Component(tagSvc, "TagService", "Spring Service", "See diagram 3d. Called by DocumentService to find or create tags by name.")
|
||||
|
||||
Rel(frontend, docCtrl, "Document requests", "HTTP / JSON")
|
||||
Rel(frontend, adminCtrl, "Trigger import", "HTTP / JSON")
|
||||
Rel(docCtrl, docSvc, "Delegates to", "")
|
||||
Rel(adminCtrl, massImport, "Triggers", "")
|
||||
Rel(userCtrl, userSvc, "Delegates to", "")
|
||||
|
||||
Rel(docSvc, fileSvc, "Upload / download files", "")
|
||||
Rel(docSvc, docRepo, "Reads / writes documents", "")
|
||||
Rel(docSvc, docSpec, "Builds search predicates", "")
|
||||
Rel(docSvc, personRepo, "Resolves sender / receivers", "")
|
||||
Rel(docSvc, tagRepo, "Finds or creates tags", "")
|
||||
|
||||
Rel(massImport, excelSvc, "Parses Excel file", "")
|
||||
Rel(docSvc, personSvc, "Resolves sender / receivers", "")
|
||||
Rel(docSvc, tagSvc, "Finds or creates tags", "")
|
||||
Rel(massImport, excelSvc, "Parses Excel/ODS file", "")
|
||||
Rel(excelSvc, docSvc, "Creates / updates documents", "")
|
||||
Rel(minioConf, fileSvc, "Provides S3Client and S3Presigner beans", "")
|
||||
Rel(fileSvc, minio, "PUT / GET / presigned URL objects", "S3 API / HTTP")
|
||||
Rel(docRepo, db, "SQL queries", "JDBC")
|
||||
```
|
||||
|
||||
### 3c — Document Transcription Pipeline
|
||||
|
||||
Annotation-driven transcription: page markup, text blocks, versioning, and comment threads.
|
||||
|
||||
```mermaid
|
||||
C4Component
|
||||
title Component Diagram: API Backend — Document Transcription Pipeline
|
||||
|
||||
Container(frontend, "Web Frontend", "SvelteKit")
|
||||
ContainerDb(db, "PostgreSQL")
|
||||
|
||||
System_Boundary(backend, "API Backend (Spring Boot)") {
|
||||
Component(transcriptionCtrl, "TranscriptionBlockController", "Spring MVC — /api/transcription", "CRUD for transcription text blocks per document page. Manages sort order, review status, and block version history.")
|
||||
Component(annotationCtrl, "AnnotationController", "Spring MVC — /api/documents/{id}/annotations", "CRUD for free-form page annotations with polygon coordinates, colour coding, and file-hash tracking.")
|
||||
Component(commentCtrl, "CommentController", "Spring MVC — /api/documents/{id}/comments", "Threaded comment CRUD on transcription blocks with @mention support and notification triggers.")
|
||||
|
||||
Component(transcriptionSvc, "TranscriptionService", "Spring Service", "Creates and updates transcription blocks from annotation regions. Tracks block versions, sanitizes text with an HTML allow-list, and triggers mentions.")
|
||||
Component(transcriptionQueueSvc, "TranscriptionQueueService", "Spring Service", "Assembles segmentation, transcription, and review queue projections by delegating to DocumentService and AuditLogQueryService.")
|
||||
Component(annotationSvc, "AnnotationService", "Spring Service", "Manages document page annotations with polygon coordinates. Called by OcrAsyncRunner to persist OCR-generated block boundaries.")
|
||||
Component(commentSvc, "CommentService", "Spring Service", "Creates and manages threaded comments with @mention parsing. Triggers NotificationService for REPLY and MENTION events.")
|
||||
|
||||
Component(blockRepo, "TranscriptionBlockRepository", "Spring Data JPA", "Reads and writes TranscriptionBlock and TranscriptionBlockVersion records.")
|
||||
Component(annotationRepo, "AnnotationRepository", "Spring Data JPA", "Reads and writes DocumentAnnotation records.")
|
||||
Component(commentRepo, "CommentRepository", "Spring Data JPA", "Reads and writes DocumentComment records.")
|
||||
}
|
||||
|
||||
Component(documentSvc, "DocumentService", "Spring Service", "See diagram 3b. Called by TranscriptionQueueService to assemble pipeline queue projections.")
|
||||
Component(auditQuerySvc, "AuditLogQueryService", "Spring Service", "See diagram 3g. Called by TranscriptionQueueService for pipeline activity data.")
|
||||
|
||||
Rel(frontend, transcriptionCtrl, "Transcription block requests", "HTTP / JSON")
|
||||
Rel(frontend, annotationCtrl, "Annotation requests", "HTTP / JSON")
|
||||
Rel(frontend, commentCtrl, "Comment requests", "HTTP / JSON")
|
||||
Rel(transcriptionCtrl, transcriptionSvc, "Delegates to", "")
|
||||
Rel(transcriptionCtrl, transcriptionQueueSvc, "Queries pipeline queues", "")
|
||||
Rel(annotationCtrl, annotationSvc, "Delegates to", "")
|
||||
Rel(commentCtrl, commentSvc, "Delegates to", "")
|
||||
Rel(transcriptionSvc, blockRepo, "Reads / writes blocks and versions", "")
|
||||
Rel(annotationSvc, annotationRepo, "Reads / writes annotations", "")
|
||||
Rel(commentSvc, commentRepo, "Reads / writes comments", "")
|
||||
Rel(transcriptionQueueSvc, documentSvc, "Queries pipeline document state", "")
|
||||
Rel(transcriptionQueueSvc, auditQuerySvc, "Queries pipeline activity data", "")
|
||||
Rel(blockRepo, db, "SQL queries", "JDBC")
|
||||
Rel(annotationRepo, db, "SQL queries", "JDBC")
|
||||
Rel(commentRepo, db, "SQL queries", "JDBC")
|
||||
```
|
||||
|
||||
### 3d — Users, Groups & Administration
|
||||
|
||||
User lifecycle, permission groups, tag management, and authentication endpoints.
|
||||
|
||||
```mermaid
|
||||
C4Component
|
||||
title Component Diagram: API Backend — Users, Groups & Administration
|
||||
|
||||
Container(frontend, "Web Frontend", "SvelteKit")
|
||||
ContainerDb(db, "PostgreSQL")
|
||||
|
||||
System_Boundary(backend, "API Backend (Spring Boot)") {
|
||||
Component(userCtrl, "UserController", "Spring MVC — /api/users", "Returns current user (/me), creates and deletes users (requires ADMIN_USER), supports user search and profile updates.")
|
||||
Component(groupCtrl, "GroupController", "Spring MVC — /api/groups", "Lists and manages permission groups.")
|
||||
Component(tagCtrl, "TagController", "Spring MVC — /api/tags", "Lists tags for typeahead, supports tag merge, tree structure, and subtree deletion.")
|
||||
Component(inviteCtrl, "InviteController", "Spring MVC — /api/auth/invite", "Creates invite codes and validates them at registration time. Rate-limited via WebConfig interceptor.")
|
||||
Component(authCtrl, "AuthController", "Spring MVC — /api/auth", "Handles user registration (POST /register) and password reset token endpoints (/forgot-password, /reset-password).")
|
||||
|
||||
Component(userSvc, "UserService", "Spring Service", "User CRUD with BCrypt password encoding, group assignment, and audit logging. Orchestrates invite-based registration and password reset tokens.")
|
||||
Component(tagSvc, "TagService", "Spring Service", "Tag CRUD with name search, hierarchical tree structure, merge/reparent operations, and recursive subtree deletion.")
|
||||
Component(dataInit, "DataInitializer", "CommandLineRunner", "On startup: creates default admin user and groups if none exist. Seeds test data if DB is empty.")
|
||||
|
||||
Component(userRepo, "AppUserRepository", "Spring Data JPA", "Finds users by email. Supports search by email or display name.")
|
||||
Component(groupRepo, "UserGroupRepository", "Spring Data JPA", "Manages permission groups.")
|
||||
Component(tagRepo, "TagRepository", "Spring Data JPA", "Finds or creates tags by name (case-insensitive). Supports recursive ancestor/descendant CTE queries and merge/reparent helpers.")
|
||||
}
|
||||
|
||||
Rel(frontend, userCtrl, "User requests", "HTTP / JSON")
|
||||
Rel(frontend, groupCtrl, "Group requests", "HTTP / JSON")
|
||||
Rel(frontend, tagCtrl, "Tag requests", "HTTP / JSON")
|
||||
Rel(frontend, inviteCtrl, "Invite validation", "HTTP / JSON")
|
||||
Rel(frontend, authCtrl, "Registration and password reset", "HTTP / JSON")
|
||||
Rel(userCtrl, userSvc, "Delegates to", "")
|
||||
Rel(groupCtrl, userSvc, "Delegates to", "")
|
||||
Rel(tagCtrl, tagSvc, "Delegates to", "")
|
||||
Rel(tagSvc, tagRepo, "Reads / writes tags", "")
|
||||
Rel(inviteCtrl, userSvc, "Creates and validates invites", "")
|
||||
Rel(authCtrl, userSvc, "Registers users, resets passwords", "")
|
||||
Rel(userSvc, userRepo, "Reads / writes users", "")
|
||||
Rel(userSvc, groupRepo, "Assigns groups", "")
|
||||
Rel(userDetails, userRepo, "Loads user by username", "")
|
||||
|
||||
Rel(fileSvc, minio, "PUT / GET objects", "S3 API / HTTP")
|
||||
Rel(docRepo, db, "SQL queries", "JDBC")
|
||||
Rel(personRepo, db, "SQL queries", "JDBC")
|
||||
Rel(userRepo, db, "SQL queries", "JDBC")
|
||||
Rel(tagRepo, db, "SQL queries", "JDBC")
|
||||
Rel(groupRepo, db, "SQL queries", "JDBC")
|
||||
Rel(dataInit, db, "Seeds initial data", "JDBC")
|
||||
Rel(secConf, userDetails, "Wires", "")
|
||||
Rel(minioConf, fileSvc, "Provides S3Client bean", "")
|
||||
Rel(userRepo, db, "SQL queries", "JDBC")
|
||||
Rel(groupRepo, db, "SQL queries", "JDBC")
|
||||
Rel(tagRepo, db, "SQL queries", "JDBC")
|
||||
```
|
||||
|
||||
### 3e — Persons & Family Graph
|
||||
|
||||
Person management including family relationship modelling and transitive inference.
|
||||
|
||||
```mermaid
|
||||
C4Component
|
||||
title Component Diagram: API Backend — Persons & Family Graph
|
||||
|
||||
Container(frontend, "Web Frontend", "SvelteKit")
|
||||
ContainerDb(db, "PostgreSQL")
|
||||
|
||||
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(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(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(relRepo, "PersonRelationshipRepository", "Spring Data JPA", "Reads and writes PersonRelationship records. Supports lookup by person ID, by relation type, and existence checks for deduplication.")
|
||||
}
|
||||
|
||||
Rel(frontend, personCtrl, "Person requests", "HTTP / JSON")
|
||||
Rel(frontend, relCtrl, "Relationship and graph requests", "HTTP / JSON")
|
||||
Rel(personCtrl, personSvc, "Delegates to", "")
|
||||
Rel(relCtrl, relSvc, "Delegates to", "")
|
||||
Rel(relCtrl, relInference, "Queries inferred graph", "")
|
||||
Rel(personSvc, personRepo, "Reads / writes persons", "")
|
||||
Rel(relSvc, relRepo, "Reads / writes relationships", "")
|
||||
Rel(relInference, relRepo, "Reads relationships for inference", "")
|
||||
Rel(personRepo, db, "SQL queries", "JDBC")
|
||||
Rel(relRepo, db, "SQL queries", "JDBC")
|
||||
```
|
||||
|
||||
### 3f — OCR Orchestration
|
||||
|
||||
How the Spring Boot backend manages OCR jobs, streams results, and trains recognition models.
|
||||
|
||||
```mermaid
|
||||
C4Component
|
||||
title Component Diagram: API Backend — OCR Orchestration
|
||||
|
||||
Container(frontend, "Web Frontend", "SvelteKit")
|
||||
ContainerDb(db, "PostgreSQL")
|
||||
ContainerDb(minio, "MinIO")
|
||||
Container(ocrPy, "OCR Service", "Python FastAPI")
|
||||
|
||||
System_Boundary(backend, "API Backend (Spring Boot)") {
|
||||
Component(ocrCtrl, "OcrController", "Spring MVC — /api/ocr", "REST entry point: trigger single or batch OCR jobs, stream progress via SSE, query job status, and manage training runs and per-sender models.")
|
||||
Component(ocrSvc, "OcrService", "Spring Service", "Creates OcrJob and OcrJobDocument records, checks Python service health, and delegates async execution to OcrAsyncRunner.")
|
||||
Component(ocrBatch, "OcrBatchService", "Spring Service", "Orchestrates multi-document OCR jobs, iterating documents and delegating each to OcrAsyncRunner.")
|
||||
Component(ocrAsync, "OcrAsyncRunner", "Spring Component — @Async", "Async worker that streams OCR results from Python page by page, persists transcription blocks and annotations via domain services, and emits progress via SSE.")
|
||||
Component(ocrClient, "RestClientOcrClient", "Spring Component", "HTTP client wrapping the Python service: POST /ocr/stream (NDJSON), /train, /segtrain, and /train-sender. Falls back from streaming to batch on 404.")
|
||||
Component(ocrTraining, "OcrTrainingService", "Spring Service", "Orchestrates model training: exports training data as ZIP, calls Python /train or /segtrain, persists training metrics in OcrTrainingRunRepository.")
|
||||
Component(ocrJobRepo, "OcrJobRepository, OcrJobDocumentRepository", "Spring Data JPA", "Reads and writes OcrJob and OcrJobDocument records. Tracks job status (RUNNING/DONE/FAILED), per-document progress, page counts, and error messages.")
|
||||
}
|
||||
|
||||
Component(transcriptionSvc, "TranscriptionService", "Spring Service", "See diagram 3c. Called by OcrAsyncRunner to persist transcription blocks per page.")
|
||||
Component(annotationSvc, "AnnotationService", "Spring Service", "See diagram 3c. Called by OcrAsyncRunner to persist OCR-generated annotation regions per page.")
|
||||
|
||||
Rel(frontend, ocrCtrl, "OCR trigger, status, and progress requests", "HTTP / JSON / SSE")
|
||||
Rel(ocrCtrl, ocrSvc, "Single-document jobs", "")
|
||||
Rel(ocrCtrl, ocrBatch, "Batch jobs", "")
|
||||
Rel(ocrCtrl, ocrTraining, "Training runs", "")
|
||||
Rel(ocrSvc, ocrAsync, "Delegates async execution", "")
|
||||
Rel(ocrBatch, ocrAsync, "Delegates async execution", "")
|
||||
Rel(ocrAsync, ocrClient, "Streams OCR results page by page", "HTTP / NDJSON")
|
||||
Rel(ocrTraining, ocrClient, "Sends training data ZIP", "HTTP / multipart")
|
||||
Rel(ocrClient, ocrPy, "POST /ocr/stream, /train, /segtrain, /train-sender", "HTTP / REST")
|
||||
Rel(ocrAsync, transcriptionSvc, "Saves transcription blocks per page", "")
|
||||
Rel(ocrAsync, annotationSvc, "Saves annotation regions per page", "")
|
||||
Rel(ocrAsync, ocrJobRepo, "Reads / writes OCR job state", "")
|
||||
Rel(ocrJobRepo, db, "SQL queries", "JDBC")
|
||||
Rel(ocrAsync, minio, "Generates presigned URLs for PDF fetch", "S3 API")
|
||||
Rel(ocrPy, minio, "Fetches PDF via presigned URL", "HTTP / S3 presigned")
|
||||
Rel(ocrTraining, db, "Persists training run metrics", "JDBC")
|
||||
```
|
||||
|
||||
### 3g — Supporting Domains
|
||||
|
||||
Audit logging, dashboard stats, SSE notifications, stories (Geschichten), and cross-cutting exception handling.
|
||||
|
||||
```mermaid
|
||||
C4Component
|
||||
title Component Diagram: API Backend — Supporting Domains
|
||||
|
||||
Container(frontend, "Web Frontend", "SvelteKit")
|
||||
ContainerDb(db, "PostgreSQL")
|
||||
|
||||
System_Boundary(backend, "API Backend (Spring Boot)") {
|
||||
Component(auditSvc, "AuditService", "Spring Service — @Async", "Writes audit log entries asynchronously via a dedicated TaskExecutor, with transaction-aware logging to prevent deadlocks on concurrent saves.")
|
||||
Component(auditQuery, "AuditLogQueryService", "Spring Service", "Queries audit logs for activity feeds, pulse stats, recent contributors, and per-document history. Facade over AuditLogRepository.")
|
||||
|
||||
Component(dashCtrl, "DashboardController", "Spring MVC — /api/dashboard", "REST endpoints for the user dashboard: recent document resume (/resume), weekly transcription pulse stats (/pulse), and activity feed (/activity) with kind filtering and pagination.")
|
||||
Component(statsCtrl, "StatsController", "Spring MVC — /api/stats", "Returns aggregate counts (total persons, total documents) for the UI stats bar.")
|
||||
Component(statsSvc, "StatsService", "Spring Service", "Queries aggregate counts: total persons and total documents.")
|
||||
Component(dashSvc, "DashboardService", "Spring Service", "Assembles the user dashboard: recent document resume (calls DocumentService + TranscriptionService), weekly transcription pulse stats, and activity feed with contributor avatars.")
|
||||
|
||||
Component(notifCtrl, "NotificationController", "Spring MVC — /api/notifications", "REST and SSE endpoints for notification stream, history with filtering, read/unread state, and per-user preference management.")
|
||||
Component(notifSvc, "NotificationService", "Spring Service", "Creates REPLY and MENTION notifications, optionally sends email, marks as read, and pushes events to connected clients via SseEmitterRegistry.")
|
||||
Component(sseRegistry, "SseEmitterRegistry", "Spring Component", "In-memory ConcurrentHashMap of Spring SseEmitter instances per user. Handles registration, deregistration, and JSON event broadcasts.")
|
||||
|
||||
Component(geschCtrl, "GeschichteController", "Spring MVC — /api/geschichten", "CRUD for publishable stories that link persons and documents. Requires BLOG_WRITE permission for write operations.")
|
||||
Component(geschSvc, "GeschichteService", "Spring Service", "Manages story lifecycle (DRAFT → PUBLISHED with timestamp). Sanitizes HTML body with an allowlist policy.")
|
||||
|
||||
Component(exHandler, "GlobalExceptionHandler", "Spring @RestControllerAdvice", "Converts DomainException, validation errors, and generic exceptions to ErrorResponse JSON with machine-readable ErrorCode and HTTP status.")
|
||||
}
|
||||
|
||||
Component(documentSvc, "DocumentService", "Spring Service", "See diagram 3b. Called by DashboardService to fetch document titles and resume data.")
|
||||
Component(transcriptionSvc, "TranscriptionService", "Spring Service", "See diagram 3c. Called by DashboardService to fetch transcription block progress for resume.")
|
||||
|
||||
Rel(frontend, dashCtrl, "Dashboard requests", "HTTP / JSON")
|
||||
Rel(frontend, statsCtrl, "GET /api/stats", "HTTP / JSON")
|
||||
Rel(frontend, notifCtrl, "Notification stream and history", "HTTP / JSON / SSE")
|
||||
Rel(frontend, geschCtrl, "Story requests", "HTTP / JSON")
|
||||
Rel(dashCtrl, dashSvc, "Delegates to", "")
|
||||
Rel(statsCtrl, statsSvc, "Delegates to", "")
|
||||
Rel(statsSvc, db, "Reads aggregate counts", "JDBC")
|
||||
Rel(dashSvc, auditQuery, "Fetches activity feed and pulse stats", "")
|
||||
Rel(dashSvc, documentSvc, "Fetches document titles and resume data", "")
|
||||
Rel(dashSvc, transcriptionSvc, "Fetches transcription block progress for resume", "")
|
||||
Rel(notifCtrl, notifSvc, "Delegates to", "")
|
||||
Rel(notifCtrl, sseRegistry, "Registers client SSE connection", "")
|
||||
Rel(notifSvc, sseRegistry, "Broadcasts events to connected clients", "")
|
||||
Rel(geschCtrl, geschSvc, "Delegates to", "")
|
||||
Rel(auditSvc, db, "Writes audit_log", "JDBC")
|
||||
Rel(auditQuery, db, "Reads audit_log", "JDBC")
|
||||
Rel(notifSvc, db, "Reads / writes notifications", "JDBC")
|
||||
Rel(geschSvc, db, "Reads / writes geschichten", "JDBC")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Level 3 — Components: Web Frontend
|
||||
|
||||
The internal structure of the SvelteKit frontend.
|
||||
The internal structure of the SvelteKit frontend, split into four focused views.
|
||||
|
||||
### 3a — Middleware, Auth & Layout
|
||||
|
||||
Per-request middleware: session validation, i18n, auth cookie handling, and auth pages.
|
||||
|
||||
```mermaid
|
||||
C4Component
|
||||
title Component Diagram: Web Frontend
|
||||
title Component Diagram: Web Frontend — Middleware, Auth & Layout
|
||||
|
||||
Person(user, "User")
|
||||
Container(backend, "API Backend", "Spring Boot")
|
||||
|
||||
System_Boundary(frontend, "Web Frontend (SvelteKit / SSR)") {
|
||||
|
||||
Component(hooks, "hooks.server.ts", "SvelteKit Server Hook", "Two responsibilities: (1) userGroup handle — reads auth_token cookie, fetches /api/users/me, stores user in event.locals. (2) handleFetch — intercepts all outgoing fetch() calls, injects Authorization header from cookie. Redirects to /login if token absent.")
|
||||
Component(hooks, "hooks.server.ts", "SvelteKit Server Hook", "Four handle layers: (1) handleAuth — redirects unauthenticated users to /login; (2) userGroup — reads auth_token cookie, fetches /api/users/me, stores user in event.locals; (3) handleFetch — injects Authorization header on all outgoing /api/ calls; (4) handleLocaleDetection — sets language cookie from Accept-Language header.")
|
||||
Component(i18n, "hooks.ts (Paraglide)", "SvelteKit Client Hook", "Client-side i18n middleware. Detects language from URL and sets the active locale for Paraglide.js translation functions.")
|
||||
|
||||
Component(layout, "+layout.server.ts", "SvelteKit Layout Loader", "Passes event.locals.user down to all child pages so every route has access to the authenticated user.")
|
||||
|
||||
Component(homePage, "/ (Home / Search)", "SvelteKit Route", "Loader: parses URL search params (q, from, to, senderId, receiverId, tags), fetches /api/documents/search and /api/persons, returns results. Page: renders search form with full-text, date range, sender/receiver typeahead, tag filters. Displays paginated document list.")
|
||||
Component(docDetail, "/documents/[id]", "SvelteKit Route", "Loader: fetches /api/documents/{id}. Handles 401 redirect to login, 404 error. Page: shows document metadata, file viewer (PDF/image inline), transcription, tags.")
|
||||
Component(docEdit, "/documents/[id]/edit", "SvelteKit Route", "Form with PersonTypeahead for sender/receiver, TagInput for tags, date/location fields. Submits PUT to /api/documents/{id}.")
|
||||
Component(persons, "/persons and /persons/[id]", "SvelteKit Routes", "Lists all persons. Detail page shows person metadata and all documents they sent.")
|
||||
Component(conversations, "/conversations", "SvelteKit Route", "Selects two persons via PersonTypeahead, fetches /api/documents/conversation, displays chronological exchange.")
|
||||
Component(loginPage, "/login", "SvelteKit Route", "Form action: encodes username:password as Base64 Basic Auth token, POSTs to /api/users/me to validate, sets auth_token httpOnly cookie (SameSite=strict, maxAge=86400), redirects to /.")
|
||||
Component(loginPage, "/login", "SvelteKit Route", "Form action: encodes email:password as Base64 Basic Auth token, POSTs to /api/users/me to validate, sets auth_token httpOnly cookie (SameSite=strict, maxAge=86400), redirects to /.")
|
||||
Component(logoutPage, "/logout", "SvelteKit Route (server-only)", "Clears the auth_token cookie and redirects to /login.")
|
||||
Component(adminPage, "/admin", "SvelteKit Route", "User management UI (create/delete users). Excel import trigger button (calls /api/admin/trigger-import).")
|
||||
|
||||
Component(apiPersons, "/api/persons (SvelteKit API)", "SvelteKit Server Route", "Proxies GET /api/persons?q=... to backend. Used by PersonTypeahead for typeahead suggestions.")
|
||||
Component(apiTags, "/api/tags (SvelteKit API)", "SvelteKit Server Route", "Proxies GET /api/tags to backend. Used by TagInput for autocomplete.")
|
||||
|
||||
Component(typeahead, "PersonTypeahead.svelte", "Svelte Component", "Async autocomplete for selecting a person. Debounces input, calls /api/persons?q=.")
|
||||
Component(tagInput, "TagInput.svelte", "Svelte Component", "Multi-tag input. Supports free-text entry and selecting existing tags from /api/tags.")
|
||||
Component(registerPage, "/register", "SvelteKit Route", "Loader validates invite code via GET /api/auth/invite/{code}. Form action: POST /api/auth/register to create the user account.")
|
||||
Component(forgotPw, "/forgot-password", "SvelteKit Route", "Form action: POST /api/auth/forgot-password. Always responds with success to prevent email enumeration.")
|
||||
Component(resetPw, "/reset-password", "SvelteKit Route", "Form action: POST /api/auth/reset-password with the token from the query string.")
|
||||
}
|
||||
|
||||
Rel(user, hooks, "Every browser request", "HTTPS")
|
||||
Rel(hooks, backend, "GET /api/users/me (session check)", "HTTP / Basic Auth")
|
||||
Rel(hooks, loginPage, "Redirect if no token", "")
|
||||
|
||||
Rel(layout, homePage, "Provides user context", "")
|
||||
Rel(layout, docDetail, "Provides user context", "")
|
||||
Rel(layout, adminPage, "Provides user context", "")
|
||||
|
||||
Rel(homePage, backend, "GET /api/documents/search", "HTTP / JSON")
|
||||
Rel(homePage, backend, "GET /api/persons", "HTTP / JSON")
|
||||
Rel(docDetail, backend, "GET /api/documents/{id}", "HTTP / JSON")
|
||||
Rel(docDetail, backend, "GET /api/documents/{id}/file", "HTTP / Binary stream")
|
||||
Rel(docEdit, backend, "PUT /api/documents/{id}", "HTTP / Multipart")
|
||||
Rel(conversations, backend, "GET /api/documents/conversation", "HTTP / JSON")
|
||||
Rel(hooks, layout, "Stores authenticated user in event.locals", "")
|
||||
Rel(loginPage, backend, "POST /api/users/me (auth check)", "HTTP / Basic Auth")
|
||||
Rel(adminPage, backend, "GET/POST/DELETE /api/users", "HTTP / JSON")
|
||||
Rel(adminPage, backend, "POST /api/admin/trigger-import", "HTTP / JSON")
|
||||
Rel(registerPage, backend, "GET /api/auth/invite/{code}, POST /api/auth/register", "HTTP / JSON")
|
||||
Rel(forgotPw, backend, "POST /api/auth/forgot-password", "HTTP / JSON")
|
||||
Rel(resetPw, backend, "POST /api/auth/reset-password", "HTTP / JSON")
|
||||
```
|
||||
|
||||
Rel(apiPersons, backend, "GET /api/persons", "HTTP / JSON")
|
||||
Rel(apiTags, backend, "GET /api/tags", "HTTP / JSON")
|
||||
### 3b — Document Workflows
|
||||
|
||||
Document search, viewing, editing, enrichment, and the shared components that support them.
|
||||
|
||||
```mermaid
|
||||
C4Component
|
||||
title Component Diagram: Web Frontend — Document Workflows
|
||||
|
||||
Person(user, "User")
|
||||
Container(backend, "API Backend", "Spring Boot")
|
||||
|
||||
System_Boundary(frontend, "Web Frontend (SvelteKit / SSR)") {
|
||||
Component(homePage, "/ (Home / Search)", "SvelteKit Route", "Loader: parses URL params (q, from, to, senderId, receiverId, tags), fetches /api/documents/search and /api/persons. Renders search form with full-text, date range, sender/receiver typeahead, and tag filters.")
|
||||
Component(docDetail, "/documents/[id]", "SvelteKit Route", "Loader: GET /api/documents/{id}. Page: metadata panel, inline file viewer, transcription editor, annotation layer, and comment thread.")
|
||||
Component(docEdit, "/documents/[id]/edit", "SvelteKit Route", "Edit form with PersonTypeahead, TagInput, date/location fields. Form action: PUT /api/documents/{id}.")
|
||||
Component(docNew, "/documents/new", "SvelteKit Route", "Upload form for a new document. Loader: GET /api/persons. Form action: POST /api/documents with multipart file.")
|
||||
Component(docBulkEdit, "/documents/bulk-edit", "SvelteKit Route", "Multi-document metadata editor. Loader: GET /api/documents/incomplete. Requires WRITE_ALL (redirects otherwise). Action: PATCH /api/documents/bulk.")
|
||||
Component(enrichPage, "/enrich/[id]", "SvelteKit Route", "Guided enrichment workflow. Loader: GET /api/documents/{id}. Progressively saves annotations and transcription blocks.")
|
||||
|
||||
Component(apiPersons, "/api/persons (SvelteKit API)", "SvelteKit Server Route", "Proxies GET /api/persons?q=... to backend for PersonTypeahead suggestions.")
|
||||
Component(apiTags, "/api/tags (SvelteKit API)", "SvelteKit Server Route", "Proxies GET /api/tags to backend for TagInput autocomplete.")
|
||||
Component(typeahead, "PersonTypeahead.svelte", "Svelte Component", "Async autocomplete for selecting a person. Debounces input, calls /api/persons?q=.")
|
||||
Component(tagInput, "TagInput.svelte", "Svelte Component", "Multi-tag input. Supports free-text entry and selecting existing tags from /api/tags.")
|
||||
}
|
||||
|
||||
Rel(user, homePage, "Searches and browses", "HTTPS / Browser")
|
||||
Rel(homePage, backend, "GET /api/documents/search, GET /api/persons", "HTTP / JSON")
|
||||
Rel(docDetail, backend, "GET /api/documents/{id}, GET /api/documents/{id}/file", "HTTP / JSON + Binary")
|
||||
Rel(docEdit, backend, "PUT /api/documents/{id}", "HTTP / Multipart")
|
||||
Rel(docNew, backend, "GET /api/persons, POST /api/documents", "HTTP / JSON + Multipart")
|
||||
Rel(docBulkEdit, backend, "GET /api/documents/incomplete, PATCH /api/documents/bulk", "HTTP / JSON")
|
||||
Rel(enrichPage, backend, "GET/POST /api/transcription, POST /api/documents/{id}/annotations", "HTTP / JSON")
|
||||
Rel(homePage, typeahead, "Uses for sender/receiver filter", "")
|
||||
Rel(docEdit, typeahead, "Uses for sender/receiver selection", "")
|
||||
Rel(docNew, typeahead, "Uses for sender selection", "")
|
||||
Rel(docEdit, tagInput, "Uses for tag management", "")
|
||||
Rel(typeahead, apiPersons, "Fetches suggestions", "HTTP")
|
||||
Rel(tagInput, apiTags, "Fetches existing tags", "HTTP")
|
||||
Rel(apiPersons, backend, "GET /api/persons", "HTTP / JSON")
|
||||
Rel(apiTags, backend, "GET /api/tags", "HTTP / JSON")
|
||||
```
|
||||
|
||||
### 3c — People, Stories & Discovery
|
||||
|
||||
Person directory, bilateral conversations, activity feed, stories, family tree, and user profiles.
|
||||
|
||||
```mermaid
|
||||
C4Component
|
||||
title Component Diagram: Web Frontend — People, Stories & Discovery
|
||||
|
||||
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(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(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.")
|
||||
Component(geschichtenEdit, "/geschichten/[id]/edit and /geschichten/new", "SvelteKit Routes", "Story editor with rich text, person and document linking. Actions: PUT/POST /api/geschichten. Requires BLOG_WRITE permission.")
|
||||
Component(stammbaum, "/stammbaum", "SvelteKit Route", "Family tree visualisation. Loader: GET /api/network (nodes + edges). Renders interactive family tree from network graph data.")
|
||||
Component(profilePage, "/profile", "SvelteKit Route", "Current user profile settings. Loader: GET /api/users/me/notification-preferences. Actions: update name/password and notification preferences.")
|
||||
Component(userProfile, "/users/[id]", "SvelteKit Route", "Public user profile view. Loader: GET /api/users/{id}.")
|
||||
}
|
||||
|
||||
Rel(user, personsPage, "Browses family members", "HTTPS / Browser")
|
||||
Rel(personsPage, backend, "GET /api/persons, GET /api/persons/{id}", "HTTP / JSON")
|
||||
Rel(personEdit, backend, "GET /api/persons/{id}, PUT /api/persons/{id}, POST /api/persons", "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")
|
||||
Rel(geschichtenEdit, backend, "GET/PUT/POST /api/geschichten", "HTTP / JSON")
|
||||
Rel(stammbaum, backend, "GET /api/network", "HTTP / JSON")
|
||||
Rel(profilePage, backend, "GET/PUT /api/users/me, notification-preferences", "HTTP / JSON")
|
||||
Rel(userProfile, backend, "GET /api/users/{id}", "HTTP / JSON")
|
||||
```
|
||||
|
||||
### 3d — Administration & Help
|
||||
|
||||
Admin panel sub-routes and the transcription help guide.
|
||||
|
||||
```mermaid
|
||||
C4Component
|
||||
title Component Diagram: Web Frontend — Administration & Help
|
||||
|
||||
Person(admin, "Administrator")
|
||||
Person(user, "User")
|
||||
Container(backend, "API Backend", "Spring Boot")
|
||||
|
||||
System_Boundary(frontend, "Web Frontend (SvelteKit / SSR)") {
|
||||
Component(adminUsers, "/admin/users, /admin/users/[id], /admin/users/new, /admin/invites", "SvelteKit Routes", "User directory, create/update/delete users, and manage invite codes. Requires ADMIN_USER permission.")
|
||||
Component(adminGroups, "/admin/groups, /admin/groups/[id], /admin/groups/new", "SvelteKit Routes", "Permission group management: create/edit groups and their permission sets.")
|
||||
Component(adminTags, "/admin/tags and /admin/tags/[id]", "SvelteKit Routes", "Tag administration: edit tag hierarchy, merge tags, delete subtrees.")
|
||||
Component(adminOcr, "/admin/ocr and /admin/ocr/[personId]", "SvelteKit Routes", "Global and per-person OCR configuration. Manages script types and triggers sender model training.")
|
||||
Component(adminSystem, "/admin/system", "SvelteKit Route", "System status panel. Triggers Excel/ODS mass import (POST /api/admin/trigger-import). Displays import state.")
|
||||
Component(hilfe, "/hilfe/transkription", "SvelteKit Route", "Static transcription style guide for Kurrent and Sütterlin character recognition. No backend calls.")
|
||||
}
|
||||
|
||||
Rel(admin, adminUsers, "Manages users and invites", "HTTPS / Browser")
|
||||
Rel(user, hilfe, "Views transcription style guide", "HTTPS / Browser")
|
||||
Rel(adminUsers, backend, "GET/POST/DELETE /api/users, POST /api/auth/invite", "HTTP / JSON")
|
||||
Rel(adminGroups, backend, "GET/POST/PUT/DELETE /api/groups", "HTTP / JSON")
|
||||
Rel(adminTags, backend, "GET/PUT/DELETE /api/tags", "HTTP / JSON")
|
||||
Rel(adminOcr, backend, "GET/POST /api/ocr (global config and sender training)", "HTTP / JSON")
|
||||
Rel(adminSystem, backend, "POST /api/admin/trigger-import, GET /api/admin/import-status", "HTTP / JSON")
|
||||
```
|
||||
|
||||
---
|
||||
@@ -218,12 +519,12 @@ sequenceDiagram
|
||||
participant Backend as Backend (Spring Boot)
|
||||
participant DB as PostgreSQL
|
||||
|
||||
User->>Browser: Enter username + password
|
||||
User->>Browser: Enter email + password
|
||||
Browser->>Frontend: POST /login (form action)
|
||||
Frontend->>Frontend: Base64 encode "user:password"
|
||||
Frontend->>Frontend: Base64 encode "email:password"
|
||||
Frontend->>Backend: GET /api/users/me<br/>Authorization: Basic <token>
|
||||
Backend->>Backend: Spring Security parses Basic Auth
|
||||
Backend->>DB: SELECT user WHERE username=?
|
||||
Backend->>DB: SELECT user WHERE email=?
|
||||
DB-->>Backend: AppUser + groups + permissions
|
||||
Backend->>Backend: BCrypt.matches(password, hash)
|
||||
Backend-->>Frontend: 200 OK — UserDTO
|
||||
|
||||
Reference in New Issue
Block a user