From 858909564e551bb56014372fa3b1978223a8873a Mon Sep 17 00:00:00 2001 From: Claude Fable 5 Date: Tue, 21 Jul 2026 17:17:26 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20ADR=200017=20=E2=80=94=20Barrierefreihe?= =?UTF-8?q?it=20als=20Standard-Anforderung?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Claude-Session: https://claude.ai/code/session_01AGM8jo3hwoV9wsCVGfy8iq --- CLAUDE.md | 30 ++++++++ docs/architecture/README.md | 1 + .../adr/0017-accessibility-by-default.md | 72 +++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 docs/architecture/adr/0017-accessibility-by-default.md diff --git a/CLAUDE.md b/CLAUDE.md index 417efeb..498ee32 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 This project has a knowledge graph at graphify-out/ with god nodes, community structure, and cross-file relationships. diff --git a/docs/architecture/README.md b/docs/architecture/README.md index e347e7d..9865a3b 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -70,6 +70,7 @@ flowchart LR | [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 | | [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 diff --git a/docs/architecture/adr/0017-accessibility-by-default.md b/docs/architecture/adr/0017-accessibility-by-default.md new file mode 100644 index 0000000..409053c --- /dev/null +++ b/docs/architecture/adr/0017-accessibility-by-default.md @@ -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.