Files
bookhoard/docs/developer/writing-ui-docs.md
T
John O'Keefe 20754f15e2 docs(standard): admin tier defined; promises require owner approval
Two additions to the screenshot-free writing standard, both owner-
ruled during the admin-docs planning session:

- Tone by audience gains the Administration tier, ending the 'not yet
  decided' limbo for admin docs: plain language like the user docs, plus
  what every control actually does (semantics, cost, consequences)
  before the reader clicks, and per-setting what/does/means/range
  coverage. Calibration in one line: user = what you see, admin = what
  it does, developer = how it works. The Developer section keeps its
  separate tone discussion for the deferred dev-docs pass.

- New 'Promises need approval' section: no coming-soon / under-
  consideration / future-release language anywhere without the owner's
  explicit approval of that exact promise; speculative text found in the
  docs is reported, never quietly kept or quietly deleted. Provenance
  recorded (the 2026-11-02 device-promise removals; the Operations
  placeholders knowingly kept).
2026-11-02 13:40:34 -05:00

142 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Writing UI documentation without screenshots
Bookhoard's UI documentation uses no screenshots. This page is the standard
for writing them. The flagship example of the style is the
[filter system documentation](../user/filters/index.md): one system taught
once, the places it appears listed as a *pattern*, samples for every field in
a [generated reference](../user/filters/fields.md) that cannot drift from the
UI.
## Why no screenshots
Screenshots fail in every way the rest of this repo's rot is already gated
against:
- **They rot silently.** No gate can diff pixels against the running UI. A
renamed button makes the screenshot wrong and nothing fails.
- **They cannot be verified.** Shown text can: this app's UI is
server-rendered from `templates/*.templ`, so every stable label and heading
is a literal in the source — checkable, like routes and API examples are.
- **They die with a redesign.** Text keyed to *function* survives a
re-layout. Text keyed to a layout dies with its redesign.
- **They exclude** (screen readers, text search) and bloat diffs.
The one thing screenshots do better — "which button is it?" — text does via
**exact quoted labels** plus a semantic path, and the label gate then holds
that text against the source.
## The layering — what is load-bearing
Write every UI page in this order. The top layers are why users don't get
lost when the UI changes:
| # | Layer | Content | Lifespan |
| --- | --- | --- | --- |
| 1 | **The pattern** | What the thing *is*, what is invariant, every place the same pattern appears | Redesign-proof |
| 2 | **Function inventory** | What the user *can do*, phrased without control names | Redesign-proof |
| 3 | **How-to with examples** | Numbered flows: current label → the outcome it produces | Survives most changes |
| 4 | **Current labels** | Exactly quoted, bold | Gate-checked today |
| 5 | **Generated references** | Enumerables regenerated from source with a currency test | Cannot drift |
Labels are **tips, not the map**. Layer 3 may quote a label; layer 1 must
make the page followable even if that label is renamed next week.
## The page template
1. **The pattern first.** The concept, its invariants, and everywhere it
appears — "one system, three places". Never page cartography.
2. **Function inventory.** Capabilities without control names: "you can pin
any narrowing to a named filter you can reopen later".
3. **How-to with examples.** Each step: the label of what you interact with,
then the outcome ("the count at the bottom shows how many books will
match"). An example beats an adjective.
4. **Findability note.** One line telling the reader how to re-locate the
feature *by function again* after any UI change — deliberately
label-independent ("it's the drawer opened from any books or podcasts
list — the only place whose header can read Match ALL").
5. **Current labels.** Quoted exactly as rendered, one canonical spelling
per control ([arbitrated by the glossary](ui-controls.md)).
## Writing rules
- **Semantic placement, never spatial.** No "top-right" or "at the bottom of
the screen" talk. "Devices page → the **Register Device** button" survives
any re-layout.
- **One canonical label per control.** Two spellings of the same control is
a defect, not a synonym.
- **Status updates get a what-it-means table**, not a color description.
- **Screenshots are never load-bearing.** Default is none.
## Tone by audience
- **User Guide (`docs/user/`) — plain language, deliberately.** Short
sentences. Everyday words. No developer jargon; any term the reader
genuinely needs (say, *rule*) is explained once, in place, then used
consistently. The reader is assumed to know books, while the app's own
words are the only technical vocabulary allowed.
- **Administration (`docs/admin/`) — plain language, one layer deeper.**
Same bones as the user docs: task-first, what to click for what, exact
quoted labels. Added: every control also states what the click *actually
does* — semantics, cost, and consequences — before the reader clicks it.
The canonical example: **Force Rescan All Libraries** re-reads and
re-extracts every file and recomputes hashes, while the other scan
buttons are shallow scans that skip unchanged files — an admin should
know that before clicking, not after. Every setting states what it is,
what it does, what it means when that is confusing, and its valid range.
No API-client detail: request and response schemas live in the developer
docs. The calibration in one line: **user = what you see, admin = what
it does, developer = how it works.**
- **Developer section — tone is a separate discussion, not yet decided.**
Write it plainly and hand-off-rich as well; do not import opinions about
its voice until that pass happens.
## Generate what has a registry
Anything enumerable gets generated from source with a currency test, not
hand-typed. The precedent: every filter field is
[generated](../user/filters/fields.md) by `TestFieldReferenceDocIsCurrent`
from the same registry the menus render — the doc cannot disagree with the
UI. Hand-typed lists drift fastest; when no registry exists yet, say so in
the page and lean on the pattern layers.
## The gates
- `TestUIControlLabels` (`internal/docs/ui_labels_test.go`): every control in
the [glossary](ui-controls.md) must exist as a literal in
`templates/*.templ` (or `web/src` for TS-rendered surfaces, marked
`source: ts`). Renames fail `make test` in the same commit as the rename.
- `TestDocsRelativeLinks`: every relative link in the docs tree resolves to
a real file.
Naming a new control in prose? Add its glossary entry in the same commit.
Form labels inside one modal (Name, Description…) are cited inline and not
glossary-tracked; the glossary carries the controls people navigate by —
buttons, tabs, badges, page titles.
## The process rule
**A UI change is not finished until the docs audit runs.** Moved card,
renamed button, restructured page — all of it triggers: labels still
resolve, links still resolve, affected pages re-read against the new
surface. The pattern layers keep users oriented between audits; the audit
keeps layers 3–5 honest.
## Promises need approval
Docs never promise future behavior on the owner's behalf. No "coming soon",
"under consideration", "in a future release", or any other forward-looking
commitment gets written without the owner explicitly approving that exact
promise — and anything speculative found in the docs gets reported, not
quietly kept and not quietly deleted. (Rule origin, 2026-11-02: the owner
ruled out "Kindle and reMarkable are under consideration" and a "Custom
Calibre Columns (Future)" section — no such plans existed — while the
Operations guide's pre-existing "Coming Soon" placeholders were reported
and knowingly kept for the future operations-docs pass.)
## What this does not replace
The filter documentation (and the older filtering overview) is hands-off
exemplar territory — read it as the model, never restyle it here. New UI
surfaces (scanning, devices, settings, podcasts, the reader, collections)
are written this way from the start.