# 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