docs(legibility): add per-domain README.md inside every domain package #400

Closed
opened 2026-05-04 16:09:08 +02:00 by marcel · 9 comments
Owner

Context

Part of Epic #394 — Documentation. This is DOC-6: a short README.md next to the code, per domain, on both stacks. This is the documentation a developer hits when they cd into the package they're about to work in.

Per the Legibility Rubric, this addresses C7.1 (Major).

Required content (per domain README)

Each per-domain README is a single short file (≤80 lines). Template:

# <Domain Name>

## What this domain owns
One-paragraph definition: which entities, which behaviors, which user-visible features.

## What this domain does NOT own
Explicit non-ownership statements that prevent confusion. Example for `person/`:
- Does NOT own AppUser accounts (those are in `user/`)
- Does NOT own document content (only references via Document.sender / Document.receivers)

## Public surface (other domains may consume this)
- `<Domain>Service.<method>()` — what it returns / what it does
- ... (only the methods other domains can call)

## Internal layout
- `<Domain>Controller` — REST endpoints under `/api/<domain>/`
- `<Domain>Service` — business logic
- `<Domain>Repository` — JPA repository
- `<Domain>` (entity) → table `<table_name>`
- DTOs in `<Domain>UpdateDTO`, etc.
- Sub-packages: `<domain>.<subpkg>` (if any — e.g., `document.transcription`)

## Cross-domain dependencies
- Calls `<OtherDomain>Service.<method>()` for X
- Reads `<SharedThing>` from `shared/`

## Frontend counterpart
Link to `frontend/src/lib/<domain>/README.md` (the symmetric file).

The frontend README mirrors this template with frontend-specific terms (routes, components, stores, hooks).

Scope: which packages

Backend (backend/src/main/java/.../):

  • document/README.md
  • person/README.md
  • tag/README.md
  • user/README.md
  • geschichte/README.md
  • notification/README.md
  • ocr/README.md
  • shared/README.md (covers the shared/ admission criteria + lists current members)

Frontend (frontend/src/lib/):

  • Same set — document/README.md, person/README.md, tag/README.md, user/README.md, geschichte/README.md, notification/README.md, ocr/README.md, shared/README.md
  • Plus derived domains: conversation/README.md, activity/README.md (each explains the "derived domain" concept)

Total: ~18 files (8 backend + 10 frontend).

Anti-patterns

  • Do NOT duplicate docs/ARCHITECTURE.md content. The per-domain README is shorter and more concrete.
  • Do NOT include code examples. The README points to the code; the code is the source of truth.
  • Do NOT exceed ~80 lines per file. If a domain needs more, that's a signal to split into sub-packages.

Acceptance criteria

  • Every backend Tier-1 domain package has a README.md (8 files)
  • Every frontend domain folder has a README.md (10 files including derived domains)
  • Each backend README links to its frontend counterpart and vice versa
  • Each README follows the template structure
  • PR opened and merged

Dependency

Hard dependency on REFACTOR-1 (Epic 4) and REFACTOR-2 (Epic 4) — the per-domain READMEs are written into the new domain packages. This issue cannot start until the domain packages exist.

Optional: stub READMEs can be drafted earlier and committed during the refactor PRs themselves.

Definition of Done

All per-domain READMEs committed on main. Closing comment lists the 18 created paths.

## Context Part of **Epic #394** — Documentation. This is **DOC-6**: a short `README.md` next to the code, per domain, on both stacks. This is the documentation a developer hits when they `cd` into the package they're about to work in. Per the Legibility Rubric, this addresses **C7.1 (Major)**. ## Required content (per domain README) Each per-domain README is a single short file (≤80 lines). Template: ```markdown # <Domain Name> ## What this domain owns One-paragraph definition: which entities, which behaviors, which user-visible features. ## What this domain does NOT own Explicit non-ownership statements that prevent confusion. Example for `person/`: - Does NOT own AppUser accounts (those are in `user/`) - Does NOT own document content (only references via Document.sender / Document.receivers) ## Public surface (other domains may consume this) - `<Domain>Service.<method>()` — what it returns / what it does - ... (only the methods other domains can call) ## Internal layout - `<Domain>Controller` — REST endpoints under `/api/<domain>/` - `<Domain>Service` — business logic - `<Domain>Repository` — JPA repository - `<Domain>` (entity) → table `<table_name>` - DTOs in `<Domain>UpdateDTO`, etc. - Sub-packages: `<domain>.<subpkg>` (if any — e.g., `document.transcription`) ## Cross-domain dependencies - Calls `<OtherDomain>Service.<method>()` for X - Reads `<SharedThing>` from `shared/` ## Frontend counterpart Link to `frontend/src/lib/<domain>/README.md` (the symmetric file). ``` The frontend README mirrors this template with frontend-specific terms (routes, components, stores, hooks). ## Scope: which packages Backend (`backend/src/main/java/.../`): - `document/README.md` - `person/README.md` - `tag/README.md` - `user/README.md` - `geschichte/README.md` - `notification/README.md` - `ocr/README.md` - `shared/README.md` (covers the shared/ admission criteria + lists current members) Frontend (`frontend/src/lib/`): - Same set — `document/README.md`, `person/README.md`, `tag/README.md`, `user/README.md`, `geschichte/README.md`, `notification/README.md`, `ocr/README.md`, `shared/README.md` - Plus derived domains: `conversation/README.md`, `activity/README.md` (each explains the "derived domain" concept) Total: ~18 files (8 backend + 10 frontend). ## Anti-patterns - Do NOT duplicate `docs/ARCHITECTURE.md` content. The per-domain README is shorter and more concrete. - Do NOT include code examples. The README points to the code; the code is the source of truth. - Do NOT exceed ~80 lines per file. If a domain needs more, that's a signal to split into sub-packages. ## Acceptance criteria - [ ] Every backend Tier-1 domain package has a `README.md` (8 files) - [ ] Every frontend domain folder has a `README.md` (10 files including derived domains) - [ ] Each backend README links to its frontend counterpart and vice versa - [ ] Each README follows the template structure - [ ] PR opened and merged ## Dependency **Hard dependency** on REFACTOR-1 (Epic 4) and REFACTOR-2 (Epic 4) — the per-domain READMEs are written *into* the new domain packages. This issue cannot start until the domain packages exist. Optional: stub READMEs can be drafted earlier and committed during the refactor PRs themselves. ## Definition of Done All per-domain READMEs committed on `main`. Closing comment lists the 18 created paths.
marcel added this to the Codebase Legibility milestone 2026-05-04 16:09:08 +02:00
marcel added the P1-highdocumentationlegibility labels 2026-05-04 16:09:55 +02:00
Author
Owner

