docs: ADR 0017 — Barrierefreiheit als Standard-Anforderung

Jede künftige UI-Änderung entwickelt Barrierefreiheit direkt mit
(Stefans Vorgabe nach Abschluss des WCAG-2.1-AA-Audits): verbindliche
Checkliste als ADR, Kurzfassung in CLAUDE.md für jede Dev-Session,
Eintrag im ADR-Index.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AGM8jo3hwoV9wsCVGfy8iq
This commit is contained in:
Claude Fable 5 2026-07-21 17:17:26 +02:00
parent 0a26572933
commit dff776d98c
3 changed files with 103 additions and 0 deletions

View File

@ -1,3 +1,33 @@
## Barrierefreiheit (verbindlich, ADR 0017)
Jede UI-Änderung wird von Anfang an barrierefrei entwickelt (WCAG 2.1
AA) — nicht nachträglich. Kurzfassung; Details und Begründung in
`docs/architecture/adr/0017-accessibility-by-default.md`:
- **Bausteine wiederverwenden:** `IconButton` (erzwungener Name),
`Field` (Label + Fehler-Verdrahtung), `useModalFocus` für Dialoge
(Trap/Initialfokus/Rückgabe + `aria-labelledby`). Keine Parallelbauten.
- **Tastatur zuerst:** alles erreichbar/bedienbar, Fokus sichtbar,
Escape schließt, kein Fokusverlust; Einzeltasten-Shortcuts respektieren
`lib/single-key-shortcuts.ts`.
- **Name/Rolle/Wert:** korrekte Rollen, lokalisierte (de+en) Labels,
Zustände via aria-*; dekorative Icons `aria-hidden`.
- **BEIDE Renderpfade:** Editor-/NodeView-Pfad UND docToHtml/Server-Pfad
gleichwertig behandeln (Cache rollt lazy aus).
- **Kontrast/Farbe:** Tokens nutzen (Text ≥ 4,5:1, UI ≥ 3:1;
`--color-border-input` für Feldränder; `--color-favorite` nur Icons);
Farbe nie als einziges Merkmal.
- **Reflow:** kein seitenweites Horizontal-Scrollen bei 320 px
(`min-width: 0` an Flex-/Grid-Kindern nicht vergessen).
- **Bewegung/Zeit:** `prefers-reduced-motion` respektieren, keine zu
kurzen Auto-Dismiss-Zeiten.
- **CI-Pack pflegen:** neue Kern-Screens in `apps/web/e2e/a11y.spec.ts`
aufnehmen; die Allowlist bleibt leer bzw. nur mit Begründung.
- Neue aria-Labels können bestehende `getByLabel`-e2e-Locator mehrdeutig
machen — betroffene Specs mit anpassen (scopen), nicht das Label opfern.
Verstöße gelten in Review und Abnahme als Funktionsfehler.
## graphify ## graphify
This project has a knowledge graph at graphify-out/ with god nodes, community structure, and cross-file relationships. This project has a knowledge graph at graphify-out/ with god nodes, community structure, and cross-file relationships.

View File

@ -70,6 +70,7 @@ flowchart LR
| [0014](adr/0014-gitea-actions-cicd.md) | CI/CD with Gitea Actions, staged promotion | | [0014](adr/0014-gitea-actions-cicd.md) | CI/CD with Gitea Actions, staged promotion |
| [0015](adr/0015-backup-strategy.md) | Nightly pg_dump + uploads sync, 30-day retention, off-host mirror | | [0015](adr/0015-backup-strategy.md) | Nightly pg_dump + uploads sync, 30-day retention, off-host mirror |
| [0016](adr/0016-self-hosted-fonts.md) | Self-hosted Google Fonts, per-pond font configuration | | [0016](adr/0016-self-hosted-fonts.md) | Self-hosted Google Fonts, per-pond font configuration |
| [0017](adr/0017-accessibility-by-default.md) | Accessibility (WCAG 2.1 AA) as a default requirement |
### Concept documents ### Concept documents

View File

@ -0,0 +1,72 @@
# ADR 0017: Accessibility (WCAG 2.1 AA) as a default requirement
- Status: accepted
- Date: 2026-07-21
## Context
A full WCAG 2.1 AA audit (July 2026) found a solid baseline — enforced
accessible names on `IconButton`, the implicitly labelling `Field`
primitive, localized ARIA labels, a clean landmark structure — but also
systemic gaps that had accumulated because accessibility was checked
after the fact rather than built in: dialogs without focus management, a
hard-coded document language, broken listbox semantics, page-level
horizontal scrolling at 320 px viewport width. All findings were fixed in
issues #162#171; an axe-core smoke pack (`apps/web/e2e/a11y.spec.ts`)
now pins the core screens in CI.
Retro-fitting accessibility is far more expensive than building it in.
This ADR makes it a default requirement for every future feature.
## Decision
**Every user-facing change ships accessible.** Concretely, a feature is
not done until it satisfies this checklist:
1. **Reuse the accessible primitives.** Icon-only controls go through
`IconButton` (enforces a name); form controls go through `Field`
(label + `aria-describedby`/`aria-invalid` wiring); dialogs use
`useModalFocus` (focus trap, initial focus, focus return) plus
`aria-labelledby` on their heading. Do not hand-roll parallels.
2. **Keyboard first.** Everything reachable and operable by keyboard,
visible focus, Escape closes overlays, no focus loss on unmount. New
single-key shortcuts must respect the "disable single-key shortcuts"
setting (`lib/single-key-shortcuts.ts`).
3. **Name, role, value.** New widgets carry correct roles and
localized (de+en) accessible names; state via `aria-expanded`,
`aria-selected`, `aria-pressed` etc. Decorative icons stay
`aria-hidden`.
4. **Both render paths.** Anything that renders content must behave
identically in the editor/NodeView path AND the `docToHtml`/server
path (public view, comments, previews) — including labels and list
semantics. Remember: `page_content_cache` rolls out `docToHtml`
changes lazily (on next persist).
5. **Color and contrast.** Use the design tokens; text ≥ 4.5:1, UI
boundaries and icons ≥ 3:1 (`--color-border-input` exists for field
borders; `--color-favorite` is icon-only). Color is never the only
cue. Dark-rendered surfaces (public shell) keep their checked colors.
6. **Reflow.** New layouts must not force page-level horizontal
scrolling at 320 px (flex/grid children need `min-width: 0`;
intrinsically wide content scrolls in its own focusable container).
7. **Motion and time.** Respect `prefers-reduced-motion`; no
auto-updating or auto-dismissing content faster than users can
perceive it.
8. **Extend the CI pack.** A new core screen or a new interaction
pattern gets added to `apps/web/e2e/a11y.spec.ts` (axe, WCAG A/AA
tags, empty allowlist — additions to the allowlist need a written
justification in the spec).
Code review and issue acceptance criteria treat violations of this
checklist like functional defects, not polish.
## Consequences
- New features cost slightly more up front and no longer accumulate an
accessibility backlog; the July 2026 audit stays the last big one.
- The axe CI pack fails builds on regressions of the fixed state; specs
may need locator updates when accessible names are added (a11y labels
can make `getByLabel` matchers ambiguous — scope them).
- The full audit report (methodology, per-criterion matrix, measurement
harness) lives in the operator's workspace
(`doku/audit-barrierefreiheit-2026-07.md`) and can be re-run after
larger UI changes.