docs(legibility): write human-targeted README.md at repo root #395
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-1: write the front door of the project. Today's
README.md(if present) is LLM-targeted viaCLAUDE.md; we need a separateREADME.mdwritten for humans (specifically Tobias, who will open it first and form a 60-second judgment).Per the Legibility Rubric, this issue addresses C1.1, C1.2, C1.4, C2.1, C2.2, C2.3 (all Critical or Major).
Required content
A single
README.mdat repo root containing, in this order:1. One-paragraph product description
What Familienarchiv is, who it's for, what problem it solves. ≤3 sentences. A reader who never met you should be able to describe the product accurately after this paragraph.
2. Subsystem map
Bullet list naming the 5 subsystems with a one-line purpose each:
frontend/— SvelteKit 2 / Svelte 5 / TypeScript / Tailwind 4 web appbackend/— Spring Boot 4 (Java 21) REST APIocr-service/— Python FastAPI for OCR/HTR (single-node by design — see ADR-001)infra/— CI/CD config (Gitea Actions); future home for IaCscripts/— operational + data-pipeline helpers3. Quick start
Numbered steps that take a stranger from clone to working app in ≤15 min. Must include:
admin@familyarchive.local/admin123)http://localhost:3000,http://localhost:8080/v3/api-docs)4. Where to go next
Links to:
docs/ARCHITECTURE.md— how the system is built (DOC-2)CONTRIBUTING.md— how to add features (DOC-4)docs/DEPLOYMENT.md— how to run in production (DOC-5)docs/GLOSSARY.md— disambiguate overloaded terms (DOC-3)5. License + copyright (if applicable)
Anti-patterns (what NOT to do)
CLAUDE.mdcontent into the README. CLAUDE.md is for an LLM; the README is for a human.CONTRIBUTING.mdordocs/ARCHITECTURE.md.Acceptance criteria
README.mdexists at repo root with the 5 sections abovegit clone && cd familienarchiv && <quickstart command>and reach the running app in ≤15 minCLAUDE.md(root) is updated to reference the new README and removes any duplicated front-matterDependency
Soft dependency on AUDIT-5 (#392) for findings about repo hygiene; can start without it if needed.
Definition of Done
README.mdcommitted onmain; closing comment on this issue links to the new README. Issue closed viaCloses #Nin commit.👨💻 Felix Brandt — Senior Fullstack Developer
Observations
docker-compose.yml—docker-compose up -dstarts only the DB, MinIO, and backend. The frontend requires a separatenpm run devfromfrontend/. The spec says "short sequence to bring up the stack" — two commands are fine, but they need to be listed explicitly so the stranger doesn't stop at a blank browser..env.exampleat the repo root. Thedocker-compose.ymlreferences${POSTGRES_USER},${POSTGRES_PASSWORD},${MINIO_ROOT_USER}, etc. A stranger who triesdocker-compose up -dwithout a.envwill hit an immediate failure before seeing a running app. The README should call this out, or a.env.exampleshould exist.docs/ARCHITECTURE.md,CONTRIBUTING.md,docs/DEPLOYMENT.md,docs/GLOSSARY.md— none of these files exist yet (DOC-2 through DOC-5 are future issues). The acceptance criterion says to mark them as "TODO once DOC-N lands." Be explicit in the README:[docs/ARCHITECTURE.md — TODO: lands with DOC-2 (#396)]. Vague "coming soon" is worse than nothing.ocr-service/) is not in thedocker-compose.ymldev stack (it's a separate Python service). The subsystem map should not imply it starts with the main compose command.Recommendations
.env.examplefile to the repo root as a sibling to this issue, or at minimum document the required env vars in the quick-start section of the README. Without it, the "≤15 min from clone to running" acceptance criterion cannot be met..env.exampleto.envand fill in values (or note the defaults for local dev)docker compose up -d— starts DB, MinIO, backendcd frontend && npm install && npm run devhttp://localhost:3000ocr-service/runs independently and is not part of the defaultdocker compose up.🏛️ Markus Keller — Senior Application Architect
Observations
frontend/,backend/,ocr-service/,infra/,scripts/) map correctly to distinct concerns with different deployment characteristics.docs/adr/) exists and has 6 records. The README's "Where to go next" section currently targetsdocs/ARCHITECTURE.md(DOC-2, not yet written), but there is adocs/architecture/c4-diagrams.mdthat already exists. This is a real navigational asset that a new contributor would want to know about — it should either be linked directly or DOC-2 should be noted as the canonical home when it lands.docs/adr/as a primary navigational aid — it's already populated and doesn't depend on any future doc issue.docs/ARCHITECTURE.md. This is fine, but the ADR index is the complementary "why" resource that already exists.Recommendations
docs/adr/in the "Where to go next" section. It's the most complete documentation that currently exists and a new contributor will want it immediately.docs/architecture/c4-diagrams.mdas a provisional architecture overview until DOC-2 lands.docs/ARCHITECTURE.mdwithout a "TODO" marker — a dead link is worse than a missing link.🔒 Nora "NullX" Steiner — Application Security Engineer
Observations
admin@familyarchive.local/admin123. This is intentional for local dev and the anti-patterns section correctly excludes "copy CLAUDE.md" which already contains these credentials. The risk is reasonable for local dev, provided the README makes unmistakably clear these are dev-only values that must be changed before any network-exposed deployment.docker-compose.yml: the PostgreSQL port is exposed externally ("${PORT_DB}:5432"), and MinIO usesminio:latest(unpinned tag). Neither of these belong in the README itself, but a first-time reader who follows the quick-start blindly will expose the DB port to their network. The README quick-start should include a brief note: "⚠️ The default Docker Compose is configured for local development only — do not expose these services to a network without reviewingdocs/DEPLOYMENT.md."docs/DEPLOYMENT.md(DOC-5, not yet written). Until that doc exists, there is no documented path for safe production deployment. The README should be explicit: production deployment documentation is not yet available.Recommendations
docs/DEPLOYMENT.mdfor production hardening."# local dev only— this gives future automated secret scanners (e.g., Gitleaks) a clear false-positive signal and makes the intent unmistakable.docs/DEPLOYMENT.md) lands, ensure it covers: change default credentials, use MinIO service accounts, close DB port, enable HTTPS. The README sets the expectation that it will.🧪 Sara Holt — Senior QA Engineer
Observations
git clone && cd familienarchiv && <quickstart command>and reach the running app in ≤15 min" criterion is testable by actually doing it in a clean environment. I'd suggest running this test before marking the PR as ready for review — it's easy to skip steps that are obvious to someone who built the app.grep -E '\[.+\]\(docs/.+\)' README.md | xargs -I{} test -f {}). This should be added to the PR checklist.CLAUDE.mdto reference the README and remove duplicated front-matter is the most ambiguous acceptance criterion here. "Duplicated front-matter" needs a clearer definition — what specifically inCLAUDE.mdwould be considered duplication once README.md exists? The product overview, stack list, and quick-start commands currently appear in CLAUDE.md. Clarify: should these be removed from CLAUDE.md (pointing to README), kept in both (redundant but fine), or left as-is (CLAUDE.md is for LLMs, README for humans, no conflict)?Recommendations
CLAUDE.mdshould be updated/removed once README.md exists. The current AC is too vague to verify.🎨 Leonie Voss — UX Designer & Accessibility Strategist
Observations
http://localhost:3000— you should see the login page").Recommendations
http://localhost:3000— you should see the Familienarchiv login screen." This closes the loop for the first-time user and confirms the environment is working.##level — not###. For a short document (≤150 lines), two heading levels are sufficient. Deeper nesting increases cognitive load without adding structure.⚙️ Tobias Wendt — DevOps & Platform Engineer
Observations
docker-compose.yml. Two things a stranger will hit immediately that the issue doesn't address:.env.exampleexists. Every environment variable (POSTGRES_USER,POSTGRES_PASSWORD,MINIO_ROOT_USER, etc.) is undefined in the compose file —docker-compose up -don a fresh clone produces an error, not a running stack.minio/minio:latest— unpinned image tag. Not the README's problem to fix, but the quick-start should not imply a reproducible result when the underlying compose file uses:latest.docker compose(V2, no hyphen) as a subcommand. The old standalonedocker-composebinary is effectively deprecated. Usedocker composein the README (V2 syntax) — it's what new developers will have.http://localhost:8080/v3/api-docs. This is correct only when the backend runs with--spring.profiles.active=dev(per CLAUDE.md: "only accessible when running with--spring.profiles.active=dev"). The README quick-start should not list this URL as universally reachable — it will mislead someone who starts the backend without the dev profile.ocr-service/subsystem is not part ofdocker-compose.ymlat the repo root. A first-time reader following the quick-start will not have OCR running. The README subsystem map should make this clear: OCR is a separately started service, not part of the default dev stack.infra/directory is listed in the issue's subsystem map as "CI/CD config (Gitea Actions); future home for IaC." I checked: the directory exists but I can't confirm what's in it from this review. If it has actual Gitea Actions workflow files, link them or describe what CI does. If it's empty/placeholder, say "future home for IaC" as the spec states.Recommendations
.env.exampleat the repo root as part of this issue (or as a fast predecessor task). The README quick-start is the wrong place to inline all required env vars. A.env.examplewith safe development defaults is the correct pattern — the README points to it: "Copy.env.exampleto.envbefore starting."docker compose(V2) notdocker-compose(V1) in all command examples.http://localhost:8080/v3/api-docsURL from the default quick-start, or add a qualifier: "API docs (requires dev profile):http://localhost:8080/v3/api-docs."ocr-service/directory at minimum).📋 Elicit — Requirements Engineer
Observations
CLAUDE.md(root) is updated to reference the new README and removes any duplicated front-matter." The word "duplicated" is undefined. CLAUDE.md contains a product overview, stack summary, and quick-start commands that will also appear in README.md. The requirement as written could mean: (a) remove the product description from CLAUDE.md and link to README; (b) remove only verbatim duplicates; or (c) add a single reference line at the top of CLAUDE.md pointing to README without removing anything. These lead to meaningfully different outcomes and different PR review expectations.http://heim-nas:3005/marcel/familienarchiv/issues— a LAN address. If the repo is ever shared or mirrored, this link will be unreachable. If this is permanently private infrastructure, it's fine. If there's any chance of public sharing, the link should either be omitted or templated.Recommendations
README.md") without removing any existing content — CLAUDE.md serves a different audience and the duplication is intentional../issueswon't work for Gitea) or note it explicitly as "internal — accessible only on the home network." Don't present a private LAN URL as a public resource.🗳️ Decision Queue — Action Required
3 decisions need your input before implementation starts.
Scope
.env.examplebe part of this issue or a prerequisite task? — Thedocker-compose.ymlhas no defaults for env vars; without a.env,docker compose up -dfails immediately on a fresh clone. Option A: create.env.exampleas part of this PR (adds scope but makes the quick-start verifiable). Option B: create a fast prerequisite task, block this issue on it, and link to.env.examplefrom the README. Either way, the ≤15 min acceptance criterion cannot be met without it. (Raised by: Felix, Tobias)Content / Links
How should
CLAUDE.mdbe updated when README.md exists? — AC 5 says "remove duplicated front-matter," but CLAUDE.md serves a different audience (LLM) and the duplication is intentional by design. Three options: (a) remove the product/stack sections from CLAUDE.md and redirect to README; (b) add one reference line at the top of CLAUDE.md without removing anything; (c) leave CLAUDE.md unchanged entirely. Option (b) is the lowest-risk change and keeps CLAUDE.md self-contained for the LLM. (Raised by: Sara, Elicit)Should the Gitea issue tracker URL (
http://heim-nas:3005/...) appear in the README? — This is a LAN address that will be unreachable from anywhere outside the home network. Options: (a) include it as-is — perfectly fine for a permanently private family project; (b) omit it — README links to docs only, not the tracker; (c) use a placeholder comment noting "internal URL — see your local Gitea instance." If the repo will never be shared publicly, option (a) is fine. If there's any chance of sharing or mirroring, option (b) or (c) is safer. (Raised by: Elicit)✅ Decision Queue — Resolved
The 3 decisions raised in #395#issuecomment-6213:
1.
.env.example→ bundle into this PR (Option A)Without it, the "≤15 min from clone to running app" AC is unverifiable. Splitting it into a prerequisite task creates merge friction without value. The
.env.examplefile is small, low-risk, and tightly coupled to the README's quickstart section. Add it in the same PR.Implementation note: keep dev defaults conservative —
POSTGRES_PASSWORD=changeme,MINIO_ROOT_USER=minioadmin, etc. — matching whatdocker-compose.ymlalready expects but with safer defaults than blanks. Comment each var briefly.2. CLAUDE.md update → single reference line, no removals (Option b)
Add one line at the top of root
CLAUDE.md:> For a human-readable project overview, see [README.md](./README.md).Do not remove any existing content from CLAUDE.md in this PR. The full migration (move rules → human docs, replace with pointer comments) is DOC-7's job per the epic-level Decision Queue D3 — and DOC-7 is hard-blocked by DOC-2/4/5/6 anyway. Pre-migrating now would create churn.3. Gitea LAN URL → include as-is with one-line qualifier (Option a + small note)
Per the project frame, this is a permanently family-only system. The Gitea instance at
http://heim-nas:3005/marcel/familienarchiv/issueswill not be exposed publicly. Include it in the README, but qualify: "(internal — only reachable from the home network)." One sentence; prevents confusion if the repo is ever cloned elsewhere.📌 Additional persona feedback to fold into implementation
These aren't decisions — just commitments worth tracking in the PR:
.env.examplecopy step,docker compose(V2, no hyphen),cd frontend && npm install && npm run dev, end with "openhttp://localhost:3000— you should see the login screen."docs/adr/in "Where to go next" (it already exists; doesn't depend on DOC-2). Also linkdocs/architecture/c4-diagrams.mdprovisionally until DOC-2 lands. Add one-line license: "Private project — all rights reserved. Not licensed for redistribution."docs/DEPLOYMENT.mdfor production hardening." Format default admin credentials in a code block tagged# local dev only.http://localhost:8080/v3/api-docsis dev-profile only. Either omit or qualify: "API docs (requires--spring.profiles.active=dev)." OCR service is not part of the defaultdocker compose up; mention this in the subsystem map.##heading level only.TODO once DOC-N lands (#396).Forward-link target issue numbers: DOC-2 = #396, DOC-3 = #397, DOC-4 = #398, DOC-5 = #399.
Status: Ready for implementation.
Implementation complete — PR #440
README.mdis written and PR #440 is open.Commits
a5d20f26—README.md(93 lines, 5 sections)f02c59dd— README reference line in rootCLAUDE.mdAcceptance criteria status
README.mdexists at repo root with the 5 sections.env.examplecopy →docker compose up -d db minio mailpit→./mvnw spring-boot:run→npm run dev→http://localhost:5173# local dev only_(coming: [DOC-N, #NNN])_CLAUDE.mdupdated with a single reference line (no removals — DOC-7 owns migration)docs/GLOSSARY.mdlinked (lands with DOC-3 PR #439)docs/adr/linked (exists now, 6 ADRs)One correction vs issue body
The issue specified
http://localhost:3000. The actual Vite port is5173(confirmed invite.config.ts,port: 5173). README and.env.exampleboth use 5173 — no change needed there.