docs(legibility): write docs/ARCHITECTURE.md with diagram and domain list #396
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Part of Epic #394 — Documentation. This is DOC-2: the architecture document Tobias will open second (after the README). It must let him reproduce the system on a whiteboard from memory after one read.
Per the Legibility Rubric, this addresses C1.3, C3.1, C3.2, C3.6 (all Critical or Major).
Required content
A single
docs/ARCHITECTURE.mdcontaining, in this order:1. High-level diagram
A diagram (ASCII art is fine; Mermaid preferred if rendered) showing:
The reader should be able to redraw this from memory.
2. Canonical domain set
List every domain from the Canonical Domain Set in #387 first comment. For each Tier-1 domain (
document,person,tag,user,geschichte,notification,ocr):For each Tier-2 (derived) domain (
conversation,activity):3. Cross-cutting layer
List every
shared/member (audit, file-storage, import, dashboard, transcription-queue, security, error-handling, config, i18n, discussion). For each, one sentence on what it does and the admission criteria it satisfies.4. Stack-symmetry principle
Explain that domain names are identical across
backend/src/main/java/.../andfrontend/src/lib/. State the rule: "Adding a new domain means adding it on both sides under the same name."5. Key architectural decisions
Pull existing ADRs and rules from
CLAUDE.mdfiles (root + per-subsystem) and present them here in human-readable form. Examples:ocr-service/CLAUDE.md)@RequirePermission,Permissionenum, AOP enforcement)6. Data flow walkthroughs
Two concrete walkthroughs (1 paragraph each):
Anti-patterns
Acceptance criteria
docs/ARCHITECTURE.mdexists with all 6 sectionsDependency
Soft dependency on AUDIT-2 (#389), AUDIT-3 (#390), AUDIT-4 (#391), AUDIT-5 (#392) for findings about existing architectural decisions. Can be drafted in parallel and refined when audits land.
Definition of Done
docs/ARCHITECTURE.mdcommitted onmain; closing comment links to it. Issue closed viaCloses #Nin commit.🏛️ Markus Keller — Senior Application Architect
Observations
docs/ARCHITECTURE.mddoes not yet exist. The nearest equivalent isdocs/architecture/c4-diagrams.md(266 lines, last updated before OCR service, Notification, Geschichte, and the full canonical domain set were added). That file omits: the OCR container and its HTTP+SSE protocol, SSE notifications path, the Tier-2 derived domains (conversation,activity), and the seven cross-cutting members inshared/.docs/adr/(001–006). None of them are referenced from any human-readable architecture document. Section 5 ("Key architectural decisions") is the place to consolidate their conclusions into prose — not to duplicate them, but to summarise the what and link to the ADR for the why.backend/src/main/java/.../is still layer-first (controller/,service/,model/,repository/) rather than domain-first. Section 4 ("Stack-symmetry principle") should state this as the target state, not the current state. Tobias reading the doc should know: "the code doesn't look like this yet — the refactor is what gets it there."docs/architecture/c4-diagrams.mdMermaid diagrams are GitHub/Gitea-renderable and already describe the L1/L2/L3 structure. Section 1 of the new doc should reference or embed the L2 diagram rather than redrawing it as ASCII. Mermaid in the existing file is the better starting point.docs/architecture/c4-diagrams.md. Reuse it (updated to include OCR queue step) rather than rewriting in prose.Recommendations
ocr-service(Python, port 8000), the SSE path (backend → frontend), and the presigned-URL path (MinIO → ocr-service). These three additions make the diagram current. Keep it at C4 Level 2 — that is the whiteboard-reproducible level.model/package withGeschichte.java,Notification.java,OcrJob.java, etc. The doc should say: "The following domains have been ratified as the target structure; code organisation will match this after the Refactor epic."Open Decisions
docs/ARCHITECTURE.mddescribe the current state or the target state of the domain structure? Option A: describe current state (layer-first packages) and note the target. Option B: describe only the target (domain-first packages) and note "not yet implemented." Option A is safer for Tobias — a discrepancy between doc and code is worse than a clearly labelled aspiration. (This affects how Section 2 and Section 4 are framed.)👨💻 Felix Brandt — Senior Fullstack Developer
Observations
controller/,service/,model/,repository/) while the issue asks the doc to describe a domain-first structure. TheGeschichte.java,OcrJob.java,Notification.javaentities exist in the flatmodel/package. The doc must not mislead: if it saysdocument/DocumentService.javathat file does not exist yet at that path.src/lib/already has closer-to-domain organisation (geschichten/route exists,components/directory has domain-shaped components). The asymmetry between frontend and backend organisation should be called out honestly in Section 4.TranscriptionService.java,TranscriptionBlockQueryService.java,OcrProgressService.java,SseEmitterRegistry.javaall exist. The autosave and SSE path are real and worth documenting. The walkthrough should name the chain:TranscriptionService→ persists block →SseEmitterRegistrybroadcasts →NotificationServiceon mention. This is conceptual enough to write without line numbers.Recommendations
model/package has:Document,Person,Tag,AppUser,Geschichte,Notification,OcrJob,TranscriptionBlock,DocumentAnnotation,DocumentComment. Map each to the canonical domain it belongs to — do not invent a structure that doesn't exist. When the domain is "not yet extracted to its own package," say so in one parenthetical.FileService, which calls MinIO via the AWS SDK v2 S3Client." That level of naming is helpful without being a code reference. Avoid: "seeFileService.java:104."conversationandactivitywithout understanding the code. Draft: "A derived domain has its own UI but no dedicated database tables; it is assembled by the frontend from data owned by other domains." That is the whole concept in one sentence — do not pad it.Open Decisions (omit this section entirely if none)
OcrService,OcrBatchService,OcrAsyncRunner,OcrClient,OcrProgressService). How much of that chain belongs in a conceptual architecture doc vs. an OCR-specific domain README (DOC-6)? If this doc stays conceptual, one paragraph suffices. If it tries to document the OCR pipeline in full, the 400-line limit breaks. (Raised by Felix — affects Section 6.)🔒 Nora "NullX" Steiner — Application Security Engineer
Observations
This is a documentation issue, not an implementation issue. There are no code-level security vulnerabilities to flag in
ARCHITECTURE.mditself. My concern is what the document should say about security — and what it must not accidentally expose.@RequirePermission, thePermissionenum, and AOP enforcement as content for Section 5. This is correct and necessary — the permission system is an architectural decision that Tobias needs to understand to avoid bypassing it when sketching a feature.docs/security-guide.mdis already in the repo. Section 5 of the architecture doc should reference it rather than repeating its content. Duplication means two files to maintain and the risk that they drift out of sync.auth_token, httpOnly, SameSite=strict, maxAge=86400). The C4 container diagram calls it "Basic Auth token" which is technically accurate but omits the httpOnly/SameSite properties. These matter architecturally — they are why CSRF is disabled. The authentication section should state: "Sessions are implemented as an httpOnly, SameSite=strict cookie containing the Base64-encoded Basic Auth token. CSRF protection is disabled because this cookie configuration structurally prevents cross-origin credential theft."PermissionAspect" is the right level: it tells Tobias where enforcement happens without exposing the implementation.Recommendations
@RequirePermission+PermissionAspect+Permissionenum), (3) why CSRF is disabled (not "we disabled it" but "the cookie configuration makes it structurally impossible"). Three sentences, no code.docs/security-guide.mdrather than duplicating it. One line: "For a full security audit reference, seedocs/security-guide.md." Tobias doesn't need to know rate limiting implementation details — just that a security guide exists.No open decisions from a security perspective — the recommendations above are all concrete.
🧪 Sara Holt — QA Engineer & Test Strategist
Observations
This is a documentation deliverable, not a code feature, so the test strategy question is: how do we verify that
docs/ARCHITECTURE.mdactually achieves its acceptance criteria?The issue has five acceptance criteria:
Criteria 1, 3, 4, and 5 are grep-testable. Criterion 2 ("Tobias-test") is a human judgment call that has no automated test equivalent — it requires a real reader.
Looking at the rubric checks this issue addresses: C1.3 (ARCHITECTURE.md with diagram, Tobias can reproduce), C3.1 (domains named), C3.2 (per-domain definitions), C3.6 (shared/ justification). All four are in the Critical/Major range.
The issue dependency on AUDIT-2 through AUDIT-5 (#389–#392) is soft — the doc can be drafted before audits land and refined after. But if the audits find that the canonical domain set described in the doc doesn't match the current code, the doc will need a revision pass.
Recommendations
docs/ARCHITECTURE.mdonly. A PR that bundles audit report content with the architecture doc makes review harder. One file, one PR.wc -l docs/ARCHITECTURE.mdin the PR. Over 400 lines is a scope failure, not a style preference.No open decisions — all recommendations are concrete verification steps.
🎨 Leonie Voss — UX Designer & Accessibility Strategist
Observations
This issue is about writing a Markdown document, so my usual concerns about touch targets, contrast ratios, and responsive layouts don't directly apply. What I do care about is the information architecture and readability of the document — the UX of the documentation itself.
docs/architecture/c4-diagrams.md. Use Mermaid. ASCII art forces readers to mentally parse spatial relationships that a rendered diagram communicates instantly.Recommendations
docs/architecture/c4-diagrams.mdhas the C4 L2 diagram. Update it to addocr-service, the SSE arrow, and the presigned-URL path. Then embed or link it from Section 1. Do not create a second diagram file.Member | One sentence | Admission criteria (a/b/c). 11 rows at ~1 line each = 12 lines including header. A paragraph per member would be ~44 lines. The table format saves 32 lines toward the 400-line budget and is easier to scan.<!-- Last reviewed: YYYY-MM-DD, against commit SHA -->at the top of the file tells future readers whether the doc is likely to still be accurate. This is a documentation hygiene convention, not code.No open decisions from a UX perspective — all recommendations are concrete.
⚙️ Tobias Wendt — DevOps & Platform Engineer
Observations
I'm the named "target reader" for this document — the issue literally says "Tobias can reproduce the diagram from memory." So I'm reviewing both the deliverable requirements and the infrastructure/deployment side of what needs to be documented.
docs/architecture/c4-diagrams.mdshows the L2 container view but is missing the OCR service. The docker-compose.yml orchestrates:frontend,backend,db,minio,ocr-service, and themcinit container. The architecture doc should describe all six containers. Tobias looking at the Compose file and the architecture diagram should see the same boxes.SseEmitterRegistry.javahandles server-sent events from the backend. The SvelteKit frontend connects to the backend SSE endpoint directly. This is a backend → browser path, not backend → frontend SSR. The diagram should show this as a direct arrow frombackendtobrowser, notbackend → frontend → browser.ocr-service → minio, "presigned URL fetch") is currently missing fromc4-diagrams.md.docs/architecture/c4-diagrams.md. That diagram doesn't include the OCR queue step. The new walkthrough should either update that diagram or be written as a numbered prose list that extends the existing diagram's description.docs/infrastructure/— so it should reference, but not duplicate, the deployment documentation.Recommendations
docs/architecture/c4-diagrams.mdto add: (1)ocr-servicecontainer withPython FastAPI / port 8000, (2)Rel(backend, ocr-service, "OCR requests", "HTTP / REST / JSON"), (3)Rel(ocr-service, storage, "Fetch PDF via presigned URL", "HTTP / S3 presigned"), (4)Rel(backend, user, "SSE notifications", "HTTP / SSE"). Then embed or reference this updated diagram in Section 1 ofARCHITECTURE.md.docs/infrastructure/for deployment details. Section 6 walkthroughs should end with: "For production deployment, seedocs/infrastructure/production-compose.md." The architecture doc describes the what; the infra docs describe the how to operate.No open decisions from my angle — all gaps have clear answers.
📋 Elicit — Requirements Engineer
Observations
docs/adr/(001–006) and additional architectural rules inbackend/CLAUDE.mdandocr-service/CLAUDE.mdthat are not formal ADRs. The AC says "CLAUDE.md files" — should every rule in every CLAUDE.md file be migrated toARCHITECTURE.md? That would produce a very long doc. Or should only decisions (not conventions) be migrated?Recommendations
docs/adr/summarised in 2–3 sentences each, (b) the layering rule (controller → service → repository), (c) the single-node OCR constraint, and (d) the permission system. Everything else in CLAUDE.md is convention, not an architectural decision — conventions belong in a separate conventions doc (DOC-3 or DOC-5), not in ARCHITECTURE.md.backend/src/main/java/.../andfrontend/src/lib/. The backend is currently organised by layer; the refactor epic will restructure it to match this convention." Without this qualifier, Anja opens the backend, seescontroller/DocumentController.java, and concludes the doc is wrong.Open Decisions
CONTRIBUTING.mdor conventions doc, not be embedded in the architecture doc. (Decision needed before authoring starts.)🗳️ Decision Queue — Action Required
3 decisions need your input before implementation starts.
Architecture / Scope
Current state vs. target state in Sections 2 and 4 — The backend is still layer-first (
controller/,service/,model/), but the doc describes a domain-first structure. Option A: describe current state and label the target as aspirational. Option B: describe only the target and note "not yet implemented." Option A is recommended — a discrepancy between doc and code is worse than a clearly labelled aspiration. Without this choice, the doc will either mislead Anja (who opens the backend and sees layer packages) or confuse Tobias (who sees a target he can't verify). (Raised by: Markus, Felix, Elicit)Section 5 scope: all CLAUDE.md rules vs. ADRs + key architectural decisions only — Option A (all CLAUDE.md rules): comprehensive but risks exceeding 400 lines and duplicating a future conventions doc. Option B (ADRs + 3 key architectural decisions — layering rule, permission system, single-node OCR): concise, maintainable, and clearly scoped. Recommend Option B. Everything else in CLAUDE.md (entity code style, DTO conventions, error handling patterns) belongs in a
CONTRIBUTING.mdor conventions doc, not inARCHITECTURE.md. (Raised by: Markus, Elicit)Scope / Detail Level
OcrService,OcrBatchService,OcrAsyncRunner,OcrClient,OcrProgressService). Option A: one paragraph in Section 6 at the conceptual level ("backend queues the OCR job, OCR service fetches PDF via presigned URL, streams results back"). Option B: full pipeline walkthrough, which will consume significant line budget and blur with the domain README scope (DOC-6). Recommend Option A — keep Section 6 conceptual; the per-domain OCR README (DOC-6) is the right place for the full pipeline. (Raised by: Felix)✅ Decision Queue — Resolved
The 3 decisions raised in #396#issuecomment-6331:
1. Current vs target state in Sections 2 and 4 → describe current state + label target as aspirational (Option A)
Markus, Felix, and Elicit all converge on this. A discrepancy between doc and code is worse than a clearly labelled aspiration. Anja will scan the actual backend package structure on day one — if the doc says
document/DocumentService.javaand the file lives atservice/DocumentService.java, the doc is misleading.Implementation pattern:
model/Document.java; will move todocument/after the Refactor epic — see #387)" where the location differs from the target.controller/,service/,model/,repository/); the Refactor epic restructures it to match this convention."2. Section 5 scope → ADRs + 3 key architectural decisions only (Option B)
Section 5 covers:
docs/adr/001..006) — 2–3 sentences each, link to the full ADR for the why.@RequirePermission+PermissionAspect+Permissionenum).Everything else in CLAUDE.md (entity Lombok template, DTO conventions, error-handling patterns, Svelte 5 patterns) is convention, not architectural decision — those go to
CONTRIBUTING.md(DOC-4 / #398), not here. This caps Section 5 around ~80 lines per Felix's budget.3. OCR domain depth in Section 6 → one paragraph conceptual (Option A)
Section 6's OCR walkthrough is conceptual: "The backend queues an OCR job, generates a MinIO presigned URL, and calls the OCR service. The OCR service fetches the PDF directly from MinIO over the internal Docker network and streams transcription blocks back. The backend persists blocks and broadcasts SSE notifications." That level of naming services is enough.
The full five-class pipeline (
OcrService,OcrBatchService,OcrAsyncRunner,OcrClient,OcrProgressService) belongs inbackend/.../ocr/README.mdandocr-service/README.md(both DOC-6 / #400).📌 Additional persona feedback to fold into implementation
docs/architecture/c4-diagrams.mdMermaid L2 diagram (do not redraw as ASCII). Add:ocr-servicecontainer (Python FastAPI / port 8000),Rel(backend, ocr-service, "OCR requests", HTTP/REST/JSON),Rel(ocr-service, storage, "Fetch PDF via presigned URL", HTTP/S3 presigned),Rel(backend, user, "SSE notifications", HTTP/SSE). Embed/link from Section 1.Member | One sentence | Admission criteria a/b/c), not paragraph-per-member — saves ~30 lines.@RequirePermission+PermissionAspect). Referencedocs/security-guide.md; do not duplicate it.wc -l docs/ARCHITECTURE.md< 400; named human reviewer for the Tobias-test (read cold after 24h, sketch architecture). Mark forward-deps to AUDIT-2..5 (#389-#392) explicitly if those haven't landed.<!-- Last reviewed: YYYY-MM-DD against commit SHA -->at the top.Status: Ready for implementation.
DOC-2 implemented — PR #441
What was written:
docs/ARCHITECTURE.md— 146 lines, 6 sections:Also updated:
docs/architecture/c4-diagrams.mdL2 Mermaid diagram — added ocr-service container, SSE notification arrow (backend → browser direct), presigned-URL arrow (ocr → minio).Commits:
aedae2a7— update c4-diagrams.md L2dc6910a3— write docs/ARCHITECTURE.mdPR: http://heim-nas:3005/marcel/familienarchiv/pulls/441