🏗️ Markus Keller — Senior Application Architect

Observations

  • Hard dependency is real and correctly stated. The current backend is fully flat-layer packaged (controller/, service/, repository/, model/). Writing document/README.md before the domain packages exist means writing a README for a directory that doesn't exist yet — the file would be committed to the future location during REFACTOR-1/REFACTOR-2. This is fine as long as the stub strategy from the issue ("stub READMEs can be drafted earlier and committed during the refactor PRs themselves") is followed rigorously. Don't create README.md files in the current flat paths — they'd be in the wrong place.

  • Scope includes geschichte/ on the backend, which currently has GeschichteController.java, GeschichteService.java, GeschichteRepository.java, and Geschichte.java in the flat packages. This domain exists but is not yet in its own package. The README should be authored assuming the final package layout, not the current flat layout.

  • The shared/ README admission criteria is the most architecturally significant of the 18 files. Every team member currently importing cross-cutting utilities needs clarity on what qualifies for shared/ vs being duplicated per domain. The issue template says "lists current members" — be specific: what concrete types/utilities currently belong there, and what the acceptance criteria are for adding future members.

  • Cross-domain dependency section reveals coupling. Writing this section for document/README.md will expose how many services reach into adjacent domains. This is a useful forcing function — document it honestly rather than aspirationally. If DocumentService currently calls PersonService, TagService, and FileService, all three should be listed.

  • Frontend lib structure is not domain-organized. frontend/src/lib/components/ is currently a flat list of ~80 components. Writing frontend domain READMEs (e.g., frontend/src/lib/document/README.md) requires REFACTOR-2 to move components into domain folders first. The issue correctly notes this dependency, but the flat frontend structure means the frontend READMEs are even more blocked than the backend ones.

Recommendations

  • Treat stub READMEs as binding contracts, not just placeholders. Write the "Public surface" and "Cross-domain dependencies" sections first — these are the sections most likely to expose boundary violations. Leave "Internal layout" as a stub pending the refactor.
  • Start with shared/README.md. It's the highest leverage: defines what counts as shared infrastructure and prevents premature generalization. This can be drafted now without waiting for REFACTOR-1.
  • Add a "not yet domain-packaged" notice to each stub README committed during the refactor PRs — something like "Note: this domain is being migrated to this package as part of Epic #4." This prevents confusion when someone reads the README during the migration.
  • Verify the frontend domain list against actual route and lib structure. conversation/ and activity/ are listed as "derived domains" but frontend/src/routes/briefwechsel/ handles conversations and frontend/src/lib/stores/aktivitaeten/ handles activity. Ensure the README path matches where files will actually live after REFACTOR-2.
## 🏗️ Markus Keller — Senior Application Architect ### Observations - **Hard dependency is real and correctly stated.** The current backend is fully flat-layer packaged (`controller/`, `service/`, `repository/`, `model/`). Writing `document/README.md` before the domain packages exist means writing a README for a directory that doesn't exist yet — the file would be committed to the future location during REFACTOR-1/REFACTOR-2. This is fine as long as the stub strategy from the issue ("stub READMEs can be drafted earlier and committed during the refactor PRs themselves") is followed rigorously. Don't create `README.md` files in the current flat paths — they'd be in the wrong place. - **Scope includes `geschichte/` on the backend**, which currently has `GeschichteController.java`, `GeschichteService.java`, `GeschichteRepository.java`, and `Geschichte.java` in the flat packages. This domain exists but is not yet in its own package. The README should be authored assuming the final package layout, not the current flat layout. - **The `shared/` README admission criteria** is the most architecturally significant of the 18 files. Every team member currently importing cross-cutting utilities needs clarity on what qualifies for `shared/` vs being duplicated per domain. The issue template says "lists current members" — be specific: what concrete types/utilities currently belong there, and what the acceptance criteria are for adding future members. - **Cross-domain dependency section reveals coupling.** Writing this section for `document/README.md` will expose how many services reach into adjacent domains. This is a useful forcing function — document it honestly rather than aspirationally. If `DocumentService` currently calls `PersonService`, `TagService`, and `FileService`, all three should be listed. - **Frontend lib structure is not domain-organized.** `frontend/src/lib/components/` is currently a flat list of ~80 components. Writing frontend domain READMEs (e.g., `frontend/src/lib/document/README.md`) requires REFACTOR-2 to move components into domain folders first. The issue correctly notes this dependency, but the flat frontend structure means the frontend READMEs are even more blocked than the backend ones. ### Recommendations - **Treat stub READMEs as binding contracts, not just placeholders.** Write the "Public surface" and "Cross-domain dependencies" sections first — these are the sections most likely to expose boundary violations. Leave "Internal layout" as a stub pending the refactor. - **Start with `shared/README.md`.** It's the highest leverage: defines what counts as shared infrastructure and prevents premature generalization. This can be drafted now without waiting for REFACTOR-1. - **Add a "not yet domain-packaged" notice** to each stub README committed during the refactor PRs — something like "Note: this domain is being migrated to this package as part of Epic #4." This prevents confusion when someone reads the README during the migration. - **Verify the frontend domain list against actual route and lib structure.** `conversation/` and `activity/` are listed as "derived domains" but `frontend/src/routes/briefwechsel/` handles conversations and `frontend/src/lib/stores/aktivitaeten/` handles activity. Ensure the README path matches where files will actually live after REFACTOR-2.
Author
Owner

👨‍💻 Felix Brandt — Senior Fullstack Developer

