# M2 – Einheitliches State-Management: Ist-Analyse + Umbauplan

> **STATUS 2026-07-06: reine Analyse, noch KEIN Umbau.** Grundlage für den
> ROADMAP-M2-Punkt „Einheitliches State-Management (Riverpod konsequent,
> keine Misch-Patterns)". Die Schritte 1–2 unten betreffen den heiligen
> Call-Pfad und sind GESPERRT, bis Bernds Klick-Test des Call-Piloten
> (`docs/PC_TESTPLAN.md` Abschnitt 8) grün ist – vorher nur Schritt 3.

## Ist-Stand (repo-weit erhoben, 2026-07-06)

Riverpod ist bereits das dominante Muster: rund 50 Provider –
`StateProvider` für UI-Zustand, `StreamProvider` auf `client.onSync`,
`FutureProvider` (Client, Update-Info), `StateNotifierProvider` für die
Prefs-Notifier (`BoolPref`/`StringSetPref` in `core/settings_prefs.dart`).
`ValueNotifier`/eigene `StreamController` gibt es NICHT. Lokales
`setState` in Widgets für rein ephemeren Zustand (Hover, Dialog-Schritte,
Textfelder) ist normales Flutter und zählt hier bewusst NICHT als
Misch-Pattern.

Gefundene Misch-Patterns, nach Gewicht:

1. **Call-Schicht: Singletons + ChangeNotifier hinter den Fassaden.**
   `LiveKitCallManager.instance` (static final Singleton,
   `features/voice_channel/livekit_call_manager.dart:17`) und
   `PyramidVoipManager._instance` (nullable static,
   `features/call_signaling/voip_manager.dart:17`; konstruiert im
   Kompositions-Punkt `core/matrix_client.dart:66–71`). Die Modul-Provider
   (`voiceChannelProvider`/`callSignalingProvider`) geben nur die
   Singletons zurück. Das ist die im Pilot BEWUSST gewählte Zwischenform
   (Verhaltensgleichheit vor Schönheit). Eigentliches Problem: UI-Zustand
   (Mute-Flags, Teilnehmer, Renderer, Qualitätswahl) lebt mutierbar IN den
   Managern und wird per `notifyListeners()` grob-granular publiziert.
2. **Voice-UI-Zustand außerhalb des Moduls:** `activeVoiceRoomIdProvider`
   und `voiceParticipantsProvider` liegen in `core/app_state.dart`
   (Kopplungspunkt laut Ist-Analyse), werden aber von Rooms-Panel und
   Mini-Call-Widget gesetzt/gelesen und gehören fachlich ins
   `voice_channel`-Modul (Join-Zustand + Presence sind Modulsache).
3. **`MediaCache.instance`** (`core/media_cache.dart:19`): reines
   Singleton, kein UI-Zustand, nur Cache. Nutzer sind `widgets/mxc_image.dart`
   (7 Stellen, Widgets – leicht umstellbar) UND
   `features/chat/message/message_media.dart` (7 Stellen, darunter der
   statische Wrapper `_DocBytesCache` für Dokument-Vorschauen, dessen
   Aufrufer keinen `ref`-Zugang haben). Eine Umstellung müsste `ref`/die
   Cache-Instanz durch die statischen Helfer der Chat-Timeline fädeln –
   und genau dieser Code (Download-/Entschlüsselungs-Fehlerpfade) ist
   laut PC_TESTPLAN Abschnitt 3 der am wenigsten geprüfte Teil der App.
4. **Push/Notifications:** modul-globale Mutable-Zustände in
   `core/notification_service.dart` (`_windowsNotifs`-Map, Plugin-Globals)
   und direkte `SharedPreferences`-Zugriffe in `background_push.dart`/
   `fcm_push_service.dart`. Das ist dem Background-Isolate-Zwang
   geschuldet (siehe Schnitt-Doc Punkt 8 + Memory „Pyramid Push") –
   **bewusst KEIN Umbau-Kandidat**, nur hier dokumentiert.

Bereits erledigt im Zuge dieser Analyse: der seit dem Call-Piloten tote
`incomingCallProvider` ist aus `app_state.dart` entfernt (41bcaf2).

## Zielbild

- `core/app_state.dart` enthält nur noch ECHTEN App-weiten UI-Zustand
  (Theme, Layout/Panels, Navigation, Toast, Space-Auswahl) – kein
  Feature-Fachzustand.
- Feature-Zustand lebt im jeweiligen Modul hinter dessen Provider;
  andere Module lesen ihn NUR über die öffentliche Schnittstelle.
- Kein `.instance`-Zugriff über Modulgrenzen; Konstruktion ausschließlich
  im Kompositions-Punkt bzw. im Provider des Moduls.
- ChangeNotifier ist als Übergangsform ok; Endzustand der Call-Module ist
  ein immutables Zustandsobjekt (z. B. `VoiceChannelState`) pro Modul,
  das der Provider publiziert, plus Kommando-Methoden auf dem Service
  (entspricht dem Schnitt-Doc-Entwurf, dort als Stream skizziert).

## Schrittfolge (Reihenfolge = Priorität)

1. **[GESPERRT bis Klick-Test] UI-State aus den Managern herauslösen:**
   je Call-Modul ein immutables Zustandsobjekt + `Notifier`/
   `StateNotifier`, Manager wird interne Implementierung ohne
   UI-Zustand. Das ist der bereits in PROGRESS.md zurückgestellte
   Logik-Umbau – NICHT vorher anfangen (heiliger Call-Pfad, ein
   ungetesteter Umbau liegt schon auf dem Stapel).
2. **[GESPERRT bis Klick-Test] `activeVoiceRoomIdProvider` +
   `voiceParticipantsProvider` ins `voice_channel`-Modul umziehen**
   (zusammen mit `kVoicePresenceType`). Mechanisch klein, aber
   Call-Pfad-nah – sinnvoll im selben Zug wie Schritt 1.
3. **[ZURÜCKGESTELLT] `MediaCache` hinter `Provider<MediaCache>`:**
   Erst als „risikoarm, jederzeit" eingestuft – das stimmte NICHT
   (Korrektur 2026-07-06, siehe Ist-Stand Punkt 3: auch die Chat-Timeline
   hängt dran, inkl. statischer Helfer ohne `ref`). Gehört in den Zug des
   `chat_timeline`-Moduls (Schnitt-Doc Punkt 9) bzw. frühestens nach dem
   Klick-Test von PC_TESTPLAN Abschnitt 3 – nicht als Lückenfüller.
4. **[kein Umbau] Push/Notifications:** bleibt wie es ist
   (Isolate-Zwang); nur bei ohnehin anstehenden Push-Arbeiten die
   Prefs-Zugriffe auf die `Prefs`-Fassade ziehen (Schnitt-Doc Punkt 6).

Abhak-Kriterium für den ROADMAP-Punkt: Schritte 1–3 umgesetzt und die
Kernflows (Login, Raum, Nachricht, Voice-Join) nach jedem Schritt
praktisch geprüft; Punkt 4 braucht nur den Doku-Vermerk (steht hiermit).
