Files
pyramid/docs/M2_MODULE_SCHNITT.md

9.5 KiB
Raw Permalink Blame History

M2 Modul-Schnitt (Entwurf)

STATUS 2026-07-06: Pilot (Schritt 1) UMGESETZT. Die Module call_signaling (lib/features/call_signaling/: CallSignalingService

  • callSignalingProvider + Implementierung voip_manager.dart) und voice_channel (lib/features/voice_channel/: VoiceChannelService + voiceChannelProvider + Implementierung livekit_call_manager.dart) existieren; ALLE Konsumenten (Shell, Call-UI, Rooms-Panel, Chat-Header, Settings) gehen nur noch über die Provider/Interfaces, kein direkter Implementierungs-Import mehr (einzige dokumentierte Ausnahme: Kompositions-Punkt matrix_client.dart). Bewusste Abweichungen vom Entwurf unten (Verhaltensgleichheit vor Schönheit, heiliger Call-Pfad): ChangeNotifier statt Streams, Methodennamen wie im Bestand (startCall/hangUp statt join/leave), CallSession/LiveKit-Room bleiben in den Schnittstellen sichtbar, weil die UI direkt rendert. Echter Call-/Voice-Channel-Test steht aus (Gerät bzw. Klick-Test) siehe PROGRESS.md 2026-07-06. Schritte 25 unten sind weiter offen.

Nachtrag 2026-07-06 (zweite PC-Session): call_ui ist jetzt ein eigenes Modul (lib/features/call_ui/, reine Umbenennung von features/call/; konsumiert weiterhin nur die zwei Service-Interfaces). Außerdem ist der storage-Teilschritt für die Call-Module erledigt: die voice_*-Prefs (Geräte + Ausgabelautstärke) laufen über die neue VoicePrefs-Kapsel in core/settings_prefs.dart (Punkt 6 unten) kein direkter SharedPreferences-Zugriff mehr in voip_manager.dart/ livekit_call_manager.dart/settings_voice.dart, Keys unverändert. „UI-State aus den Managern herauslösen" wartet bewusst auf Bernds Klick-Test des Piloten (heiliger Call-Pfad).

Stand: 2026-07-03. Reine Schnittstellen-Planung, noch kein Umbau. Grundlage: Ist-Analyse in PROGRESS.md (Eintrag „M2: Ist-Analyse der Architektur geschrieben"). Leitprinzip (Bernd, CLAUDE.md): jedes Modul muss sich in einem Jahr komplett neu schreiben lassen, ohne andere Module anzufassen. Andere Module dürfen daher nur die hier genannte öffentliche Schnittstelle importieren, nie interne Dateien.

Korrektur zur Ist-Analyse: der Import von rooms_provider.dart in app_state.dart ist kein toter Altlast-Import, wie dort vermutet voiceParticipantsProvider (Zeile 160) nutzt roomListProvider daraus, um bei jedem Sync neu zu bauen. Der Eintrag in PROGRESS.md wird beim nächsten Durchgang korrigiert.

Wichtige Erkenntnis vor dem Schnitt: „Calls" ist eigentlich ZWEI Features

Beim genaueren Lesen von voip_manager.dart und livekit_call_manager.dart zeigt sich: das sind keine zwei Hälften derselben Sache, sondern zwei unabhängige Call-Mechanismen, die zufällig beide „Call" heißen:

  • PyramidVoipManager natives Matrix-VoIP (m.call.*-Events über das matrix-SDK, direkte 1:1-WebRTC-Peer-Connection, kein SFU). Vermutlich für spontane 1:1-Anrufe gedacht.
  • LiveKitCallManager SFU-basierte, dauerhafte Voice-Channels (LiveKit- Server-Raum, Presence über Matrix-State-Events, Screensharing, Mehrpersonen). Das ist der Discord-artige Voice-Channel aus M3/M4.

Beide Module sollten getrennt bleiben, nicht zu einem „calls"-Modul verschmolzen werden. Nur die UI (call_ui) darf beide kennen, falls sie gemeinsam dargestellt werden müssen (z. B. „du bist in einem Voice-Channel, jemand ruft dich per 1:1-VoIP an").

Modul-Liste mit öffentlicher Schnittstelle (Entwurf)

1. call_signaling (Matrix-1:1-VoIP)

Ersetzt: core/voip_manager.dart Öffentliche Schnittstelle (Ausschnitt):

abstract class CallSignalingService {
  Stream<CallSession?> get currentCallStream;
  bool get isMicMuted;
  bool get isCameraMuted;
  Future<void> startCall(String roomId, {bool video});
  Future<void> hangup();
  Future<void> toggleMic();
  Future<void> toggleCamera();
  Future<void> toggleScreenSharing(BuildContext? context);
  RTCVideoRenderer get localRenderer;   // bleibt vorerst WebRTC-typisiert,
  RTCVideoRenderer get remoteRenderer;  // da UI direkt rendert
}

Interna (ICE-Server-Merge, MediaDevicesWrapper, Geräte-Prefs aus SharedPreferences) bleiben privat im Modul. Geräte-Prefs sollten künftig über die storage-Fassade laufen statt direktem SharedPreferences-Zugriff (aktuell Zeile 260, 447).

2. voice_channel (LiveKit-SFU, Discord-artige Kanäle)

Ersetzt: core/livekit_call_manager.dart Öffentliche Schnittstelle (Ausschnitt):