Observations

  • ~18 README files is a real authoring burden if done all at once. At 80 lines each, that's ~1440 lines of documentation to write, review, and keep accurate. The risk is that several files get written hastily to close the issue, then immediately go stale when REFACTOR-1/2 actually reorganizes the code.

  • The template section "Public surface (other domains may consume this)" is the most code-adjacent section. For it to be accurate, I'd need to audit the actual service method signatures. For example, PersonService currently has getById(), findOrCreate(), merge(), and search methods — but which of these are intended cross-domain API vs internal implementation? This isn't documented anywhere today.

  • Frontend domain list includes conversation/ and activity/, but these live under routes/briefwechsel/ and stores/aktivitaeten/ right now. When writing the frontend README, use the post-REFACTOR-2 path (lib/conversation/README.md, lib/activity/README.md), not the current path. If the refactor hasn't happened yet, the README file literally can't be committed to the right place.

  • OCR is split across two stacks in a non-obvious way. Backend has OcrController, OcrService, OcrJobRepository, OcrTrainingService, etc. The frontend has frontend/src/lib/ocr/. But the actual OCR processing is in the Python microservice. The ocr/README.md on the backend should be explicit: "this domain orchestrates OCR jobs, it does NOT perform OCR — that's the Python service." Similarly the frontend OCR README should call out the SSE streaming pattern.

  • notification/README.md needs to capture the SSE emitter registry pattern. SseEmitterRegistry.java is a runtime-stateful component that manages SSE connections. It's unusual enough that a developer walking into this domain will be confused without context.

Recommendations

  • Write the shared/README.md and one domain (e.g., document/) as a gold-standard example first, then use that to calibrate the others. Don't try to write all 18 in one pass — quality degrades.
  • For the "Public surface" section, only list methods that are actually called from other domains. Grep the codebase for cross-service calls before writing this section. Example: grep -r "personService\." --include="*.java" | grep -v PersonService.java to find actual callers.
  • The 80-line limit is a good forcing function. If you find yourself exceeding it for any domain, that's a signal that domain has too many responsibilities and should be flagged for the REFACTOR issues, not expanded in the README.
  • Don't duplicate what's in CLAUDE.md or docs/architecture/. The per-domain README is for the developer who just cd'd into backend/src/main/java/.../document/ — they want to know what this specific package owns, not the full system overview.
## 👨‍💻 Felix Brandt — Senior Fullstack Developer ### Observations - **~18 README files is a real authoring burden if done all at once.** At 80 lines each, that's ~1440 lines of documentation to write, review, and keep accurate. The risk is that several files get written hastily to close the issue, then immediately go stale when REFACTOR-1/2 actually reorganizes the code. - **The template section "Public surface (other domains may consume this)"** is the most code-adjacent section. For it to be accurate, I'd need to audit the actual service method signatures. For example, `PersonService` currently has `getById()`, `findOrCreate()`, `merge()`, and search methods — but which of these are intended cross-domain API vs internal implementation? This isn't documented anywhere today. - **Frontend domain list includes `conversation/` and `activity/`**, but these live under `routes/briefwechsel/` and `stores/aktivitaeten/` right now. When writing the frontend README, use the post-REFACTOR-2 path (`lib/conversation/README.md`, `lib/activity/README.md`), not the current path. If the refactor hasn't happened yet, the README file literally can't be committed to the right place. - **OCR is split across two stacks in a non-obvious way.** Backend has `OcrController`, `OcrService`, `OcrJobRepository`, `OcrTrainingService`, etc. The frontend has `frontend/src/lib/ocr/`. But the actual OCR processing is in the Python microservice. The `ocr/README.md` on the backend should be explicit: "this domain orchestrates OCR jobs, it does NOT perform OCR — that's the Python service." Similarly the frontend OCR README should call out the SSE streaming pattern. - **`notification/README.md` needs to capture the SSE emitter registry pattern.** `SseEmitterRegistry.java` is a runtime-stateful component that manages SSE connections. It's unusual enough that a developer walking into this domain will be confused without context. ### Recommendations - **Write the `shared/README.md` and one domain (e.g., `document/`) as a gold-standard example first**, then use that to calibrate the others. Don't try to write all 18 in one pass — quality degrades. - **For the "Public surface" section, only list methods that are actually called from other domains.** Grep the codebase for cross-service calls before writing this section. Example: `grep -r "personService\." --include="*.java" | grep -v PersonService.java` to find actual callers. - **The 80-line limit is a good forcing function.** If you find yourself exceeding it for any domain, that's a signal that domain has too many responsibilities and should be flagged for the REFACTOR issues, not expanded in the README. - **Don't duplicate what's in `CLAUDE.md` or `docs/architecture/`.** The per-domain README is for the developer who just `cd`'d into `backend/src/main/java/.../document/` — they want to know what this specific package owns, not the full system overview.
Author
Owner

🔒 Nora "NullX" Steiner — Application Security Engineer

Observations

This is a documentation issue, so there are no direct security vulnerabilities to flag. However, the content of the per-domain READMEs has security implications worth shaping before authoring starts.

  • The security/ package is conspicuously absent from the scope list. The issue lists 8 backend domains: document, person, tag, user, geschichte, notification, ocr, shared. The security/ package (SecurityConfig, Permission enum, @RequirePermission, PermissionAspect) exists as a separate package today. It should either get its own README or be covered in shared/README.md. Without documentation, developers joining the project won't know that @RequirePermission is the sanctioned authorization mechanism — they may reach for @PreAuthorize with magic strings instead.

  • The "Public surface" sections for each domain should include permission requirements. For example, DocumentService methods called from other services should note whether the caller needs to have already verified permissions, or whether the service method enforces its own access control. This is a security contract that currently lives only in code.

  • user/README.md should explicitly state that AppUser accounts are never linked to historical Person entities. This domain boundary (documented in project memory) prevents identity confusion attacks — where someone might accidentally expose a historical person's records as if they belonged to a registered user. Hardcoding this in a README makes the separation undeniable to future developers.

  • ocr/README.md should document the training token authentication pattern. The Python OCR service uses X-Training-Token header auth for the /train endpoint. The backend's OcrTrainingService calls this endpoint. This security-relevant pattern should be mentioned in the backend ocr/ README so developers know that OCR training is authenticated.

Recommendations

  • Add security/ to the backend scope, or add a section to shared/README.md that covers it. Document: what @RequirePermission is, where the Permission enum lives, and that developers should never use @PreAuthorize with string literals.
  • In user/README.md, include an explicit "NOT" statement: "This domain does NOT link AppUser accounts to historical Person entities. An AppUser is a system user who can log in; a Person is a historical family member. They are unrelated concepts."
  • The acceptance criteria should include a check that security-sensitive domains (user/, ocr/) have their auth mechanisms documented in the README.
