docs: M2-Modul-Schnitt definieren (docs/M2_MODULE_SCHNITT.md)
Öffentliche Schnittstellen für call_signaling, voice_channel, call_ui, settings, verification, storage u.a. entworfen. Wichtigste Erkenntnis: "Calls" ist architektonisch zwei getrennte Module (Matrix-VoIP vs. LiveKit-SFU-Voice-Channels), keine gemeinsame Fassade. Korrigiert nebenbei einen falschen Ist-Analyse-Befund (rooms_provider-Import war fälschlich als toter Code eingestuft).
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
# M2 – Modul-Schnitt (Entwurf)
|
||||
|
||||
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):**
|
||||
```dart
|
||||
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):**
|
||||
```dart
|
||||
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 2921–4545 (SAS-Dialog,
|
||||
QR-Anzeige, Emoji-Vergleich, Recovery-Key-Flow).
|
||||
```dart
|
||||
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`
|
||||
```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.
|
||||
Reference in New Issue
Block a user