E09: Product documentation backlog (#101)
Some checks failed
Test / suites (push) Failing after 3m12s
Test / container (push) Failing after 4m23s

This commit was merged in pull request #101.
This commit is contained in:
2026-08-23 15:04:45 +02:00
parent 833bfa95bf
commit 370f966d29
8 changed files with 322 additions and 5 deletions

View File

@@ -0,0 +1,49 @@
# US09-01 — Serve the Documentation Inside the Application
Epic: [E09](../E09-documentation.md)
As an operator who was handed a URL and an access secret, I want the manuals inside the
application I am looking at, so that understanding it does not require a repository
checkout or an internet connection.
## Acceptance criteria
- Documentation lives as markdown under `docs/`, with an index that names every page and
the order it is meant to be read in. The same files render on Gitea without
modification.
- The application serves a `/docs` view reachable from the main navigation, listing the
pages and rendering the selected one.
- Rendering uses a vendored, version-pinned markdown library committed under
`frontend/js/vendor/`. It is not fetched from a CDN, not bundled by a build step, and
not written by hand. The build records the version and a checksum of the vendored file.
- Diagrams written as ```mermaid``` fenced blocks render as diagrams. Mermaid is vendored
the same way.
- `script-src` in the Content-Security-Policy is unchanged: no `'unsafe-eval'`, no
`'unsafe-inline'`. Only `style-src` gains `'unsafe-inline'`, and the reason is recorded
where the policy is defined.
- Links between documents work in the app: a relative `../foo.md#section` link navigates
to that page and heading rather than downloading a file or leaving the application.
Every heading has a stable anchor, and a deep link to an anchor scrolls to it.
- An unknown page renders a documentation-specific not-found message with a link back to
the index, and never exposes a filesystem path.
- Documentation is readable without an access secret **or** behind the same session as
the rest of the application — whichever is chosen is stated explicitly in the story's
implementation notes and covered by a test, because an operator locked out by a
configuration mistake is exactly who needs the troubleshooting page.
- The view works with no outbound network access at all.
## Automated tests
- Unit: heading-anchor slugs (duplicates, punctuation, non-ASCII), and the rewriting of
relative markdown links into in-app routes.
- Integration: every markdown file under `docs/` is reachable from the index; every
internal link in every document resolves to a file and, where an anchor is given, to a
heading that exists; the vendored library files match their recorded checksums.
- Browser: the documentation view renders a page, follows an internal link, deep-links to
an anchor, renders a mermaid diagram to an SVG, and shows the not-found message for an
unknown page — all with **zero console errors and zero CSP violations**, asserted, not
eyeballed.
## Dependencies
- None beyond the delivered application.

View File

@@ -0,0 +1,46 @@
# US09-02 — Write the Installation and Operations Manual
Epic: [E09](../E09-documentation.md)
As somebody installing this application for the first time, I want one manual that takes
me from nothing to a running instance pointed at my photo library, so that I do not have
to reconstruct the procedure from the README, the compose file, and the test suite.
## Acceptance criteria
- A **host installation** path: prerequisites and their versions (Python, exiftool,
immich-go, Playwright's browser for the test suite), virtual environment, dependency
install, `.env`, database migration, starting `serve` and `worker`, and how to verify
the install succeeded.
- A **container installation** path: the published image, the compose file, the data
volume, the library bind mount and why it is mounted the way it is, published ports,
running behind a reverse proxy with `PHOTO_PIPELINE_ALLOWED_HOSTS` and
`PHOTO_PIPELINE_TRUSTED_PROXIES`, and the Portainer/webhook deployment already in use.
- A **configuration reference**: every `PHOTO_PIPELINE_*` setting with its meaning,
default, accepted values, and whether it is a secret. Secrets are described, never
exemplified with a real-looking value.
- A **first run checklist** that ends in a verified state: library discovered, worker
claiming jobs, readiness endpoint green, diagnostics clean.
- **Operations**: upgrading (including what the migration backup does), backup, verify,
restore, pruning, diagnostics, and the log locations for each role.
- **Troubleshooting**: each refusal an operator can hit at startup — every non-zero exit
code of the CLI, the trust-boundary refusal, the unmounted library root refusal, the
library lock being held, and a legacy CLI still running — with the cause and the fix.
- The manual states the safety invariants an installer must not work around: one worker
writes, `_IGNORE/` is never read, EXIF is verified before upload, and the library lock
is authoritative.
## Automated tests
- Every `PHOTO_PIPELINE_*` setting documented exists as a field on `Config`, and every
field on `Config` is documented — both directions, so a new setting cannot ship
undocumented.
- Every CLI command and flag named in the manual exists in the argument parser, and every
subcommand the parser accepts appears in the manual.
- Every exit code documented is one the CLI can actually return.
- No documented example value collides with a real secret pattern (the repository's own
credential scanner runs over `docs/`).
## Dependencies
- US09-01

View File

@@ -0,0 +1,47 @@
# US09-03 — Write the Architecture Overview
Epic: [E09](../E09-documentation.md)
As a developer or reviewer new to this repository, I want an architecture overview that
explains what the pieces are and which rules they enforce, so that I can find the right
module and not violate an invariant I never knew existed.
## Acceptance criteria
- A **context diagram**: the operator, the browser application, the API and worker, the
photo library, the Immich server, the vision provider, and the archive destination —
with the direction and nature of every interaction, including which ones leave the
machine.
- A **runtime diagram**: the migrate/api/worker composition, the data volume, the library
bind mount, the SQLite database, and the process lock — showing what is shared and what
is exclusive.
- A **module map**: every package under `photo_pipeline/` with its responsibility and the
boundary it must not cross (which modules may touch the filesystem, which may call an
external provider, which own schema).
- **Key flows**, each as a diagram plus prose: the durable job lifecycle from enqueue to
recovery; the rename journal state machine including the rollback and manual-resolution
paths; the upload lifecycle through preflight, run, report ingestion, and verification.
- **The invariants and where they are enforced**, each pointing at the module that owns
it: one writer at a time, the library process lock, the path policy and library roots,
`_IGNORE/` exclusion, verified EXIF before upload, safety decisions gating the vision
provider, and restart-safety of every mutation.
- **The data model**: the tables, what identity means for an asset, and how a moved file
keeps its identity.
- A short **history and donor** section: what was migrated out of the legacy CLIs, where
the archive and its ledger live, and why they are kept.
- Diagrams are ```mermaid``` blocks so the source is diffable and Gitea renders them
natively.
## Automated tests
- Every package and top-level module under `photo_pipeline/` appears in the module map,
and every module named in the map exists — a new service cannot appear on the map's
blind side.
- Every job state, journal state, and upload batch state named in the document exists in
the code, and every state the code defines is named in the document.
- Every mermaid block parses (rendered in the browser test without an error node).
- Every code path referenced by file name exists.
## Dependencies
- US09-01

View File

@@ -0,0 +1,52 @@
# US09-04 — Write the User Manual with Generated Screenshots
Epic: [E09](../E09-documentation.md)
As the person actually sorting a photo library, I want a manual that walks the workflow
screen by screen and tells me what each refusal means, so that I can use the application
confidently and know what it is about to do to my files before it does it.
## Acceptance criteria
- One page per workflow stage, in the order the application presents them: discovery and
inventory, duplicate review, safety review, analysis, album proposals, renames, upload,
archive, and diagnostics. Each page answers the same four questions: what this stage is
for, what I have to decide, **what it changes on disk or on the server**, and what it
refuses to do.
- A **guided first pass** that takes a new library from scan to a verified upload, naming
the point of no return in each stage and what is reversible after it.
- Every stage page carries at least one screenshot of the real application showing the
state being described.
- Screenshots are **generated** by a committed Playwright script that seeds a temporary
fixture library, drives the application, and writes the images. Regenerating them is one
documented command. No screenshot is captured by hand.
- Screenshots contain no real library paths, no personal photos, and no secrets — the
fixture library is synthetic, and this is asserted rather than assumed.
- An **error and refusal catalogue**: every `error.code` the API can return, with what
causes it, what the application did or refused to do, and what the operator should do
next. Refusals that protect data (`lock_held`, `rename_recovery_required`,
`stale_preflight`, `path_not_allowed`, `host_not_allowed`, `dry_run_not_approved`,
conflict codes) are explained as intentional, not as faults.
- A **recovery** page: an interrupted rename, an uncertain upload, a failed migration, a
restored backup — what the application does by itself and what needs a decision.
- The work-item safety allow list is extended to permit `docs/images/**`, since the
repository denies image files by default. This is an explicit, reviewed change, not a
quiet one, and it stays narrow enough that a real photo still cannot be committed.
## Automated tests
- Every `error.code` the application can emit is documented, and every code documented
exists in the code — both directions.
- Every image referenced by a documentation page exists, and every image under
`docs/images/` is referenced by a page.
- The screenshot generator runs end to end in the test environment and produces every
image the manual references, against a temporary fixture library that is destroyed
afterwards.
- Generated screenshots are checked for library paths outside the fixture root and for
the configured secrets.
- Browser: each stage page renders in the documentation view with its screenshot loaded
and no console error.
## Dependencies
- US09-01

View File

@@ -0,0 +1,38 @@
# US09-05 — Automate Documentation Acceptance
Epic: [E09](../E09-documentation.md)
As a release owner, I want one gate that proves the documentation still describes the
application, so that a change to the code cannot quietly make the manuals wrong.
## Acceptance criteria
- One documented command runs every documentation check and retains its evidence, in the
shape the release and container gates already use.
- The gate fails when: an internal link or anchor is dead; a page is unreachable from the
index; an image is referenced but missing or present but unreferenced; a documented
setting, command, exit code, error code, or state does not exist in the code; a code
path exists that the documentation is required to cover and does not.
- The gate regenerates the screenshots and fails when a regenerated image no longer
matches the committed one beyond a stated tolerance, so a UI change that invalidates the
manual is a red build rather than a discovery months later.
- The gate renders every documentation page in a real browser and fails on any console
error or CSP violation, and asserts that `script-src` contains neither `'unsafe-eval'`
nor `'unsafe-inline'`.
- The checks run on a `phase_i` marker; CI runs the gate, and the earlier epic suites keep
running unchanged.
- The README and the application's documentation index point at each other, so neither is
the forgotten copy.
- Documentation stories are mapped in the story traceability matrix like every other
story.
## Automated tests
- The gate's own contract is testable without a browser: a seeded broken link, a missing
image, an undocumented error code, and a stale screenshot each fail it, and a clean tree
passes.
- The full documentation suite runs on `phase_i` in CI.
## Dependencies
- US09-01 through US09-04