## 🔒 Nora "NullX" Steiner — Application Security Engineer ### Observations This is a documentation issue, so there are no direct security vulnerabilities to flag. However, the content of the per-domain READMEs has security implications worth shaping before authoring starts. - **The `security/` package is conspicuously absent from the scope list.** The issue lists 8 backend domains: `document`, `person`, `tag`, `user`, `geschichte`, `notification`, `ocr`, `shared`. The `security/` package (`SecurityConfig`, `Permission` enum, `@RequirePermission`, `PermissionAspect`) exists as a separate package today. It should either get its own README or be covered in `shared/README.md`. Without documentation, developers joining the project won't know that `@RequirePermission` is the sanctioned authorization mechanism — they may reach for `@PreAuthorize` with magic strings instead. - **The "Public surface" sections for each domain should include permission requirements.** For example, `DocumentService` methods called from other services should note whether the *caller* needs to have already verified permissions, or whether the service method enforces its own access control. This is a security contract that currently lives only in code. - **`user/README.md` should explicitly state that `AppUser` accounts are never linked to historical `Person` entities.** This domain boundary (documented in project memory) prevents identity confusion attacks — where someone might accidentally expose a historical person's records as if they belonged to a registered user. Hardcoding this in a README makes the separation undeniable to future developers. - **`ocr/README.md` should document the training token authentication pattern.** The Python OCR service uses `X-Training-Token` header auth for the `/train` endpoint. The backend's `OcrTrainingService` calls this endpoint. This security-relevant pattern should be mentioned in the backend `ocr/` README so developers know that OCR training is authenticated. ### Recommendations - **Add `security/` to the backend scope**, or add a section to `shared/README.md` that covers it. Document: what `@RequirePermission` is, where the `Permission` enum lives, and that developers should never use `@PreAuthorize` with string literals. - **In `user/README.md`, include an explicit "NOT" statement:** "This domain does NOT link `AppUser` accounts to historical `Person` entities. An `AppUser` is a system user who can log in; a `Person` is a historical family member. They are unrelated concepts." - **The acceptance criteria should include a check that security-sensitive domains (`user/`, `ocr/`) have their auth mechanisms documented in the README.**
Author
Owner

🧪 Sara Holt — Senior QA Engineer

Observations

  • No testability angle on this issue — this is pure documentation. No CI verification is required for the README files themselves, and there is no runtime behavior to test. My role is minimal here.

  • The acceptance criteria are auditable but not automated. "Every backend Tier-1 domain package has a README.md (8 files)" is verifiable by find . -name README.md -path "*/domain/*" in CI, but there's no CI gate proposed. Given this is docs-only, manual review on the PR is sufficient.

  • The closing comment requirement ("lists the 18 created paths") is a good manual acceptance gate. That's exactly the right format for a closing checklist.

  • Risk: READMEs go stale immediately after the refactors. The "Frontend counterpart" cross-links between backend and frontend READMEs depend on the frontend having domain-organized folders, which doesn't exist yet (frontend/src/lib/components/ is flat). If backend READMEs are written first and link to frontend/src/lib/document/README.md before that path exists, the link is broken at merge time.

Recommendations

  • Add a CI check to the PR: find backend/src/main/java -name README.md | wc -l should equal 8 and find frontend/src/lib -maxdepth 2 -name README.md | wc -l should equal 10. This is a 2-minute addition to the CI workflow and prevents partial-delivery merges.
  • Defer the cross-links between backend and frontend READMEs until both stacks have been refactored into domain packages (REFACTOR-1 and REFACTOR-2 both done). For the stub READMEs committed during the refactor PRs, use a TODO placeholder: Frontend counterpart: TODO — link after REFACTOR-2 completes. This way the link is honest rather than broken.
  • The 80-line limit should be a soft gate in PR review, not just a guideline. If any README exceeds it, the PR reviewer should ask why — the limit is a smell detector, not a hard formatter rule.
## 🧪 Sara Holt — Senior QA Engineer ### Observations - **No testability angle on this issue** — this is pure documentation. No CI verification is required for the README files themselves, and there is no runtime behavior to test. My role is minimal here. - **The acceptance criteria are auditable but not automated.** "Every backend Tier-1 domain package has a README.md (8 files)" is verifiable by `find . -name README.md -path "*/domain/*"` in CI, but there's no CI gate proposed. Given this is docs-only, manual review on the PR is sufficient. - **The closing comment requirement** ("lists the 18 created paths") is a good manual acceptance gate. That's exactly the right format for a closing checklist. - **Risk: READMEs go stale immediately after the refactors.** The "Frontend counterpart" cross-links between backend and frontend READMEs depend on the frontend having domain-organized folders, which doesn't exist yet (`frontend/src/lib/components/` is flat). If backend READMEs are written first and link to `frontend/src/lib/document/README.md` before that path exists, the link is broken at merge time. ### Recommendations - **Add a CI check to the PR**: `find backend/src/main/java -name README.md | wc -l` should equal 8 and `find frontend/src/lib -maxdepth 2 -name README.md | wc -l` should equal 10. This is a 2-minute addition to the CI workflow and prevents partial-delivery merges. - **Defer the cross-links between backend and frontend READMEs** until both stacks have been refactored into domain packages (REFACTOR-1 and REFACTOR-2 both done). For the stub READMEs committed during the refactor PRs, use a `TODO` placeholder: `Frontend counterpart: TODO — link after REFACTOR-2 completes`. This way the link is honest rather than broken. - **The 80-line limit should be a soft gate in PR review**, not just a guideline. If any README exceeds it, the PR reviewer should ask why — the limit is a smell detector, not a hard formatter rule.
Author
Owner

🎨 Leonie Voss — UX Designer & Accessibility Strategist

Observations

This is a developer-facing documentation issue with no user interface impact. The per-domain READMEs are consumed by developers, not end users. From a UX and accessibility perspective, I have nothing to flag on the feature itself.

