feat(C): Phase C — Core UI prüfen, vervollständigen, testen

C-ERR-BOUNDARY: ErrorBoundary erweitert (trace_id, Fallback-UI, PluginErrorBoundary)
C-NOTIF: NotificationDropdown mit System-Channel-Link
C-DOCS: ApiDocs.tsx Seite (Swagger UI iframe)
C-A11Y: aria-label, min-h-touch, focus-visible ergänzt
C-FE-TEST: 29 neue Tests (ErrorBoundary, ApiDocs, PrintButton, themeStore, NotificationDropdown)
C-DOC: ui-design-guidelines.md aktualisiert

Verifiziert (keine Änderungen nötig):
- C-TAGS, C-CF, C-FILTER, C-DEDUP, C-ONBOARD, C-THEME, C-PWA, C-PRINT

TSC: 0 errors, Build: erfolgreich, Vitest: 29/29 passed
This commit is contained in:
Agent Zero
2026-08-13 21:57:59 +02:00
parent 0e72d4624d
commit 25b2581653
15 changed files with 713 additions and 62 deletions
+112 -1
View File
@@ -511,7 +511,118 @@ function ContactForm({ open, onClose }) {
---
## 10. Datei-Struktur
## 10. Error Boundaries & Plugin-Fehlerbehandlung
### ErrorBoundary (common)
Die zentrale `ErrorBoundary` in `components/common/ErrorBoundary.tsx` fängt React-Render-Fehler ab und zeigt eine Fallback-UI mit:
- **Trace-ID**: Jeder Fehler erhält eine eindeutige `trace_id` (Format: `err-<timestamp>-<random>`), die im Fehlerbuffer und im Backend-Log gespeichert wird
- **Fehlerdetails**: Ausklappbare Details mit Fehlermeldung und Stack-Trace
- **Retry-Button**: Setzt den Error-State zurück und versucht erneut zu rendern
- **Neu laden-Button**: Lädt die Seite neu (`window.location.reload()`)
- **ARIA**: `role="alert"` und `aria-live="assertive"` für Screenreader
```tsx
import { ErrorBoundary } from '@/components/common/ErrorBoundary';
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
// Custom Fallback
<ErrorBoundary fallback={(error, retry, traceId) => <CustomErrorUI error={error} retry={retry} traceId={traceId} />}>
<MyComponent />
</ErrorBoundary>
```
### PluginErrorBoundary
Plugin-Seiten werden zusätzlich durch `PluginErrorBoundary` in `PluginLoader.tsx` umschlossen. Diese zeigt den Plugin-Namen im Fehlerfall und loggt den Fehler mit `pluginName` und `trace_id`.
### PluginRouteRenderer
Der `PluginRouteRenderer` (Catch-All Route) ist mit `ErrorBoundary` umschlossen, sodass Plugin-Seiten-Fehler nicht die gesamte App crashen.
---
## 11. Print & PDF-Export
### PrintButton
Die `PrintButton`-Komponente in `components/common/PrintButton.tsx` bietet ein Dropdown mit Druck- und PDF-Export-Funktionen:
- **Drucken**: Ruft `printElement(targetId)` oder `printCurrentPage()` auf
- **Als PDF**: Ruft `exportToPDF(targetId, filename)` auf (Browser-Print-to-PDF)
- **Print-CSS**: `public/print.css` mit `@media print` Regeln — versteckt Sidebars, TopBar, Buttons und formatiert Tabellen/Card für Druck
```tsx
import { PrintButton } from '@/components/common/PrintButton';
<PrintButton targetId="contact-detail" filename="kontakt-john-doe" />
```
Verwendung in: `ContactDetailPage`, `Reports`, `Calendar`.
---
## 12. API-Dokumentation (Swagger UI)
Die `ApiDocsPage` in `pages/ApiDocs.tsx` bettet die FastAPI Swagger UI in einem iframe ein:
- Route: `/api-docs` (erfordert `settings:read` Permission)
- iframe src: `/docs` (FastAPI Swagger UI)
- External-Link: Öffnet `/docs` in neuem Tab
- Vollbild-iframe mit Header-Leiste
---
## 13. Notification-System
### NotificationBell + Dropdown
Die `NotificationBell` in `components/layout/NotificationBell.tsx` zeigt ungelesene Benachrichtigungen mit:
- **Unread-Badge**: Roter Zähler (max. 99+) mit 30s Polling
- **Dropdown**: Liste der Benachrichtigungen, „Alle als gelesen"-Button
- **System-Channel-Link**: Öffnet den Kommunikations-System-Channel unter `/communication?channel=system`
- **Alle anzeigen**: Navigiert zu `/settings/notifications`
Das Backend delegiert `/notifications` an den Kommunikations-System-Channel (`post_system_message`).
---
## 14. Accessibility (A11Y) Patterns
### Verbindliche ARIA-Regeln
| Element | Attribut | Wert |
|---|---|---|
| Buttons | `aria-label` | Beschreibung der Aktion |
| Icon-only Buttons | `aria-label` + `aria-hidden` auf Icon | Icon dekorativ |
| Dropdowns | `aria-haspopup="menu"` + `aria-expanded` | true/false |
| Menüs | `role="menu"` + `aria-label` | Menüname |
| Error-Bereiche | `role="alert"` + `aria-live="assertive"` | Für Screenreader |
| Navigation | `aria-label` auf `<nav>` und `<aside>` | „Hauptnavigation" etc. |
| Skip-Link | `sr-only focus:not-sr-only` | „Zum Hauptinhalt springen" |
### Touch Targets
Alle interaktiven Elemente müssen `min-h-touch` (44px) und `min-w-touch` (44px) haben:
```tsx
<button className="min-h-touch min-w-touch ...">Klick</button>
```
### Focus-Management
- Sichtbarer Focus-Ring: `focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500`
- Skip-Link in `App.tsx`: `sr-only focus:not-sr-only`
- `main`-Element mit `tabIndex={-1}` für Tastatur-Fokus
---
## 15. Datei-Struktur
```
frontend/src/