dak.c2s/docs/plans/2026-02-26-state-management-design.md
CCS Admin d4420500e5 docs: add state management refactoring design (TanStack Query)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 18:11:55 +00:00

101 lines
3.6 KiB
Markdown

# State Management Refactoring — Design
## Ziel
Boilerplate reduzieren und Zukunftssicherheit schaffen durch Einführung von TanStack Query für Server-State-Management. UI-State bleibt bei useState/Context.
## Ansatz
TanStack Query (`@tanstack/react-query`) übernimmt alles was mit API-Daten zu tun hat: Fetching, Caching, Refetch, Mutations mit automatischer Cache-Invalidierung.
## Architektur
### Provider-Hierarchie
```
App.tsx
└── QueryClientProvider (NEU)
└── AuthProvider (bleibt)
└── BrowserRouter
└── Routes...
```
### Globale Query-Konfiguration
- `staleTime: 30s` — Daten gelten 30 Sekunden als frisch
- `retry: 1` — Einmal wiederholen bei Fehler
- `refetchOnWindowFocus: false` — Kein automatischer Refetch bei Tab-Wechsel
### Was migriert wird
Alle `useEffect(() => api.get(...), [deps])` Patterns → `useQuery()`
Alle `api.put/post` in Save-Handlern → `useMutation()` mit Cache-Invalidierung
useNotifications Polling → `useQuery()` mit `refetchInterval: 60000`
### Was bleibt
- AuthContext (Token + User)
- useTheme
- UI-State (Modals, Sidebar-Toggle, Filter-Inputs) — useState
- useInlineEdit — bleibt als Hook, nutzt aber TanStack Mutations intern
## Custom Query-Hooks
Domänenspezifische Hooks in `frontend/src/hooks/`:
| Hook | Ersetzt | Datei |
|------|---------|-------|
| `useCases(filters)` | useState+useEffect in CasesPage | `hooks/useCases.ts` |
| `useCase(id)` | Einzelfall-Fetch in CaseDetail | `hooks/useCases.ts` |
| `useCaseMutation()` | api.put in useInlineEdit | `hooks/useCases.ts` |
| `useDashboard(jahr)` | useState+useEffect in DashboardPage | `hooks/useDashboard.ts` |
| `useNotifications()` | Bestehender Polling-Hook | `hooks/useNotifications.ts` |
| `useUsers()` | useState+useEffect in AdminUsersPage | `hooks/useUsers.ts` |
| `useDisclosures(status)` | useState+useEffect in DisclosuresPage | `hooks/useDisclosures.ts` |
| `useAuditLog(filters)` | useState+useEffect in AdminAuditPage | `hooks/useAuditLog.ts` |
| `useImportLogs(page)` | useState+useEffect in ImportLogTab | `hooks/useImportLogs.ts` |
### Query Key Konvention
- `['cases']` — alle Fälle
- `['cases', { page, search, jahr, fallgruppe }]` — gefilterte Liste
- `['cases', id]` — Einzelfall
- `['dashboard', jahr]` — Dashboard-KPIs
- `['notifications']` — Benachrichtigungen
- `['users']` — Admin-Benutzerliste
- `['disclosures', status]` — Disclosure-Anfragen
- `['audit-log', filters]` — Audit-Log
- `['import-logs', page]` — Import-Logs
## Mutations & Cache-Invalidierung
| Mutation | Invalidiert |
|----------|-------------|
| Case updaten | `['cases']` |
| KVNR setzen | `['cases']` |
| ICD setzen | `['cases']`, `['dashboard']` |
| Coding setzen | `['cases']`, `['dashboard']` |
| Disclosure genehmigen/ablehnen | `['disclosures']`, `['notifications']` |
| Notification lesen | `['notifications']` |
| User anlegen/bearbeiten | `['users']` |
useInlineEdit nutzt intern `useMutation()` statt direkter `api.put()`. Der `onCaseSaved`-Callback durch den Komponentenbaum entfällt komplett.
## Migrations-Strategie
Schrittweise Migration, Page für Page:
### Phase 1: Setup
- `pnpm add @tanstack/react-query @tanstack/react-query-devtools`
- `QueryClientProvider` in App.tsx
### Phase 2: Einfache Pages
- DashboardPage, ReportsPage, AdminAuditPage, DisclosuresPage
### Phase 3: Mittlere Komplexität
- AdminUsersPage, ImportLogTab, useNotifications
### Phase 4: CasesPage (komplexeste)
- useCases, useCaseMutation, useKvnrMutation, useIcdMutation
- useInlineEdit intern auf Mutations umstellen
- onCaseSaved-Callback entfernen