However, there's one oblique concern worth naming:

  • The frontend domain READMEs, when they exist, will document accessibility-relevant patterns. The document/README.md and geschichten/README.md frontend READMEs should note any domain-specific accessibility commitments — for example, that GeschichtenCard.svelte requires aria-label for the story action buttons, or that the PersonChipRow.svelte component uses keyboard-navigable chips. These are currently undocumented. If we're going to write READMEs, this is the right place to capture "here's what accessibility means for components in this domain."

  • The audience split matters for the frontend READMEs. The project has two distinct audiences: transcribers (60+ on laptop/tablet) and readers (younger, on phone). The geschichten/ frontend README should explicitly note which audience it primarily serves (readers on mobile) since this affects component decisions like touch target sizing and layout density.

Recommendations

  • Add an optional "Accessibility notes" section to the frontend README template — just a bullet or two on any domain-specific a11y commitments. This is domain-README territory, not CLAUDE.md territory. Example for geschichten/: "All interactive cards must have 44px touch targets. Story titles must not rely on color alone for status."
  • No blocker here — this is a nice-to-have. The core issue is correct and well-scoped. Ship it.
## 🎨 Leonie Voss — UX Designer & Accessibility Strategist ### Observations This is a developer-facing documentation issue with no user interface impact. The per-domain READMEs are consumed by developers, not end users. From a UX and accessibility perspective, I have nothing to flag on the feature itself. However, there's one oblique concern worth naming: - **The frontend domain READMEs, when they exist, will document accessibility-relevant patterns.** The `document/README.md` and `geschichten/README.md` frontend READMEs should note any domain-specific accessibility commitments — for example, that `GeschichtenCard.svelte` requires `aria-label` for the story action buttons, or that the `PersonChipRow.svelte` component uses keyboard-navigable chips. These are currently undocumented. If we're going to write READMEs, this is the right place to capture "here's what accessibility means for components in this domain." - **The audience split matters for the frontend READMEs.** The project has two distinct audiences: transcribers (60+ on laptop/tablet) and readers (younger, on phone). The `geschichten/` frontend README should explicitly note which audience it primarily serves (readers on mobile) since this affects component decisions like touch target sizing and layout density. ### Recommendations - **Add an optional "Accessibility notes" section to the frontend README template** — just a bullet or two on any domain-specific a11y commitments. This is domain-README territory, not CLAUDE.md territory. Example for `geschichten/`: "All interactive cards must have 44px touch targets. Story titles must not rely on color alone for status." - **No blocker here** — this is a nice-to-have. The core issue is correct and well-scoped. Ship it.
Author
Owner

⚙️ Tobias Wendt — DevOps & Platform Engineer

Observations

This is a documentation issue with no infrastructure, CI, or deployment implications. No Docker changes, no new services, no secrets involved.

The only infrastructure-adjacent point I'd raise:

  • The ocr/ domain READMEs (both backend and frontend) should document the service boundary clearly for ops purposes. When I'm debugging a production issue and OCR jobs are failing, I need to know quickly: is this a backend orchestration problem (OcrService, OcrJobRepository), a frontend SSE streaming problem, or a Python microservice problem (ocr-service/)? The backend ocr/README.md should include a one-liner on the Python service: "OCR processing is delegated to ocr-service/ (Python, port 8000, separate Docker container). This domain handles job lifecycle only."

  • No CI gate is proposed for verifying all 18 files exist. Sara flagged this too. From a pipeline perspective, a find-based count check in the CI workflow is trivial. I'd add it to the same job that runs mvn verify or npm run check — it costs nothing and prevents half-merges. Example:

- name: Verify domain READMEs
  run: |
    BACKEND_COUNT=$(find backend/src/main/java -name "README.md" | wc -l)
    FRONTEND_COUNT=$(find frontend/src/lib -maxdepth 2 -name "README.md" | wc -l)
    [ "$BACKEND_COUNT" -ge 8 ] && [ "$FRONTEND_COUNT" -ge 10 ] || exit 1

Recommendations

  • Add the CI check above as part of the PR that merges this issue — it's 5 lines in the workflow YAML and prevents the acceptance criteria from being honored manually then immediately forgotten.
  • The ocr/ README cross-reference to ocr-service/ (Python) should be explicit so on-call ops don't have to reverse-engineer which layer failed when debugging.
  • No other infrastructure concerns. This issue is cleanly scoped and has zero deployment risk.
## ⚙️ Tobias Wendt — DevOps & Platform Engineer ### Observations This is a documentation issue with no infrastructure, CI, or deployment implications. No Docker changes, no new services, no secrets involved. The only infrastructure-adjacent point I'd raise: - **The `ocr/` domain READMEs (both backend and frontend) should document the service boundary clearly for ops purposes.** When I'm debugging a production issue and OCR jobs are failing, I need to know quickly: is this a backend orchestration problem (`OcrService`, `OcrJobRepository`), a frontend SSE streaming problem, or a Python microservice problem (`ocr-service/`)? The backend `ocr/README.md` should include a one-liner on the Python service: "OCR processing is delegated to `ocr-service/` (Python, port 8000, separate Docker container). This domain handles job lifecycle only." - **No CI gate is proposed for verifying all 18 files exist.** Sara flagged this too. From a pipeline perspective, a `find`-based count check in the CI workflow is trivial. I'd add it to the same job that runs `mvn verify` or `npm run check` — it costs nothing and prevents half-merges. Example: ```yaml - name: Verify domain READMEs run: | BACKEND_COUNT=$(find backend/src/main/java -name "README.md" | wc -l) FRONTEND_COUNT=$(find frontend/src/lib -maxdepth 2 -name "README.md" | wc -l) [ "$BACKEND_COUNT" -ge 8 ] && [ "$FRONTEND_COUNT" -ge 10 ] || exit 1 ``` ### Recommendations - **Add the CI check above** as part of the PR that merges this issue — it's 5 lines in the workflow YAML and prevents the acceptance criteria from being honored manually then immediately forgotten. - **The `ocr/` README cross-reference to `ocr-service/`** (Python) should be explicit so on-call ops don't have to reverse-engineer which layer failed when debugging. - **No other infrastructure concerns.** This issue is cleanly scoped and has zero deployment risk.
Author
Owner

📋 Elicit — Requirements Engineer

Observations

