# Pyramid – Roadmap Die lange Liste. Wird von oben nach unten abgearbeitet (Arbeitszyklus siehe `CLAUDE.md`). Reihenfolge = Priorität: erst Ordnung & Sicherheit (Datenverlust-Risiken!), dann das große Refactoring, dann Calls/Streaming/Chat-Features, dann Feinschliff. Punkte abhaken (`[x]`), wenn erledigt UND in `PROGRESS.md` protokolliert. ## M0 – Backup & Ordnung - [x] Vollbackup vor dem Refactoring (2026-07-03 → `MatrixPi\backups\pyramid-kopie_backup_2026-07-03.tar.gz`) - [x] Die ~140 uncommitteten Dateien sichten, in thematische Commits aufteilen, zu Gitea pushen (Sicherungs-Commit 25ed765 + Folge-Commits bis 74d38fd; Arbeitsbaum ist jetzt sauber) - [x] `flutter analyze` komplett sauber bekommen und sauber halten (nur noch 1 bewusst zurückgestellter Hinweis, siehe PROGRESS.md 2026-07-03) - [x] `lib/features/call/` vs. `lib/features/calls/` (leer?) klären – Leiche entfernen (geprüft: `calls/` existiert nicht mehr, nur `call/` mit den echten Dateien) - [x] README.md durch echte Projektbeschreibung ersetzt (74d38fd) - [x] **Fable-5-Qualitäts-Review aller bisherigen Autopilot-Commits (Bernds Wunsch, VOR allem anderen):** ERLEDIGT – siehe Abschnitt „Fable-5-Review" oben in PROGRESS.md. (a) alle 6 Gott-Datei-Aufteilungen unabhängig verifiziert (Zeilen-Multiset, part-Bezüge): korrekt, verlorene Erklärkommentare waren mit f9979e4 schon wiederhergestellt; (b) Uta-Logout-/Push-Fix gegen matrix-SDK 6.2.0 verifiziert: Analyse richtig, Lücke (SDK eskaliert Refresh-Fehler zu logout()+clear()) war mit 891f348 (onSoftLogout-Guard) geschlossen, Guard heute gegenverifiziert; (c) Lint-Fixes verhaltensäquivalent (onReorderItem gegen Flutter-SDK geprüft, kein Off-by-One); (d) abgehakte Punkte stimmen mit dem Code überein. Alles weiterhin UNGETESTET (Pi) → PC-Praxistest bleibt. - [x] **Uta-Random-Logout untersuchen:** UNGETESTET (Pi) – Ursache im matrix-SDK gefunden + Fix committet (63e4919, 9dc83f7), siehe PROGRESS.md 2026-07-03. Nächster PC-Lauf MUSS den vollen Kreislauf praktisch prüfen (Login → Nachrichten → Logout → erneuter Login → alte Nachrichten lesbar?), erst dann gilt der Punkt als wirklich erledigt. - [x] **REGRESSION: Push-Benachrichtigungen werden nicht mehr entschlüsselt** – UNGETESTET (Pi), sehr wahrscheinlich DIESELBE Ursache wie der Uta-Random-Logout-Bug (bereits mit 9dc83f7 mitgefixt), siehe PROGRESS.md 2026-07-03. Auf echtem Gerät prüfen: nach Neu-Login (für den Refresh-Token) eine Weile laufen lassen und beobachten, ob Push-Nachrichten wieder mit echtem Text statt nur „Neue Nachricht"-Platzhalter ankommen. Falls das Problem weiterhin auftritt, liegt eine zweite, unabhängige Ursache vor (z. B. fehlende Megolm-Schlüssel/Key-Sharing) – dann `docs/NOTIFICATIONS.md` + Memory „Pyramid Push" erneut konsultieren und die dort gelisteten 3 Fallstricke der Hintergrund-Entschlüsselung gegenprüfen. - [ ] **Sichere Speicherung von Access-Token & Krypto-DB: LÜCKE GEFUNDEN.** `sqlcipher_flutter_libs` steht zwar in `pubspec.yaml`, wird aber nirgends benutzt – `matrix_client.dart` und `background_push.dart` öffnen die `pyramid.sqlite` (Access-Token, gepickelter Olm-Account, Nachrichten) über den normalen `sqflite`/`sqflite_common_ffi`-Factory, also **unverschlüsselt** auf der Platte. Bewusst NICHT blind auf dem Pi gefixt: eine Umstellung auf SQLCipher braucht eine Migration für bereits bestehende Klartext-DBs (Utas Gerät!) – ohne Testgerät hier zu riskant für „Kein Datenverlust". Siehe PROGRESS.md 2026-07-03 + Frage an Bernd. **Umsetzungsplan liegt fertig in `docs/SQLCIPHER_MIGRATION.md`** (2026-07-03, gegen Code und SDK verifiziert) – PC-Termin kann direkt damit starten. - [x] Key-Backup einrichten-Flow: bereits vorhanden (`bootstrap_dialog.dart`, wird automatisch getriggert wenn Cross-Signing fehlt, `app_shell.dart`) - [x] Key-Backup wiederherstellen-Flow: bereits vorhanden (`bootstrap_dialog.dart`, `BootstrapState.askUnlockSsss` fragt nach Recovery-Key auf neuem Gerät) - [x] Logout-Schutz: Warnung mit Klartext-Folgen, wenn Key-Backup fehlt (b5762ea) - [x] Geräte-/Sessionverwaltung in den Einstellungen: bereits vorhanden (`_SessionsSection` in `settings_modal.dart` – Liste, Umbenennen, Verifizieren per SAS/QR, Abmelden, Massen-Abmeldung mit Passwort-Reauth) - [ ] **SICHERHEIT: Dashboard-Admin-Endpoints – akutes Loch mit Interims-Gate geschlossen (2026-07-04), Fernzugriffs-Entscheidung offen** (Fable-5-Review (o)). `server.py` nimmt `/api/ban`, `/api/unban`, `/api/toggle-registration`, `/api/create-invite`, `/api/run-stats` jetzt NUR noch aus Heimnetz/localhost an (Socket-IP + Cloudflare-Header-Check); Fremde aus dem Internet bekommen 403. Headless verifiziert (öffentlich 403, Heimnetz ok, App-Endpoints unverändert), siehe PROGRESS.md 2026-07-04. **Bernds Dashboard läuft im Heimnetz unverändert: `http://192.168.178.71:8080/stats.html`.** Offen bleibt: Will Bernd die Admin-Buttons auch von unterwegs? Dann Weg A (Cloudflare Access, empfohlen – schließt auch die weiterhin öffentliche Nutzerlisten-Ansicht) oder Weg B (`DASH_TOKEN`), Plan + Restrisiken in `docs/DASHBOARD_AUTH_HARDENING.md`. - [x] **LiveKit-Token-Route server-seitig gebaut + verifiziert** (Fable-5-Review (n), PROGRESS.md 2026-07-04). `POST /api/livekit-token` läuft live in `server.py` (whoami-Auth, stdlib-HS256-Minting aus `livekit.yaml`), headless geprüft (401/400/413/200, JWT-Signatur unabhängig gegen `livekit.yaml` gültig, Identität = geprüfte user_id). **Offen:** Client-Umstellung (`livekit_token.dart`/ `livekit_call_manager.dart`) + Secret-Rotation – beides PC/Gerät (heiliger Call-Pfad), siehe `docs/LIVEKIT_TOKEN_MIGRATION.md`. - [ ] **SICHERHEIT: geleakte Secrets rotieren + aus dem Client holen** (Fable-5-Review (k), PROGRESS.md 2026-07-04). Das Gitea-Repo ist öffentlich (`private:false`), und es lagen vier aktive Secrets drin – teils schon bereinigt (release.ps1, Admin-Doku), aber: - **Rotieren (Pflicht, sie sind bereits geleakt):** Matrix-Server-Admin-Token `J5lax…` (noch gültig, voller Admin!), Gitea-Release-Token, LiveKit-`apiKey`/ `apiSecret`, Giphy-Key. Alte jeweils widerrufen. - **LiveKit-Token server-seitig minten:** kleiner Token-Endpoint auf dem Pi, damit `apiSecret` aus `lib/core/livekit_token.dart` verschwindet (App holt nur das JWT). **Umsetzungsplan liegt fertig in `docs/LIVEKIT_TOKEN_MIGRATION.md`** (2026-07-04, gegen Code + Pi-Konfig geschrieben) – braucht echten Call-Test auf einem Gerät. - **E2EE-Diagnose-Upload: ERLEDIGT (2026-07-04).** Der Dashboard-Server auf dem Pi (`/home/steggi/matrix/server.py`) benutzte für `/api/e2ee-diagnostics` denselben String wie den Matrix-Admin-Token – deshalb steckte er im Client. Jetzt hat das Diagnose-Endpoint einen eigenen, eng begrenzten Token (`DIAG_TOKEN`, hängt nur an den Log an, keine Admin-Rechte); `settings_encryption.dart` benutzt diesen. Der **Admin-Token ist damit nicht mehr im App-Code** (per `grep` bestätigt). Server + Client umgestellt und verifiziert (neuer Token 200, alter Admin-Token 403). Der Admin-Token selbst muss trotzdem noch rotiert werden (steht oben, Bernds Sache). - Optional: Git-History-Rewrite (Bernds Entscheidung, Repo ist auch Backup). - **ACHTUNG bei „Repo einfach privat schalten":** Der In-App-Updater (`lib/core/update_checker.dart`) holt Releases **anonym** über die öffentliche Gitea-API (`/api/v1/repos/steggi/pyramid/releases`). Repo privat = Utas App findet keine Updates mehr (und ein Fix ließe sich nicht mehr per Update verteilen – Henne-Ei). Erst Updater-Strategie klären, dann Sichtbarkeit ändern. - [ ] Härtetest dokumentieren: Login → Nachrichten → Logout → Login neu → alles noch lesbar (gehört zum ausstehenden PC-Praxistest der beiden Bugfixes oben; kompletter Ablauf inkl. aller aufgelaufenen UNGETESTET-Punkte steht jetzt in `docs/PC_TESTPLAN.md` – dort abarbeiten und abhaken) ## M2 – Das große Refactoring (erst nach M0/M1!) Ziel: gleiche Funktionen, saubere **modulare** Struktur – als Fundament für alles Folgende. Leitprinzip (Bernd): austauschbare Bausteine – jedes Modul muss sich komplett neu schreiben lassen, ohne dass andere Module angefasst werden müssen. - [x] Ist-Analyse geschrieben (PROGRESS.md 2026-07-03): Gott-Datei `settings_modal.dart` (5541 Zeilen/50+ Klassen), Call-Schicht ohne gemeinsame Fassade (4 Module importieren `voice_channel.dart` direkt), `app_state.dart` als Kopplungspunkt aller Features, keine gemeinsame Storage-Schnittstelle (12 direkte `SharedPreferences`-Zugriffe), toter Code (`message_bubble.dart`) + Duplikate (`_formatTime`/`_formatDate` 3-fach). 8 Modul-Kandidaten dokumentiert. - [x] Modul-Schnitt definiert (`docs/M2_MODULE_SCHNITT.md`, PROGRESS.md 2026-07-03): „Calls" ist architektonisch zwei getrennte Module (`call_signaling` = Matrix-1:1-VoIP, `voice_channel` = LiveKit-SFU-Kanäle) + `call_ui`; außerdem `settings` (aufgesplittet), `verification` (neu, aus Settings herausgelöst), `storage` (Ausbau `settings_prefs.dart`), `auth`, `push`, `chat_timeline`/`rooms`. Umsetzungsreihenfolge vorgeschlagen, wartet auf Bernds Go für den Call-Pilot (Frage in PROGRESS.md). - [ ] Call-Schicht entwirren: EINE klare Zuständigkeit pro Klasse (Signalisierung / LiveKit-Verbindung / UI-State sauber getrennt) - [ ] Einheitliches State-Management (Riverpod konsequent, keine Misch-Patterns) - [x] Toten Code & Duplikate entfernen, Ordnerstruktur vereinheitlichen (PROGRESS.md 2026-07-03: `message_bubble.dart` tot entfernt, doppelte `_formatTime` in `message_group.dart` zusammengeführt; alle 6 in der Ist-Analyse gefundenen Gott-Dateien per `part`/`part of` in thematische Dateien aufgeteilt – `widgets/settings_modal.dart` (5541→270 Zeilen, 12 Teile unter `widgets/settings/`), `features/chat/message_group.dart` (2775→30 Zeilen, 7 Teile unter `features/chat/message/`), `features/rooms/rooms_panel.dart` (2555→31 Zeilen, 8 Teile unter `features/rooms/panel/`), `features/spaces/space_admin_dialog.dart` (2278→19 Zeilen, 6 Teile unter `features/spaces/admin/`), `features/chat/chat_view.dart` (2116→33 Zeilen, 6 Teile unter `features/chat/view/`), `features/chat/document_viewer.dart` (1773→20 Zeilen, 5 Teile unter `features/chat/document/`) – jeweils verifiziert per automatisiertem Blockvergleich gegen das Original und `flutter analyze`, siehe PROGRESS.md-Einträge. `features/call/voice_channel.dart` (1123 Zeilen) und `layout/app_shell.dart` (1073 Zeilen) bewusst NICHT mit angefasst – beide hängen eng mit der noch unentschiedenen Call-Fassade bzw. dem Bootstrap/Login-Pfad zusammen, siehe „Call-Schicht entwirren" unten. UNGETESTET (Pi) im Sinne von „nicht in echter UI gesehen" – nächster Windows-Lauf sollte alle 6 betroffenen Bereiche einmal durchklicken (zusätzlich zu den 5 unten: eine PDF/Text/Archiv/Bild-Datei im Chat öffnen, Vollbild-PDF-Viewer inkl. Thumbnail-Leiste und Speichern-Button prüfen), siehe „Fragen an Bernd"/Nächster-Schritt in den jeweiligen PROGRESS.md-Einträgen) - [ ] Nach JEDEM Schritt: App läuft, Kernflows getestet, Commit ## M3 – Calls: Logik, UI & Audio (Discord als Referenz) - [ ] Voice-Channel-Logik robust machen: Beitreten/Verlassen/Wechseln ohne Hänger, klarer Zustand wer drin ist, sauberes Verhalten bei Verbindungsabbruch - [ ] Call-UI aufräumen: aufgeräumter, intuitiver, konsistent (Mini-Call-Widget, Vollansicht) - [ ] **Windows: Audiogeräte-Erkennung reparieren** (Mikrofon/Ausgabe erkennen und in den Einstellungen auswählbar machen – geht aktuell gar nicht) - [ ] Noise Suppression als optionale Einstellung (z. B. RNNoise/LiveKit-Audio-Filter) - [ ] Lautstärke pro Teilnehmer einstellbar (Discord-Style, persistent pro Nutzer) - [ ] Weitere Feinjustierung: Eingangsempfindlichkeit/Gate, Echo-Unterdrückung an/aus, Push-to-Talk prüfen – von Discords Sprach-Einstellungen inspirieren lassen - [ ] Anruf-Benachrichtigung auch bei gekillter App (Push-Architektur nutzen) ## M4 – Streaming (Bildschirmübertragung) - [ ] **Framerate verbessern:** Ursache messen (Encoder? Auflösung? Simulcast-Settings? Software- statt Hardware-Encoding?), dann gezielt fixen - [ ] Auflösung/Qualität wählbar für den **Streamer** (z. B. 720p/1080p + FPS-Wahl) - [ ] Qualität wählbar für den **Empfänger** (LiveKit-Simulcast-Layer auswählen) - [ ] Sauberes Degradieren bei schwacher Bandbreite statt Ruckel-Chaos ## M5 – Chat-Funktionen - [ ] Sprachnachrichten aufnehmen & abspielen (MSC3245-kompatibel, wie Element) - [ ] **Bilder speichern → richtige Galerie:** über MediaStore/Downloads statt in den unzugänglichen App-Ordner (Android Scoped Storage korrekt nutzen) - [ ] Medien senden/empfangen generell prüfen (Fortschritt, Vorschau, Videos) ## M6 – Release & Verteilung - [ ] **Google-Warnung beim Installieren untersuchen:** Play-Protect-Meldung seit der Signatur-Einführung analysieren (Signing-Konfig prüfen; unbekannte Signatur + Sideload löst das oft aus; ggf. Play-Protect-Appeal oder saubere v2/v3-Signierung) - [ ] Release-Skript prüfen/aktualisieren (Windows + Android), Versionierung sauber - [ ] In-App-Updater testen (existiert laut Git-Historie) ## M7 – Design & Feinschliff - [ ] Rooms-Icon überarbeiten – passt stilistisch nicht zu den anderen Buttons - [ ] Design-Konsistenz-Pass über alle Icons/Buttons - [ ] Onboarding: erster Start erklärt Server-Wahl und Verifikation verständlich - [ ] Themes/Darkmode-Feinschliff, Schriftgrößen ## Ideen-Parkplatz (unsortiert, erst nach M7 bewerten) - Threads, Sticker, Standort teilen, mehrere Konten - Watch-Together (z. B. Jellyfin gemeinsam schauen) > Bernd: „Das ist nur der Anfang meiner Liste" – neue Punkte einfach hier in den > passenden Meilenstein eintragen (oder Claude sagen, er soll sie einsortieren).