QA-09: barrierefreiheits-audit

Voller Merge von TEN-05/IAM-08/RBAC-05/LIC-04/AUD-04/CFG-04/OPS-02 (SHL-01
bereits Bestandteil) nach feature/qa-09-barrierefreiheits-audit. WCAG-2.1-AA-
Audit ueber alle 7 Core-Frontends (15 Seiten): automatisierte Pruefung
(pa11y/HTML_CodeSniffer WCAG2AA) und automatisiertes Tastatur-Traversal
(Puppeteer) auf 192.168.1.131 durchgefuehrt, Ergebnis nach Fixes 0/15
Verstoesse, 100% Tastaturerreichbarkeit ohne Fallen.

Vier reale WCAG-Verstoesse gefunden und behoben: ungueltiger
autocomplete="username" auf type="email"-Feldern (account, 2 Seiten) sowie
fehlende zugaengliche Namen auf Filter-/Eingabefeldern in audit-log,
lic-admin und tenant-admin (aria-label ergaenzt).

Zusaetzlich ein realer Testinfrastruktur-Fehler in internal/adminapi
gefunden: lichandler_test.go's Cleanup rief `DELETE FROM tenant_licenses
WHERE tenant_id = $1` OHNE das $1-Argument auf (Fehler durch `_, _ =`
verschluckt) - die Tenant-Zeile blieb dadurch ueber eine FK-Constraint
dauerhaft haengen und verfaelschte internal/migrate im vollen Testlauf,
analog zu den in QA-04 gefundenen defer/t.Cleanup-Bugs. Nur Testcode
betroffen.

Ein Restbefund terminiert: echter Bildschirmleser-Durchlauf (NVDA/
VoiceOver) steht mangels grafischer Testumgebung noch aus, Frist vor QA-05
(siehe docs/QA-09-BARRIEREFREIHEITS-AUDIT.md Abschnitt 5).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
This commit is contained in:
sysops
2026-08-29 10:27:15 +02:00
co-authored by Claude Sonnet 5
parent d1977e6c2e
commit 349104a809
7 changed files with 154 additions and 4 deletions
+1 -1
View File
@@ -45,7 +45,7 @@ export default function LoginPage() {
<TextField
label="E-Mail-Adresse"
type="email"
autoComplete="username"
autoComplete="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
@@ -35,7 +35,7 @@ export default function PasswordResetRequestPage() {
<TextField
label="E-Mail-Adresse"
type="email"
autoComplete="username"
autoComplete="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
+4
View File
@@ -40,24 +40,28 @@ export default function Page() {
value={caller}
onChange={(e) => setCaller(e.target.value)}
placeholder="Admin-Token (Berechtigung)"
aria-label="Admin-Token (Berechtigung)"
style={{ padding: "0.5rem", gridColumn: "span 3" }}
/>
<input
value={filter.tenant}
onChange={(e) => setFilter({ ...filter, tenant: e.target.value })}
placeholder="Tenant"
aria-label="Tenant"
style={{ padding: "0.5rem" }}
/>
<input
value={filter.actor}
onChange={(e) => setFilter({ ...filter, actor: e.target.value })}
placeholder="Akteur"
aria-label="Akteur"
style={{ padding: "0.5rem" }}
/>
<input
value={filter.action}
onChange={(e) => setFilter({ ...filter, action: e.target.value })}
placeholder="Aktion"
aria-label="Aktion"
style={{ padding: "0.5rem" }}
/>
<label>
+1
View File
@@ -56,6 +56,7 @@ export default function Page() {
value={tenantId}
onChange={(e) => setTenantId(e.target.value)}
placeholder="Tenant-ID eingeben"
aria-label="Tenant-ID eingeben"
style={{ flex: 1, padding: "0.5rem", fontSize: "1rem" }}
/>
<button onClick={load} disabled={loading} style={{ padding: "0.5rem 1rem" }}>
+3 -1
View File
@@ -105,15 +105,17 @@ export default function Page() {
value={superadminId}
onChange={(e) => setSuperadminId(e.target.value)}
placeholder="Superadmin-ID"
aria-label="Superadmin-ID"
style={{ padding: "0.5rem" }}
/>
<input
value={search}
onChange={(e) => setSearch(e.target.value)}
placeholder="Suche (Slug/Name)"
aria-label="Suche (Slug/Name)"
style={{ padding: "0.5rem" }}
/>
<select value={status} onChange={(e) => setStatus(e.target.value)} style={{ padding: "0.5rem" }}>
<select value={status} onChange={(e) => setStatus(e.target.value)} aria-label="Status-Filter" style={{ padding: "0.5rem" }}>
<option value="">Alle Status</option>
<option value="active">Aktiv</option>
<option value="suspended">Suspendiert</option>