The issue is well-structured with a clear template, scope list, anti-patterns section, and acceptance criteria. For a documentation task, this is unusually thorough. A few gaps worth naming:

  • The hard dependency is stated but the unblocking path is underspecified. "This issue cannot start until the domain packages exist" — but the issue is already open and in the milestone. Without knowing when REFACTOR-1 and REFACTOR-2 are scheduled, there's no clear signal for when this issue can actually be picked up. If those refactors don't have scheduled PRs, this issue may sit open indefinitely.

  • The stub README strategy ("stub READMEs can be drafted earlier and committed during the refactor PRs themselves") is optional but potentially the most pragmatic path. The issue doesn't commit to this path — it says "can be." Recommend making this the default plan: stubs committed with each refactor PR, completed during this issue's PR.

  • "Tier-1 domain" is used in the acceptance criteria but not defined in the issue. The scope section lists 8 backend packages, but doesn't explain why audit/, config/, dashboard/, relationship/, and security/ are excluded. Developers reading this issue in 6 months won't know whether audit/ was intentionally excluded or just forgotten. The non-obvious omissions should be stated explicitly as "NOT in scope."

  • The acceptance criteria item "Each backend README links to its frontend counterpart" is not verifiable until after REFACTOR-2. This creates a situation where the PR could pass all other ACs but fail this one if the frontend refactor isn't done yet. Either split this AC into a separate issue, or note that cross-links are deferred until after both refactors.

  • No owner or milestone date. The issue is assigned to "Codebase Legibility" milestone but has no assignee and no target date. For a solo developer, this is fine operationally, but the hard dependency means this issue needs to be re-triaged once REFACTOR-1 has a timeline.

Recommendations

  • Explicitly list out-of-scope backend packages: audit/, config/, dashboard/, relationship/, security/, exception/, dto/ — with one sentence on why each is excluded (e.g., "config/ and exception/ are infrastructure, not domains; security/ is cross-cutting and covered in shared/README").
  • Commit to the stub strategy: change "Optional: stub READMEs can be drafted" to "Plan: stub READMEs will be committed with each refactor PR, completed in this PR."
  • Split the cross-link AC: "Each backend README links to its frontend counterpart" → separate AC with condition: "Only after REFACTOR-2 is merged." This avoids blocking the issue close on the frontend refactor timeline.
  • Add a dependency notice at the top of the issue with links to the REFACTOR-1 and REFACTOR-2 issue numbers so readers can track them directly.
## 📋 Elicit — Requirements Engineer ### Observations The issue is well-structured with a clear template, scope list, anti-patterns section, and acceptance criteria. For a documentation task, this is unusually thorough. A few gaps worth naming: - **The hard dependency is stated but the unblocking path is underspecified.** "This issue cannot start until the domain packages exist" — but the issue is already open and in the milestone. Without knowing when REFACTOR-1 and REFACTOR-2 are scheduled, there's no clear signal for when this issue can actually be picked up. If those refactors don't have scheduled PRs, this issue may sit open indefinitely. - **The stub README strategy ("stub READMEs can be drafted earlier and committed during the refactor PRs themselves")** is optional but potentially the most pragmatic path. The issue doesn't commit to this path — it says "can be." Recommend making this the default plan: stubs committed with each refactor PR, completed during this issue's PR. - **"Tier-1 domain" is used in the acceptance criteria but not defined in the issue.** The scope section lists 8 backend packages, but doesn't explain why `audit/`, `config/`, `dashboard/`, `relationship/`, and `security/` are excluded. Developers reading this issue in 6 months won't know whether `audit/` was intentionally excluded or just forgotten. The non-obvious omissions should be stated explicitly as "NOT in scope." - **The acceptance criteria item "Each backend README links to its frontend counterpart"** is not verifiable until after REFACTOR-2. This creates a situation where the PR could pass all other ACs but fail this one if the frontend refactor isn't done yet. Either split this AC into a separate issue, or note that cross-links are deferred until after both refactors. - **No owner or milestone date.** The issue is assigned to "Codebase Legibility" milestone but has no assignee and no target date. For a solo developer, this is fine operationally, but the hard dependency means this issue needs to be re-triaged once REFACTOR-1 has a timeline. ### Recommendations - **Explicitly list out-of-scope backend packages:** `audit/`, `config/`, `dashboard/`, `relationship/`, `security/`, `exception/`, `dto/` — with one sentence on why each is excluded (e.g., "config/ and exception/ are infrastructure, not domains; security/ is cross-cutting and covered in shared/README"). - **Commit to the stub strategy**: change "Optional: stub READMEs can be drafted" to "Plan: stub READMEs will be committed with each refactor PR, completed in this PR." - **Split the cross-link AC**: "Each backend README links to its frontend counterpart" → separate AC with condition: "Only after REFACTOR-2 is merged." This avoids blocking the issue close on the frontend refactor timeline. - **Add a dependency notice at the top of the issue** with links to the REFACTOR-1 and REFACTOR-2 issue numbers so readers can track them directly.
Author
Owner

Decisions Resolved

This issue does not have a consolidated Decision Queue comment, but Elicit, Markus, and Sara raised implicit decisions in their reviews. Resolving them here for completeness.

1. Out-of-scope packages → explicitly excluded with rationale

