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:
parent
0a26572933
commit
dff776d98c
30
CLAUDE.md
30
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
|
## 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.
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
72
docs/architecture/adr/0017-accessibility-by-default.md
Normal file
72
docs/architecture/adr/0017-accessibility-by-default.md
Normal 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.
|
||||||
Loading…
Reference in New Issue
Block a user