abstract class VoiceChannelService {
  Stream<VoiceChannelState> get stateStream; // isActive, isMuted, participants…
  Future<void> join({required String roomName, required String matrixRoomId, ...});
  Future<void> leave();
  Future<void> toggleMute();
  Future<void> toggleDeafen();
  Future<void> toggleCamera();
  Future<void> toggleScreenShare();
  Future<void> setPublishQuality(String key);   // Streamer-Seite (M4)
  Future<void> setSubscribeQuality(String key); // Empfänger-Seite (M4)
  Future<void> setOutputVolume(double v);
}

Presence-Writing (_writePresence, Matrix-State-Event io.pyramid.voice.presence) bleibt intern, aber nutzt eine injizierte Client-Referenz statt globalem Singleton-Zugriff macht das Modul für Tests austauschbar.

3. call_ui

Ersetzt: features/call/voice_channel.dart, features/call/mini_call_widget.dart Konsumiert ausschließlich CallSignalingService + VoiceChannelService über Riverpod-Provider (callSignalingProvider, voiceChannelProvider). Keine direkten Importe von core/voip_manager.dart/core/livekit_call_manager.dart mehr heute importieren chat_view.dart, matrix_client.dart und settings_modal.dart diese Dateien direkt, das entfällt.

4. settings (aufgesplittet)

Kein eigenes fachliches Modul, sondern reine Aggregations-UI. Jede Sektion wird eine eigene Datei/Klasse mit einer schmalen Widget build(...)-Fläche, die ihrerseits nur die Provider ihres Fachmoduls konsumiert (z. B. _VoiceSection nutzt künftig voiceChannelProvider/callSignalingProvider statt der Manager direkt). Vorschlag für Dateien: settings/profile_section.dart, settings/notifications_section.dart, settings/appearance_section.dart, settings/sessions_section.dart, settings/account_section.dart, settings/voice_section.dart, settings/about_section.dart.

5. verification (neu, aus Settings herausgelöst)

Quelle: widgets/settings_modal.dart Zeile 29214545 (SAS-Dialog, QR-Anzeige, Emoji-Vergleich, Recovery-Key-Flow).

abstract class VerificationService {
  Future<void> startSasVerification(DeviceKeys device);
  Future<void> confirmSas();
  Future<void> declineSas();
  Stream<VerificationStep> get stepStream;
}

Eigenständig, weil SAS/QR-Verifikation künftig auch außerhalb der Settings gebraucht werden könnte (z. B. beim Login auf einem neuen Gerät bootstrap_dialog.dart macht heute schon etwas Ähnliches separat).

6. storage (Fassade, kein Rewrite)

Ausbau von: core/settings_prefs.dart

abstract class Prefs {
  Future<bool> getBool(String key, {bool fallback});
  Future<void> setBool(String key, bool value);
  // … String, double, StringSet analog zu BoolPref/StringSetPref
}

Ziel ist NICHT, SharedPreferences zu ersetzen, sondern die bereits vorhandene BoolPref/StringSetPref-Abstraktion zur Pflicht zu machen. Die 12 identifizierten Direktzugriffsstellen (u. a. voip_manager.dart:260, livekit_call_manager.dart:246, settings_modal.dart:1804/1860/1870) werden schrittweise umgestellt nicht in diesem Schritt, sondern sobald das jeweilige Modul (z. B. call_signaling) ohnehin angefasst wird. Krypto-/Access-Token-Speicherung (flutter_secure_storage, matrix_client.dart) bleibt bewusst außen vor hängt an der noch offenen SQLCipher-Frage (M1) und wird dort separat behandelt, nicht hier.

7. auth

Dateien: features/auth/login_notifier.dart, login_page.dart, server_page.dart, bootstrap_dialog.dart (Bootstrap-Teil, Verifikations-Teil wandert ggf. zu verification, s. o.). Schnittstelle bleibt der bereits vorhandene matrixClientProvider/login_notifier-Zustandsautomat heute schon relativ sauber gekapselt, kein akuter Handlungsbedarf.

8. push

Dateien: core/background_push.dart, core/fcm_push_service.dart, core/notification_service.dart. Bereits über eigene Dateien getrennt (nativ vs. Flutter-Engine, siehe Memory „Pyramid Push"). Einzige Lücke: eigener sqflite-Zugriff in background_push.dart statt gemeinsamer DB-Schicht bewusst so gewollt (Background-Isolate-Zwang), daher kein Refactoring-Kandidat, nur dokumentieren.

9. chat_timeline / rooms

Niedrigste Priorität für den Pilot-Umbau, da laut Ist-Analyse strukturell am wenigsten verwoben (Hauptproblem dort ist Dateigröße + Duplikate, nicht Modul-Kopplung). Wird nach dem Call-Pilot angegangen.

Reihenfolge-Vorschlag für die Umsetzung

  1. Pilot: call_signaling + voice_channel + call_ui (Punkt „Call-Schicht entwirren" in ROADMAP.md) kleinster klar abgegrenzter Schnitt, deckt gleich zwei ROADMAP-Punkte ab (Modul-Schnitt beweisen + Call-Entwirrung).
  2. settings_modal.dart aufsplitten (reine Datei-Teilung, geringes Risiko, keine Verhaltensänderung).
  3. verification aus Settings herauslösen.
  4. storage-Fassade schrittweise erzwingen, immer im Zuge anderer Umbauten.
  5. chat_timeline/rooms zuletzt.

Bernd-Entscheidung nötig: siehe Frage in PROGRESS.md ob Punkt 1 (Call-Pilot) so wie hier vorgeschlagen als Nächstes umgesetzt werden soll.