Per epic-level D2 (resolved on #394), the canonical DOC-6 enumeration is 18 files:

Backend (9): document/, person/, tag/, user/, geschichte/, notification/, ocr/, audit/, dashboard/
Frontend (8): document/, person/, tag/, user/, geschichte/, notification/, ocr/, shared/
OCR service (1): ocr-service/README.md

Explicitly excluded (per Elicit's flag — this MUST appear in the README that introduces DOC-6, so reviewers know the omissions are deliberate, not forgotten):

  • Backend config/ — Spring infrastructure, no domain identity. Conventions covered in CONTRIBUTING.md (#398).
  • Backend exception/DomainException + ErrorCode + GlobalExceptionHandler. Cross-cutting; documented in CONTRIBUTING.md "Error handling" section.
  • Backend security/SecurityConfig, Permission enum, @RequirePermission, PermissionAspect. Per Nora's flag, this content must appear in docs/ARCHITECTURE.md security model section (#396) AND in CONTRIBUTING.md "Security checklist" (#398). It does not need its own per-domain README.
  • Backend filestorage/FileService (S3/MinIO wrapper). Cross-cutting infrastructure.
  • Backend importing/MassImportService. Documented in CONTRIBUTING.md as a walkthrough or in import/CLAUDE.md migration target (DOC-7).

The original issue body listed only document/, person/, tag/, user/, geschichte/, notification/, ocr/, shared/ for the backend (8) — the revised list is 9 backend files, adding audit/ and dashboard/ per epic D2 and Markus's audit observations. Update the issue's scope section to match.

2. Stub strategy → commit stubs during refactor PRs; complete in DOC-6 PR

Per Elicit and Markus: change "Optional: stub READMEs can be drafted earlier" to "Plan: stub READMEs are committed alongside each refactor PR (Epic 4 / REFACTOR-1, REFACTOR-2). DOC-6 PR completes them." Each stub carries a header note: "Note: this domain is being migrated as part of Epic 4 — README will be expanded once the refactor lands."

This unblocks the issue's hard dependency on REFACTOR-1/2: the work happens incrementally, not in one big-bang PR.

Per Sara: "Each backend README links to its frontend counterpart" cannot land until REFACTOR-2 finishes. Resolution:

  • During the stub phase: each README's "Frontend counterpart" line says TODO — link after REFACTOR-2 completes.
  • DOC-6 closing PR replaces all TODOs with real links once both stacks are domain-organised.
  • Split this into a separate AC: "Cross-stack links resolve to existing README files. Verifiable only after REFACTOR-1 + REFACTOR-2 merge."

📌 Additional persona feedback to fold into implementation

  • Markus: start with shared/README.md — highest leverage; defines what counts as shared infrastructure; can be drafted now without waiting for refactor. Be specific: list current concrete types/utilities that belong in shared/, plus the admission criteria from #387 (no entity, no CRUD, ≥2 consumers OR framework infra).
  • Markus: verify frontend domain-list paths against current routes — briefwechsel/ (= conversation), aktivitaeten/ (= activity), stammbaum/ (= person stammbaum view). Ensure README path matches where files actually live after REFACTOR-2.
  • Felix: write shared/ and one domain (e.g., document/) as a gold standard first, then calibrate the others. Don't try to write all 18 in one pass — quality degrades.
  • Felix: for the "Public surface" section — only list methods actually called from other domains. Quick check: grep -r "personService\." --include="*.java" | grep -v PersonService.java to find actual cross-domain callers.
  • Felix: treat the 80-line cap as a forcing function. If a domain exceeds it, the domain has too many responsibilities — flag for the REFACTOR issues, don't expand the README.
  • Nora: for user/README.md — explicit "does NOT" statement: "This domain does NOT link AppUser accounts to historical Person entities. An AppUser is a system user who can log in; a Person is a historical family member. They are unrelated concepts." Per memory project_person_appuser_separation, this is a load-bearing project rule.
  • Nora: for ocr/README.md (backend) — note the X-Training-Token authentication pattern and that OCR processing is delegated to ocr-service/ (Python).
  • Felix + Tobias: for ocr/README.md (backend) — explicit boundary statement: "This domain orchestrates OCR jobs. It does NOT perform OCR — that's the Python service in ocr-service/."
  • Felix: for notification/README.md — capture the SseEmitterRegistry pattern (runtime-stateful component managing SSE connections) so a developer walking in isn't confused.
  • Sara + Tobias: add a CI check — find backend/src/main/java -name "README.md" | wc -l ≥ 9 AND find frontend/src/lib -maxdepth 2 -name "README.md" | wc -l ≥ 8 (after refactor). Trivial to add; prevents partial-merge.
  • Leonie: add an optional Accessibility notes section to the frontend README template — domain-specific a11y commitments (touch targets, aria-labels, color-not-status). Cap at 1–2 bullets per domain; link to docs/STYLEGUIDE.md for the full WCAG checklist.
  • Leonie: for geschichten/, note primary audience is mobile readers (per memory project_user_split_transcribe_vs_read); for transcribers, primary audience is laptop/tablet.
  • Elicit: explicitly list out-of-scope packages in the issue body (done above in this comment).
  • Elicit: add hard-dependency call-out at the top of the issue: "Blocked by REFACTOR-1 (Epic 4) and REFACTOR-2 (Epic 4); also blocked by DOC-2 / DOC-4 for cross-document links."

Status: Mostly ready, but hard-blocked by Epic 4 (refactor) for the per-domain backend READMEs. The non-blocked file is shared/README.md — that can be authored now. The 17 others need their target package paths to exist.

## ✅ Decisions Resolved This issue does not have a consolidated Decision Queue comment, but Elicit, Markus, and Sara raised implicit decisions in their reviews. Resolving them here for completeness. ### 1. Out-of-scope packages → **explicitly excluded with rationale** Per **epic-level D2** (resolved on #394), the canonical DOC-6 enumeration is **18 files**: **Backend (9):** `document/`, `person/`, `tag/`, `user/`, `geschichte/`, `notification/`, `ocr/`, `audit/`, `dashboard/` **Frontend (8):** `document/`, `person/`, `tag/`, `user/`, `geschichte/`, `notification/`, `ocr/`, `shared/` **OCR service (1):** `ocr-service/README.md` **Explicitly excluded** (per Elicit's flag — this MUST appear in the README that introduces DOC-6, so reviewers know the omissions are deliberate, not forgotten): - Backend `config/` — Spring infrastructure, no domain identity. Conventions covered in CONTRIBUTING.md (#398). - Backend `exception/` — `DomainException` + `ErrorCode` + `GlobalExceptionHandler`. Cross-cutting; documented in CONTRIBUTING.md "Error handling" section. - Backend `security/` — `SecurityConfig`, `Permission` enum, `@RequirePermission`, `PermissionAspect`. Per Nora's flag, this content **must** appear in `docs/ARCHITECTURE.md` security model section (#396) AND in CONTRIBUTING.md "Security checklist" (#398). It does not need its own per-domain README. - Backend `filestorage/` — `FileService` (S3/MinIO wrapper). Cross-cutting infrastructure. - Backend `importing/` — `MassImportService`. Documented in CONTRIBUTING.md as a walkthrough or in `import/CLAUDE.md` migration target (DOC-7). The original issue body listed only `document/`, `person/`, `tag/`, `user/`, `geschichte/`, `notification/`, `ocr/`, `shared/` for the backend (8) — the **revised list is 9 backend files**, adding `audit/` and `dashboard/` per epic D2 and Markus's audit observations. Update the issue's scope section to match. ### 2. Stub strategy → **commit stubs during refactor PRs; complete in DOC-6 PR** Per Elicit and Markus: change "_Optional: stub READMEs can be drafted earlier_" to **"_Plan: stub READMEs are committed alongside each refactor PR (Epic 4 / REFACTOR-1, REFACTOR-2). DOC-6 PR completes them."_** Each stub carries a header note: "_Note: this domain is being migrated as part of Epic 4 — README will be expanded once the refactor lands._" This unblocks the issue's hard dependency on REFACTOR-1/2: the work happens incrementally, not in one big-bang PR. ### 3. Cross-link AC → **defer "links to counterpart" until both stacks refactored** Per Sara: "_Each backend README links to its frontend counterpart_" cannot land until REFACTOR-2 finishes. Resolution: - During the stub phase: each README's "_Frontend counterpart_" line says `TODO — link after REFACTOR-2 completes`. - DOC-6 closing PR replaces all TODOs with real links once both stacks are domain-organised. - Split this into a separate AC: "_Cross-stack links resolve to existing README files. Verifiable only after REFACTOR-1 + REFACTOR-2 merge._" --- ## 📌 Additional persona feedback to fold into implementation - **Markus:** **start with `shared/README.md`** — highest leverage; defines what counts as shared infrastructure; can be drafted now without waiting for refactor. Be specific: list current concrete types/utilities that belong in `shared/`, plus the admission criteria from #387 (no entity, no CRUD, ≥2 consumers OR framework infra). - **Markus:** verify frontend domain-list paths against current routes — `briefwechsel/` (= conversation), `aktivitaeten/` (= activity), `stammbaum/` (= person stammbaum view). Ensure README path matches where files actually live after REFACTOR-2. - **Felix:** **write `shared/` and one domain (e.g., `document/`) as a gold standard first**, then calibrate the others. Don't try to write all 18 in one pass — quality degrades. - **Felix:** for the "_Public surface_" section — only list methods actually called from other domains. Quick check: `grep -r "personService\." --include="*.java" | grep -v PersonService.java` to find actual cross-domain callers. - **Felix:** treat the 80-line cap as a forcing function. If a domain exceeds it, the domain has too many responsibilities — flag for the REFACTOR issues, don't expand the README. - **Nora:** for `user/README.md` — explicit "_does NOT_" statement: "_This domain does NOT link `AppUser` accounts to historical `Person` entities. An `AppUser` is a system user who can log in; a `Person` is a historical family member. They are unrelated concepts._" Per memory `project_person_appuser_separation`, this is a load-bearing project rule. - **Nora:** for `ocr/README.md` (backend) — note the X-Training-Token authentication pattern and that OCR processing is delegated to `ocr-service/` (Python). - **Felix + Tobias:** for `ocr/README.md` (backend) — explicit boundary statement: "_This domain orchestrates OCR jobs. It does NOT perform OCR — that's the Python service in `ocr-service/`._" - **Felix:** for `notification/README.md` — capture the `SseEmitterRegistry` pattern (runtime-stateful component managing SSE connections) so a developer walking in isn't confused. - **Sara + Tobias:** add a CI check — `find backend/src/main/java -name "README.md" | wc -l` ≥ 9 AND `find frontend/src/lib -maxdepth 2 -name "README.md" | wc -l` ≥ 8 (after refactor). Trivial to add; prevents partial-merge. - **Leonie:** add an optional **Accessibility notes** section to the frontend README template — domain-specific a11y commitments (touch targets, aria-labels, color-not-status). Cap at 1–2 bullets per domain; link to `docs/STYLEGUIDE.md` for the full WCAG checklist. - **Leonie:** for `geschichten/`, note primary audience is mobile readers (per memory `project_user_split_transcribe_vs_read`); for transcribers, primary audience is laptop/tablet. - **Elicit:** **explicitly list out-of-scope packages** in the issue body (done above in this comment). - **Elicit:** add hard-dependency call-out at the top of the issue: "_Blocked by REFACTOR-1 (Epic 4) and REFACTOR-2 (Epic 4); also blocked by DOC-2 / DOC-4 for cross-document links._" **Status:** Mostly ready, but **hard-blocked by Epic 4 (refactor) for the per-domain backend READMEs**. The non-blocked file is `shared/README.md` — that can be authored now. The 17 others need their target package paths to exist.
Author
Owner

DOC-6 implemented — PR #444

18 per-domain README.md files created:

Backend (9):

  • backend/.../document/README.md
  • backend/.../person/README.md
  • backend/.../tag/README.md
  • backend/.../user/README.md
  • backend/.../geschichte/README.md
  • backend/.../notification/README.md
  • backend/.../ocr/README.md
  • backend/.../audit/README.md
  • backend/.../dashboard/README.md

Frontend (8):

  • frontend/src/lib/document/README.md
  • frontend/src/lib/person/README.md
  • frontend/src/lib/tag/README.md
  • frontend/src/lib/user/README.md
  • frontend/src/lib/geschichte/README.md
  • frontend/src/lib/notification/README.md
  • frontend/src/lib/ocr/README.md
  • frontend/src/lib/shared/README.md

OCR service (1):

  • ocr-service/README.md

PR: http://heim-nas:3005/marcel/familienarchiv/pulls/444

## DOC-6 implemented — PR #444 **18 per-domain README.md files created:** Backend (9): - `backend/.../document/README.md` - `backend/.../person/README.md` - `backend/.../tag/README.md` - `backend/.../user/README.md` - `backend/.../geschichte/README.md` - `backend/.../notification/README.md` - `backend/.../ocr/README.md` - `backend/.../audit/README.md` - `backend/.../dashboard/README.md` Frontend (8): - `frontend/src/lib/document/README.md` - `frontend/src/lib/person/README.md` - `frontend/src/lib/tag/README.md` - `frontend/src/lib/user/README.md` - `frontend/src/lib/geschichte/README.md` - `frontend/src/lib/notification/README.md` - `frontend/src/lib/ocr/README.md` - `frontend/src/lib/shared/README.md` OCR service (1): - `ocr-service/README.md` PR: http://heim-nas:3005/marcel/familienarchiv/pulls/444
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marcel/familienarchiv#400