9f797279eb
Neuer gegateter Test (PYRAMID_LIVE_TEST=1, Windows): echter Login als pyramidtest1, Byte-Pruefung der Platte (kein SQLite-Header, Token + Nachricht nicht im Klartext, Positiv-Kontrolle in Klartext-DB), Neustart aus verschluesselter DB, Logout/Re-Login, Migration einer Klartext-DB mit echter eingeloggter Session. Zugangsdaten bleiben ausserhalb des Repos. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
307 lines
21 KiB
Markdown
307 lines
21 KiB
Markdown
# 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.**
|
||
**Stand 2026-07-06: UMGESETZT + auf Windows praxisgetestet** – neue
|
||
Storage-Fassade `lib/core/app_database.dart` (SQLCipher auf
|
||
Android/Windows/Linux, Schlüssel im Keystore, Klartext-Migration mit
|
||
Backup/Verifikation/atomarem Tausch, Push-Isolate-Marker). Bernds echte
|
||
Windows-DB wurde erfolgreich migriert (PROGRESS.md 2026-07-06), Tests in
|
||
`test/app_database_test.dart` fahren die Migration mit echtem SQLCipher.
|
||
**Nachtrag 2026-07-06 (vierte PC-Session): Android-EMULATOR-Test grün**
|
||
(API 36: Neuanlage verschlüsselt, Klartext-Migration beim ersten Start,
|
||
Neustart mit Keystore-Schlüssel ohne Re-Migration – Details im
|
||
Status-Kopf von `docs/SQLCIPHER_MIGRATION.md`).
|
||
**Nachtrag 2026-07-06 (Nacht-Session): LIVE-E2E-Test mit ECHTEM Login grün**
|
||
(`test/live_encryption_e2e_test.dart`, Test-Account pyramidtest1 auf
|
||
steggi-matrix.work, Gate `PYRAMID_LIVE_TEST=1`): Platte nach echtem
|
||
Login/Nachricht byte-geprüft (kein SQLite-Header, Access-Token und
|
||
Nachrichtentext NICHT im Klartext auffindbar, Positiv-Kontrolle in
|
||
Klartext-DB findet beides), Neustart restauriert Session aus der
|
||
verschlüsselten DB, Logout→Re-Login→alte Nachricht lesbar, und die
|
||
Klartext-Migration mit einer ECHTEN eingeloggten Session erhält
|
||
Session+Daten. **Bleibt offen:**
|
||
echtes ARM-Gerät mit eingeloggter Session + Push-Isolate-Test
|
||
(FCM liest verschlüsselte DB, secure_storage im Background-Isolate) –
|
||
Testplan Punkt 4 in `docs/SQLCIPHER_MIGRATION.md`;
|
||
erst nach grünem Gerätetest Release + Utas Gerät (vorher ihr Key-Backup
|
||
prüfen!), dann abhaken.
|
||
`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)
|
||
- [x] **SICHERHEIT: Dashboard-Admin-Endpoints – ERLEDIGT: Loch geschlossen,
|
||
Heimnetz-only ist laut Bernd der Endzustand** (Fable-5-Review (o);
|
||
Entscheidung `ANTWORTEN_BERND.md` Nr. 3, 2026-07-05).
|
||
`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`.
|
||
Zusatz (Fable-5-Review (p), 2026-07-04): `server.py` läuft jetzt multithreaded
|
||
mit 30-s-Socket-Timeout – ein einzelner langsamer Client kann den Server
|
||
(und damit `/api/livekit-token`) nicht mehr blockieren; headless verifiziert.
|
||
Zusatz (Fable-5-Review (q), 2026-07-04): Der durch (p) eingeführte
|
||
Nebenläufigkeits-Race in den Admin-Routen (Read-Modify-Write auf `conduit.toml`,
|
||
`send_admin`-Readback) ist mit `ADMIN_LOCK` geschlossen, das NUR die
|
||
Admin-Mutationen serialisiert – die öffentlichen Routen bleiben nebenläufig;
|
||
headless verifiziert (2× parallel = 2× Laufzeit, öffentlicher Pfad 11 ms).
|
||
Zusatz (Fable-5-Review (r), 2026-07-04): drei Restbefunde gefixt –
|
||
`registration-status`-Leser jetzt unter ADMIN_LOCK (Truncate-Write-Race),
|
||
negative/übergroße `Content-Length` überall abgelehnt (kein Thread-Hänger,
|
||
ban/unban 4-KB-Deckel), Einladungs-Token per `secrets` statt `random`.
|
||
Zusatz (Fable-5-Review (s), 2026-07-04): ban/unban-Body wird jetzt VOR dem
|
||
ADMIN_LOCK gelesen (hängender Body-Read konnte den Lock 30 s festhalten),
|
||
und die öffentlichen Routen antworten bei internen Fehlern generisch statt
|
||
mit Exception-Text (Info-Leak); Details ins Journal. Headless verifiziert.
|
||
Zusatz (Fable-5-Review (t), 2026-07-04): auch der öffentliche GET-Leser
|
||
`registration-status` antwortet bei internen Fehlern jetzt generisch
|
||
statt mit `str(e)` (hätte den `conduit.toml`-Pfad geleakt); headless
|
||
verifiziert inkl. 500-Beweis.
|
||
Zusatz (Fable-5-Review (u), 2026-07-04): (t)-Fix gegengelesen – korrekt,
|
||
kein Befund; die server.py-Härtungskette ist damit KONVERGIERT (alle
|
||
verbliebenen `str(e)`-Antworten LAN-gegated, absichtlich).
|
||
**Abschluss (2026-07-05, `ANTWORTEN_BERND.md` Nr. 3): KEIN Fernzugriff
|
||
gewünscht – die A/B-Frage ist GESCHLOSSEN, das Heimnetz-Gate ist der
|
||
Endzustand (unterwegs nutzt Bernd WireGuard). Die Restrisiken des Gates
|
||
(öffentliche Nutzerlisten-Ansicht, theoretisches LAN-CSRF) sind bewusst
|
||
akzeptiert und in `docs/DASHBOARD_AUTH_HARDENING.md` dokumentiert.
|
||
Nicht weiter daran arbeiten.**
|
||
- [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).
|
||
- **Stand 2026-07-05 (`ANTWORTEN_BERND.md` Nr. 4): Rotation und
|
||
History-Rewrite ruhen BEWUSST – beides bleibt Bernds manuelle Sache,
|
||
NICHT vom Autopilot anstoßen oder nachfragen. Der Punkt bleibt nur als
|
||
Merkposten offen; Autopilot-bearbeitbar ist hier nichts mehr.**
|
||
- **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)
|
||
**Teilstand 2026-07-06 (Autopilot, siehe PC_TESTPLAN):** flutter test
|
||
grün (29), Session über 3 Starts + DB-Migration stabil eingeloggt,
|
||
E2EE-Empfang live belegt, auth_log unauffällig; App läuft seit 12:43
|
||
für die Langzeit-Beobachtung weiter. **Offen (Klick/Bernd):**
|
||
Senden, Logout-Warnung, Re-Login mit Lesbarkeits-Check.
|
||
|
||
## 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)
|
||
**Teilschritt erledigt (2026-07-06, M2-Pilot laut Entscheidung 2):**
|
||
Module `call_signaling` und `voice_channel` mit Fassaden-Interfaces +
|
||
Providern existieren (`lib/features/call_signaling/`,
|
||
`lib/features/voice_channel/`), alle Konsumenten gehen nur noch über
|
||
`callSignalingProvider`/`voiceChannelProvider` – kein UI-Import der
|
||
Implementierungen mehr (Details/Abweichungen: Status-Kopf in
|
||
`docs/M2_MODULE_SCHNITT.md`). App startet, 29 Tests grün, Sync/E2EE
|
||
laufen. **UNGETESTET:** echter 1:1-Call und Voice-Channel-Join per
|
||
Klick (braucht Gerät bzw. interaktiven Test) – deshalb nicht abgehakt.
|
||
**Weitere Teilschritte erledigt (2026-07-06, zweite PC-Session):**
|
||
`call_ui` ist jetzt ein eigenes Modul (`lib/features/call_ui/`,
|
||
b2335da) und die voice_*-Prefs laufen über die `VoicePrefs`-Fassade
|
||
in `core/settings_prefs.dart` statt direktem SharedPreferences-Zugriff
|
||
(d22f9c2) – beides verhaltensgleich, analyze/Tests grün, App-Start
|
||
geprüft. **Bewusst zurückgestellt bis Bernds Klick-Test des Piloten
|
||
(PC_TESTPLAN Abschnitt 8) grün ist:** UI-State aus den Managern
|
||
herauslösen – kein zweiter ungetesteter Logik-Umbau auf dem heiligen
|
||
Call-Pfad.
|
||
- [ ] Einheitliches State-Management (Riverpod konsequent, keine Misch-Patterns)
|
||
**Ist-Analyse + Umbauplan liegen in `docs/M2_STATE_MANAGEMENT.md`**
|
||
(2026-07-06): Riverpod ist schon dominant (~50 Provider); 4
|
||
Misch-Patterns identifiziert, Schrittfolge definiert. Schritte 1–2
|
||
(Call-Manager-UI-State, Voice-Provider-Umzug) GESPERRT bis Bernds
|
||
Klick-Test (PC_TESTPLAN Abschnitt 8); MediaCache-Umstellung
|
||
zurückgestellt (hängt an der Chat-Timeline, Korrektur im Doc).
|
||
Push bleibt bewusst wie er ist (Isolate-Zwang). Toter
|
||
`incomingCallProvider` bereits entfernt (41bcaf2).
|
||
- [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) waren zunächst bewusst NICHT
|
||
mit angefasst – beide hängen eng mit der damals unentschiedenen
|
||
Call-Fassade bzw. dem Bootstrap/Login-Pfad zusammen.
|
||
**Nachtrag 2026-07-06:** Nach dem Call-Piloten ist
|
||
`call_ui/voice_channel.dart` jetzt ebenfalls geteilt (5 part-Dateien
|
||
unter `call_ui/view/`, zeichenidentisch verifiziert, 95d9b07);
|
||
`app_shell.dart` bleibt wegen des Bootstrap/Login-Pfads (heilig)
|
||
weiter unangetastet. Ebenso `settings/settings_encryption.dart`
|
||
(1470 Zeilen, größte verbliebene Teildatei) in 4 part-Dateien unter
|
||
`settings/encryption/` geteilt (zeichenidentisch verifiziert,
|
||
6128953) – Vorbereitung für das spätere verification-Modul
|
||
(Schnitt-Doc Schritt 3), Code selbst unangetastet.
|
||
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).
|