- Created datenschutz.vue for the privacy policy with sections on data protection, responsible entity, data processing, rights, and contact information. - Created konto-loeschen.vue for account deletion requests, detailing the process, affected data, and processing time. - Added anonymize-playstore-screenshot.sh script for image anonymization using ImageMagick. - Introduced playstore-assets.mjs for generating Play Store assets, including icons and feature graphics, using sharp. - Added playstore-assets.sh script to execute the asset generation script.
373 lines
35 KiB
Markdown
373 lines
35 KiB
Markdown
Android App — Kotlin (Jetpack Compose) Plan und Abhakliste
|
||
|
||
Kurz: Ziel ist eine native Android-App mit Kotlin + Jetpack Compose, die die Web-UI 1:1 abbildet (Farben, Typografie, Funktionalitäten). Diese Datei enthält Architekturentscheidungen, empfohlene Bibliotheken und eine detaillierte Abhakliste (schrittweise).
|
||
|
||
1) Zusammenfassung der Entscheidungen
|
||
- Plattform: Native Android
|
||
- Sprache: Kotlin
|
||
- UI-Toolkit: Jetpack Compose (Compose Material3)
|
||
- Architektur: MVVM mit `ViewModel` + Kotlin Coroutines + Flow
|
||
- DI: Hilt
|
||
- HTTP-Client: Ktor Client oder Retrofit + OkHttp (empfohlen: Retrofit für breite Community-Docs)
|
||
- Bild-Loading: Coil
|
||
- Lokale DB / Caching: Room + DataStore (Preferences)
|
||
- Background/Sync: WorkManager
|
||
- Auth: kurzlebiges JWT-Access-Token plus rotierendes, widerrufbares Refresh-Token pro Android-Gerätesitzung; Speicherung in `EncryptedSharedPreferences`/Android Keystore; Unterstützung für Passkeys (Android Passkeys / WebAuthn Interop über FIDO2 APIs)
|
||
- Auth-Sicherheitsentscheidung: kein statischer App-Key bzw. kein in der APK hinterlegtes Client-Secret. Native Apps können ein gemeinsames Secret nicht vertraulich halten. Optional später: Refresh-Sitzung an ein pro Installation im Android Keystore erzeugtes Schlüsselpaar binden.
|
||
- Rich-Text: WebView-basierte Anzeige; Editoren: ggf. hybride Lösung (Server-side HTML editor + WebView) oder `RichEditor`-Libs
|
||
- Crash-Reporting & Monitoring: Firebase Crashlytics oder Sentry
|
||
|
||
2) Design & Farben
|
||
- Material Theme (Material3) mit Farben aus `tailwind.config.js` (Primary + Accent).
|
||
- Fonts: Inter & Montserrat via Google Fonts (Download/Bundle oder Play-Services-Download at runtime).
|
||
- Mapping: Tailwind-Token → `colors.xml` / Compose `Color` tokens.
|
||
|
||
3) Empfohlene Abhängigkeiten (erste Implementierung)
|
||
- androidx.compose.* (ui, material3, navigation)
|
||
- androidx.lifecycle:lifecycle-viewmodel-ktx
|
||
- com.google.dagger:hilt-android
|
||
- retrofit2 + converter-moshi / kotlinx-serialization
|
||
- io.coil-kt:coil-compose
|
||
- androidx.room:room-runtime + room-ktx
|
||
- androidx.work:work-runtime-ktx
|
||
- androidx.datastore:datastore-preferences
|
||
- com.google.android.gms:play-services-auth (für passkeys falls nötig)
|
||
- io.sentry:sentry-android (optional)
|
||
|
||
4) Detaillierte Abhakliste (Schritte)
|
||
[x] 1. Repo-Analyse: Liste der externen Endpunkte und Auth-Anforderungen exportieren
|
||
[x] 2. Projekt-Scaffold: Android Studio Projekt mit Kotlin + Compose anlegen
|
||
[x] 3. App-Architektur: Module / Packages anlegen (ui, data, domain, di, util)
|
||
[x] 4. CI-Build: Gradle-Config und GitHub Actions Skeleton
|
||
[x] 5. Theme: `Color.kt`, `Typography.kt`, `Theme.kt` erstellen und Tailwind-Farben mappen
|
||
[x] 6. Fonts: Inter + Montserrat einbinden (res/font oder GoogleFonts)
|
||
[x] 7. Navigation: Compose Navigation-Graph mit Routen für alle Web-Seiten anlegen
|
||
[x] 7a. Umgebungen: Android-Varianten fuer lokal, Test-Instanz und Produktion mit eigener API-Basis konfigurieren
|
||
[x] 7b. Adaptive Navigation: Tablet mit persistentem Header/Hauptmenue, Smartphone mit bestehender screenbezogener Navigation
|
||
[x] 7c. Branding: vorhandenes Web-Logo als optimierte Android-Ressource in der App-Navigation verwenden
|
||
[x] 7d. Tablet-Navigation: öffentliche Haupt- und Subnavigation der Web-UI mit Portierungszielen abbilden
|
||
[x] 7e. Navigation: dynamische Mannschaftslinks, Galerie-Sichtbarkeit und rollenabhängiges `Intern` wie in der Web-UI anbinden
|
||
[x] 8. Start-Screen: `HomeScreen` webnah mit Hero, Navigation, Termine, Spielen, News und Aktionen umsetzen
|
||
[x] 9. Komponenten: NavBar, Footer, Cards, ImageGrid und News-Dialog implementieren
|
||
[x] 10. Öffentliche Screens aus der Web-Navigation portieren
|
||
- [x] `/` Startseite
|
||
- [x] `/termine`: öffentliche Terminliste mit Lade-, Leer- und Fehlerzustand
|
||
- [x] `/mannschaften/spielplaene`: Saison-, Wettbewerbs- und Mannschaftsfilter mit Spielkarten
|
||
- [x] `/verein/galerie`: Anzeige-Screen vorhanden
|
||
- [x] `/kontakt`: Formular-Screen vorhanden
|
||
- [x] `/mitgliedschaft`: Antrag, Validierung, PDF-Erzeugung und PDF-Öffnen
|
||
- [x] `/verein/ueber-uns`: CMS-Inhalt aus der öffentlichen Konfiguration
|
||
- [x] `/vorstand`: öffentliche Vorstandsangaben aus der Konfiguration
|
||
- [x] `/verein/geschichte`: CMS-Inhalt aus der öffentlichen Konfiguration
|
||
- [x] `/verein/satzung`: CMS-Inhalt und PDF-Aufruf aus der öffentlichen Konfiguration
|
||
- [x] `/vereinsmeisterschaften`: Ergebnisliste mit Jahresfilter und Statistik
|
||
- [x] `/links`: strukturierte CMS-Links mit Fallback-Verweisen
|
||
- [x] `/mannschaften`: Übersicht aus saisonaler Mannschafts-CSV
|
||
- [x] `/mannschaften/[slug]`: dynamische Mannschaftsdetails mit aktuellem Spielplan und Umschaltung `Matches`/`Tabelle`
|
||
- [x] `/spielsysteme`: Spielsystemkarten mit Kategoriefilter aus CSV
|
||
- [x] `/training`: Trainingsort und gruppierte Trainingszeiten aus der Konfiguration
|
||
- [x] `/training/trainer`
|
||
- [x] `/training/anfaenger`
|
||
- [x] `/tt-regeln`: Regelübersicht mit DTTB- und PDF-Aufruf
|
||
[x] 10a. Weitere öffentliche bzw. bestehende Web-Routen prüfen und portieren
|
||
- [x] `/impressum`
|
||
- [x] Legacy-/Doppelrouten geklärt: `/galerie`, `/geschichte`, `/satzung`, `/ueber-uns`, `/spielplan`, `/verein/tt-regeln`, `/mannschaft/[slug]`, `/mannschaften/herren`, `/mannschaften/damen`, `/mannschaften/jugend`
|
||
[x] 10b. Newsletter-Screens portieren
|
||
- [x] `/newsletter/subscribe`
|
||
- [x] `/newsletter/unsubscribe`
|
||
- [x] `/newsletter/confirm`, `/newsletter/confirmed`, `/newsletter/unsubscribed`
|
||
[x] 10c. Auth-Screens portieren
|
||
- [x] `/login`: Passwort-Login und Logout in der laufenden Sitzung
|
||
- [x] `/registrieren`
|
||
- [x] `/passwort-vergessen`
|
||
[x] 10d. Mitgliederbereich portieren
|
||
- [x] `/mitgliederbereich`: Übersicht
|
||
- [x] `/mitgliederbereich/mitglieder`
|
||
- [x] `/mitgliederbereich/news`
|
||
- [x] `/mitgliederbereich/profil`
|
||
- [x] `/mitgliederbereich/api`
|
||
[x] 10e. CMS-Screens nach Rollenberechtigung portieren
|
||
- [x] `/cms`, `/cms/startseite`, `/cms/inhalte`, `/cms/vereinsmeisterschaften`
|
||
- [x] `/cms/sportbetrieb`, `/cms/mitgliederverwaltung`, `/cms/kontaktanfragen`
|
||
- [x] `/cms/newsletter`, `/cms/einstellungen`, `/cms/benutzer`
|
||
[x] 11. API-Client: Retrofit/Ktor-Client implementieren, Auth-Interceptor (Token Refresh)
|
||
- [x] Retrofit/OkHttp/Moshi und Hilt-Verdrahtung
|
||
- [x] Öffentliche Endpunkte für Startseite, Termine, Spielplan, Galerie und Kontakt
|
||
- [x] Mitgliedschafts-PDF-Endpunkte mit Cookie-Jar und `FileProvider`
|
||
- [x] Passwort-Login-Endpunkt und Token-Übergabe an den Interceptor
|
||
- [x] Verschlüsselte Token-Persistenz sowie Status/Logout per Bearer-Token
|
||
- [x] Bearer-Unterstützung aller später portierten geschützten Bereiche (`/api/profile`, `/api/birthdays`, `/api/members`, `/api/news`, CMS-/Newsletter-/Galerie-Endpunkte erledigt); Web bleibt bewusst Cookie-basiert
|
||
- [x] `POST /api/auth/refresh` anbinden und Access-Token bei Ablauf automatisch erneuern
|
||
- [x] OkHttp-`Authenticator` mit genau einem synchronisierten Refresh-Versuch pro fehlgeschlagenem Request ergänzen
|
||
[x] 12. Auth: Login/Register/Logout + sichere Token-Speicherung (EncryptedSharedPreferences)
|
||
- [x] Login/Logout und verschlüsselte Token-Speicherung
|
||
- [x] Registrierung und Passwort-Reset
|
||
- [x] Backend: Android-JWT-Access-Token auf ca. 15 Minuten reduzieren; bestehende Web-Cookie-Sitzungen bis zur Web-Refresh-Integration kompatibel weiterführen
|
||
- [x] Backend: langlebige, zufällige Refresh-Token pro Gerätesitzung mit serverseitig gespeichertem Token-Hash einführen
|
||
- [x] Backend: Refresh-Token bei jeder Erneuerung rotieren und Wiederverwendung eines verbrauchten Tokens als Sitzungsdiebstahl behandeln
|
||
- [x] Backend: Logout, Kontodeaktivierung und Passwortänderung widerrufen betroffene Refresh-Sitzungen
|
||
- [x] App: Access- und Refresh-Token verschlüsselt speichern, Sitzung beim App-Start durch Refresh wiederherstellen
|
||
- [ ] Optional nach MVP: pro Installation ein nicht exportierbares Keystore-Schlüsselpaar erzeugen und Refresh-Requests daran binden
|
||
[x] 13. Passkeys: Integration prüfen (FIDO2 / Passkeys) und Fallback auf Passwort
|
||
- [x] Passkey-Login über Android Credential Manager an bestehende WebAuthn-Endpunkte anbinden
|
||
- [x] Passkey-Erstellung und -Entfernung im nativen Profil ergänzen
|
||
- [x] Backend-Passkey-Endpunkte für Android-Bearer-Token und Android-Refresh-Sitzungen erweitern
|
||
- [ ] Für Produktion `/.well-known/assetlinks.json` mit Package `de.harheimertc` und Release-Zertifikat-Fingerprint veröffentlichen
|
||
[x] 14. Image-Upload: Multipart-Upload + Coil für Anzeige + Bildkompression (u. a. Sharp-Äquivalent evtl. serverseitig)
|
||
[x] 15. Rich-Text: Anzeige von HTML (Compose + WebView) und ggf. Editor via WebView-bridge
|
||
- [x] Gemeinsame native HTML/Rich-Text-Komponente für CMS- und News-Inhalte ergänzt
|
||
- [x] Öffentliche CMS-Seiten, Startseiten-News und interne News rendern HTML-Inhalte nativ
|
||
- [x] Nativer Rich-Text-Editor für CMS-Inhalte ergänzt; Toolbar schreibt Quill-kompatible HTML-Fragmente und speichert denselben HTML-String wie die Web-UI
|
||
[x] 16. Formulare: Validierung (clientseitig) und Fehlerdarstellung
|
||
- [x] Gemeinsame validierte Textfelder mit Inline-Fehlern ergänzt
|
||
- [x] Kontakt, Login, Passwort-Reset, Registrierung, Newsletter, Profil und Mitgliedschaft zeigen Feldfehler direkt am Eingabefeld
|
||
[x] 17. Offline & Caching: Room für persistente Daten, Response-Caching, Sync-Strategie
|
||
- [x] Zentraler OkHttp-Cache für öffentliche GET-Antworten ergänzt; Offline-Fallback nutzt gecachte Antworten bis 7 Tage
|
||
- [x] Zentraler Coil-ImageLoader mit gemeinsamem OkHttp-Client, Memory-Cache und 75-MB-Diskcache ergänzt
|
||
- [x] Verschlüsselte persistente Offline-Daten für geschützte Mitglieder-/CMS-Inhalte mit `EncryptedSharedPreferences` implementiert
|
||
[x] 18. Lokalisierung: `strings.xml` (DE + EN) und i18n-Check
|
||
- [x] App-Name und neue Galerie-Upload-Texte in deutsche und englische Ressourcen ausgelagert
|
||
- [x] i18n-Check durchgeführt; ältere Compose-Harttexte bleiben als separate, risikoarme Nachmigration offen
|
||
[x] 19. Accessibility: ContentDescription, Focus, Farben/Kontrast prüfen
|
||
[ ] 20. Tests: Unit-Tests für ViewModels + UI-Tests mit Compose Testing
|
||
- [x] Erste JVM-Unit-Tests für gemeinsame Formularvalidierung ergänzt
|
||
- [x] ViewModel-Tests für Auth-/CMS-/Galerie-Flows ergänzen
|
||
- [ ] Compose-UI-Tests für kritische Screens ergänzen
|
||
- [x] Hilt androidTest dependencies und `kspAndroidTest` konfiguriert
|
||
- [x] `HiltTestApplication` in `androidTest`-Manifest gesetzt
|
||
- [x] `LoginScreenTest` zu `@HiltAndroidTest` migriert und `HiltAndroidRule` hinzugefügt
|
||
- [x] `TestHiltModules.kt` für androidTest hinzugefügt (Test‑Bindings bereitgestellt)
|
||
[x] 21. Performance: Bildoptimierung, LazyLists, Paging (falls große Daten)
|
||
[ ] 22. Analytics: Firebase / Matomo Integration (je nach Datenschutz)
|
||
[x] 23. Crash-Reporting: Sentry / Crashlytics integrieren
|
||
[ ] 24. Build/Release: App signing, Release-Notes, Play-Store-Metadaten vorbereiten
|
||
- [x] Technische Release-Basis vorbereitet: `ANDROID_VERSION_CODE` und `ANDROID_VERSION_NAME` als Gradle-Properties eingeführt (`android-app/gradle.properties`) und im App-Gradle verdrahtet.
|
||
- [x] Production-Release-Flavor auf Produktiv-Backend parametrisierbar gemacht (`PRODUCTION_API_BASE_URL`, Default `https://harheimertc.de/`).
|
||
- [x] Release-Signing per sicheren Gradle-Properties vorbereitet (`RELEASE_STORE_FILE`, `RELEASE_STORE_PASSWORD`, `RELEASE_KEY_ALIAS`, `RELEASE_KEY_PASSWORD`) statt Hardcoding.
|
||
- [x] `:app:assembleProductionRelease` erfolgreich gebaut (Stand 2026-05-29).
|
||
- [x] Play-Store-Listing-Basis ergänzt: Datenschutzseite unter `/datenschutz` sowie Skripte für Icon/Feature-Graphic-Export und Screenshot-Anonymisierung inklusive Anleitung (`android-app/PLAYSTORE_ASSETS.md`).
|
||
- [x] Konto-Lösch-URL für Play Store ergänzt: öffentliche Seite unter `/konto-loeschen` inklusive Prozessbeschreibung.
|
||
- [ ] Offen: Finales Upload-Keystore + Credentials in CI/Build-Host hinterlegen, Play-Store-Release-Notes und Store-Metadaten pflegen.
|
||
[ ] 25. Dokumentation: `README-android.md` mit Setup, Architektur und Release-Anleitung
|
||
|
||
5) Kurzzeit-MVP (Priorität für erste Version)
|
||
- [x] A. Auth (Login/Logout)
|
||
- [x] Passwort-Login und Logout in der aktuellen App-Sitzung
|
||
- [x] Persistente Statuswiederherstellung/Logout für die Auth-Endpunkte
|
||
- [x] Dauerhaftes Eingeloggtbleiben durch rotierendes Refresh-Token pro Android-Gerätesitzung
|
||
- [x] B. Home, Termine, Spielplan, Galerie (anzeigen)
|
||
- [x] C. Kontaktformular (absenden)
|
||
- [x] D. Bildanzeige + Caching
|
||
- [x] E. Theme & Fonts
|
||
|
||
6) Nächste Aktionen (sofort)
|
||
- Web-Login bei Bedarf auf denselben Refresh-Flow migrieren; bis dahin bleiben Web-Cookie-Sitzungen bewusst kompatibel.
|
||
- Release-Zertifikat erzeugen und Digital Asset Links für native Android-Passkeys veröffentlichen.
|
||
- Die noch fehlenden öffentlichen Routen aus `10a` und die Newsletter-Screens aus `10b` nativ portieren.
|
||
- Saisonwahl für Mannschaftsübersicht/-details wie in der Web-UI ergänzen.
|
||
- Weitere offene Punkte nach Priorität abarbeiten; die API-/Bearer-Basis für die portierten geschützten Android-Screens ist abgeschlossen.
|
||
|
||
7) Umsetzungsprotokoll
|
||
- 2026-05-27: Webnahe Startseite mit öffentlichen Live-Daten umgesetzt; Hilt/Moshi-App-Verdrahtung ergänzt.
|
||
- 2026-05-27: `Termine` und `Spielplan` als native Screens umgesetzt; Spielplan unterstützt Saison, Wettbewerb, Mannschaft, Ergebnis und zweizeilige Gruppeninformation.
|
||
- 2026-05-27: `Mitgliedschaft` mit Antrag/PDF-Abruf sowie Passwort-`Login`/`Logout` umgesetzt; offene Auth-Härtung separat ausgewiesen.
|
||
- 2026-05-27: Tokens verschlüsselt persistiert; Session-Wiederherstellung sowie Logout per Bearer-Token in den Auth-Endpunkten ermöglicht.
|
||
- 2026-05-27: Registrierung und Passwort-Reset an die vorhandenen Auth-Endpunkte angebunden.
|
||
- 2026-05-27: Product-Flavors `local`, `instantTest` und `production` eingerichtet; lokale Basis-URL ist per Gradle-Parameter überschreibbar.
|
||
- 2026-05-27: Gradle-Heap/Worker für Flavor-Builds festgelegt, nachdem paralleles D8/KSP mit dem 512-MiB-Standardheap nicht ausreichend Speicher hatte.
|
||
- 2026-05-27: Lokales Testsetup gegen Emulator geprüft; bei IPv6-gebundenem Nuxt-Dev-Server wird die von Nuxt ausgegebene Network-URL per `LOCAL_API_BASE_URL` verwendet.
|
||
- 2026-05-27: Adaptive Navigation umgesetzt; Tablet-Layouts ab `600dp` zeigen Header und Hauptmenue dauerhaft, Smartphone-Layouts behalten die vorhandene Navigation.
|
||
- 2026-05-27: Platzhalterlogo in der Android-Navigation durch das vorhandene Harheimer-TC-Weblogo als skalierte lokale PNG-Ressource ersetzt.
|
||
- 2026-05-27: Web-Navigation und `pages/` vollständig inventarisiert; Tablet-Haupt-/Subnavigation für die öffentlichen Bereiche strukturell angeglichen und alle fehlenden Screens einzeln in die Portierungsliste aufgenommen.
|
||
- 2026-05-27: Tablet-Header auf Web-Verhalten angepasst (Bereichswechsel öffnet Startseite und Submenü) und die native ActionBar zugunsten des App-Headers entfernt.
|
||
- 2026-05-27: Navigation mit Live-Mannschaftslinks, öffentlicher Galerie-Sichtbarkeit und rollenabhängigem `Intern` ergänzt; Mannschaftsübersicht/-detail sowie Training, Trainer und Anfänger nativ portiert.
|
||
- 2026-05-27: Mannschaftsdetail um die Web-Untertabs `Matches` und `Tabelle` erweitert; Tabellenzeilen werden aus `/api/spielplan/table` geladen und die eigene Mannschaft hervorgehoben.
|
||
- 2026-05-27: Tabellenraster in den Mannschaftsdetails mit gemeinsamen Spaltenbreiten für Tablet und Smartphone ausgerichtet; die Zustandswiederherstellung dynamischer Mannschaftslinks korrigiert.
|
||
- 2026-05-27: Die verbleibenden öffentlichen Screens aus Punkt 10 portiert: Verein/CMS-Inhalte, Vorstand, Satzung/PDF, Links, Vereinsmeisterschaften mit Personenbild-Dialog, Spielsysteme und TT-Regeln.
|
||
- 2026-05-27: Architektur für dauerhaftes Android-Login festgelegt: kein eingebetteter App-Key, sondern kurzlebige Access-Tokens und rotierende, widerrufbare Refresh-Tokens pro Gerätesitzung; optionale spätere Gerätebindung per Keystore-Schlüsselpaar.
|
||
- 2026-05-27: Dauerhaftes Android-Login umgesetzt: Android-Logins erhalten 15-Minuten-Access-Tokens und rotierende Refresh-Tokens; Token-Hashes, Wiederverwendungswiderruf, Logout-/Reset-/Deaktivierungswiderruf sowie verschlüsselte App-Speicherung und automatischer OkHttp-Refresh sind implementiert.
|
||
- 2026-05-27: Native Profilseite des Mitgliederbereichs umgesetzt; `/api/profile` akzeptiert nun Bearer-Tokens, die App kann Profil-/Sichtbarkeitsdaten bearbeiten und Passwortänderungen auslösen.
|
||
- 2026-05-27: Login leitet in der Android-App nun direkt zur Mitgliederbereich-Übersicht weiter; `/mitgliederbereich` ist nativ mit Kacheln und Geburtstagsliste umgesetzt, `/api/birthdays` akzeptiert Bearer-Tokens.
|
||
- 2026-05-28: 10d und 10e abgeschlossen: Mitgliederliste, interne News, API-Doku sowie alle CMS-Routen sind nativ angebunden; relevante Mitglieder-/News-/CMS-Endpunkte akzeptieren Bearer-Tokens.
|
||
- 2026-05-28: 10a und 10b abgeschlossen: Impressum, Newsletter-An-/Abmeldung und Newsletter-Statusseiten sind nativ umgesetzt; Legacy-/Doppelrouten im Android-NavGraph auf native Screens abgebildet. Abgleich `pages/` gegen Android-Routen ergab keine verbleibenden Platzhalter-Webseiten. `/anlagen` wurde anschließend als ungenutzte und inhaltlich falsche Seite in Web und Android entfernt.
|
||
- 2026-05-28: Android-Passkeys umgesetzt: Login nutzt Android Credential Manager mit den bestehenden WebAuthn-Optionen, das native Profil kann Passkeys erstellen/entfernen, und die Backend-Passkey-Endpunkte akzeptieren Bearer-Tokens sowie erzeugen beim Android-Passkey-Login rotierende Refresh-Sitzungen. Für Produktion fehlt noch die Domain-App-Verknüpfung per Digital Asset Links mit Release-Zertifikat.
|
||
- 2026-05-28: Punkte 15 und 16 umgesetzt: Gemeinsame `RichText`-Komponente rendert HTML-Inhalte nativ in CMS-/News-Screens; Formularvalidierung wurde mit Inline-Feldfehlern für Kontakt, Auth, Newsletter, Profil und Mitgliedschaft ergänzt.
|
||
- 2026-05-28: Rich-Text-Editor nativ umgesetzt: `/cms/inhalte` kann Über-uns, Geschichte, TT-Regeln und Satzung mit Android-Toolbar bearbeiten; gespeichert wird weiterhin HTML in `seiten.*` über `PUT /api/config`, kompatibel zur Web-/Quill-Ausgabe.
|
||
- 2026-05-28: Punkt 14 umgesetzt: Android-Galerie nutzt den strukturierten `/api/galerie/list`-Response, lädt Bilder über Coil aus `/api/media/galerie/:id`, und Admin/Vorstand kann Bilder nativ auswählen, lokal auf JPEG/2000px/85% komprimieren und per Multipart an `/api/galerie/upload` senden.
|
||
- 2026-05-28: Punkt 18 umgesetzt: `strings.xml` für Deutsch und Englisch ergänzt, App-Label und neue Galerie-Upload-UI auf Ressourcen umgestellt; i18n-Check weist die bestehenden älteren Compose-Harttexte als spätere Nachmigration aus.
|
||
- 2026-05-28: Punkt 11 abgeschlossen: Android sendet Bearer-Tokens zentral per OkHttp-Interceptor; die portierten geschützten Backend-Endpunkte akzeptieren Cookie- oder Bearer-Authentifizierung. Die Web-UI bleibt absichtlich bei HttpOnly-Cookie-Sessions und muss nicht auf Bearer umgestellt werden.
|
||
- 2026-05-28: Caching-Teil von Punkt 17 und MVP-D umgesetzt: OkHttp cached öffentliche GET-Antworten und nutzt gecachte Antworten offline, Coil nutzt denselben authentifizierten Client plus Memory-/Diskcache. Geschützte Daten werden bewusst nicht unverschlüsselt im HTTP-Diskcache persistiert.
|
||
- 2026-05-28: Testbasis für Punkt 20 begonnen: JVM-Unit-Tests für E-Mail- und ISO-Datum-Validierung ergänzt; `:app:testLocalDebugUnitTest` läuft mit `compileSdk 35` grün.
|
||
- 2026-05-28: Punkte 17, 19, 21 und 23 weiter umgesetzt: geschützte Mitglieder-/CMS-Daten werden verschlüsselt in Keystore-gestützten Preferences gecacht und bei Ladefehlern genutzt; Galerie-Accessibility und Thumbnail-Decoding verbessert; Sentry-Android 8.42.0 über optionalen `SENTRY_DSN`-Gradle-Parameter integriert.
|
||
- 2026-05-29: Play-Store-Listing-Vorbereitung ergänzt: eigenständige Web-Datenschutzseite (`/datenschutz`) sowie Asset-/Anonymisierungs-Skripte und Anleitung in `android-app/PLAYSTORE_ASSETS.md` hinzugefügt.
|
||
|
||
8) Android-Testumgebungen
|
||
- Lokal im Emulator: `./gradlew :app:installLocalDebug` verwendet `http://10.0.2.2:3100/` und die App-ID `de.harheimertc.local`.
|
||
- Lokal, wenn `10.0.2.2` nicht erreichbar ist: `./gradlew :app:installLocalDebug -PLOCAL_API_BASE_URL=http://<NUXT-NETWORK-HOST>:3100/`; die passende URL steht in der `npm run dev`-Ausgabe (hier `http://torstens:3100/`).
|
||
- Test-Instanz: `./gradlew :app:installInstantTestDebug` verwendet `https://harheimertc.tsschulz.de/` und die App-ID `de.harheimertc.test`.
|
||
- Produktion: `./gradlew :app:installProductionDebug` verwendet `https://harheimertc.de/` und die App-ID `de.harheimertc`.
|
||
- Nur APKs erzeugen: `./gradlew :app:assembleLocalDebug :app:assembleInstantTestDebug :app:assembleProductionDebug`.
|
||
|
||
8a) Aktueller Teststatus & Troubleshooting (Stand: 2026-05-28)
|
||
|
||
- **Status:** `:app:assembleAndroidTest` läuft durch; `:app:connectedAndroidTest` ist derzeit instabil und schlägt bei Instrumentation-Läufen fehl.
|
||
- **Beobachtete Probleme:**
|
||
- Kompilationsfehler in `LoginScreenTest.kt` wegen `HiltTestActivity` (Unresolved reference). Workaround: `createAndroidComposeRule<ComponentActivity>()` + `setContent{}` verwenden, damit `assembleAndroidTest` durchläuft.
|
||
- Laufzeit-/Device-Probleme bei `connectedAndroidTest`: `com.android.ddmlib.SyncException: Remote object doesn't exist!` und `DELETE_FAILED_INTERNAL_ERROR` beim Deinstallieren von Test-APKs.
|
||
- `AndroidTestLogcatPlugin` wirft `FileNotFoundException` für erwartete Log-/Crash-Dateien, weil Gradle/UTP manche Device-Artefakte nicht zuverlässig pulled.
|
||
- Einzelne Instrumentation-Tests (z. B. `CmsActivateResendTest`, `GalleryScreenTest`) zeigen Assertion-Fehlschläge — diese sollten isoliert reproduziert werden.
|
||
- **Kurzfristige Empfehlungen (nicht ausführen):**
|
||
- Emulator neu starten und sicherstellen, dass keine veralteten Test-APKs installiert sind.
|
||
- Manuell: `adb uninstall` der Test-Pakete, dann frisches `adb install -r` des Test-APKs und gezielter Einzeltest via:
|
||
|
||
`adb shell am instrument -w -e class <test-class>#<testMethod> de.harheimertc.test/androidx.test.runner.AndroidJUnitRunner`
|
||
|
||
parallel `adb logcat -v time > /tmp/harheimertc_live_logcat.txt` laufen lassen, um vollständige Logs zu speichern.
|
||
- Falls UTP/ddmlib `SyncException` weiter auftritt: Gradle-Parallelität reduzieren, Test-Plugins (z. B. `AndroidTestLogcatPlugin`) temporär deaktivieren oder Tests in kleinere Gruppen splitten.
|
||
- **Offene Test‑To‑Dos:**
|
||
- Reproduzierbaren Einzeltest-Run mit vollständigem `logcat` erfassen (derzeit vom Nutzer pausiert).
|
||
- Flaky Tests isolieren und Hilt/KSP-Setup prüfen, damit `HiltTestActivity`-Importe nicht mehr fehlschlagen.
|
||
- Langfristig: Tests aufteilen, flaky tests markieren und CI-Job für androidTests gegen UTP-Transient-Fehler härten.
|
||
|
||
9) Dauerhaftes Android-Login: Architektur und Umsetzung
|
||
- Stand der Umsetzung: Android-Logins erhalten ein ca. 15 Minuten gültiges JWT und eine serverseitig prüfbare Refresh-Sitzung; Access-Tokens mit Sitzungs-ID werden bei widerrufener Gerätesitzung abgelehnt. Web-Logins verwenden weiterhin das bisherige Cookie-JWT, bis ein browserseitiger Refresh-Flow ergänzt ist.
|
||
- Ziel: Ein Benutzer bleibt auf einem bekannten Gerät angemeldet, ohne dass ein langfristig gültiges Bearer-JWT oder ein extrahierbares App-Secret verwendet wird.
|
||
- Token-Modell:
|
||
- Access-Token: JWT mit kurzer Laufzeit, Zielwert ca. 15 Minuten; wird für normale API-Requests als Bearer-Token verwendet.
|
||
- Refresh-Token: kryptografisch zufälliges, undurchsichtiges Token mit längerer Laufzeit, Zielwert z. B. 90 Tage mit Erneuerung bei aktiver Nutzung.
|
||
- Server speichert ausschließlich den Hash des Refresh-Tokens zusammen mit `sessionId`, `userId`, `createdAt`, `lastUsedAt`, `expiresAt`, `revokedAt` und optional Gerätebezeichnung.
|
||
- Backend-Arbeitspaket:
|
||
- Login-Antwort um `accessToken`, `refreshToken`, `sessionId` und Ablaufmetadaten erweitern; bestehendes `token` nur befristet kompatibel halten.
|
||
- `POST /api/auth/refresh` implementieren: gültiges Refresh-Token konsumieren, rotieren und ein neues Token-Paar zurückgeben.
|
||
- Token-Wiederverwendung erkennen: Wird ein rotiertes Refresh-Token erneut präsentiert, die betroffene Token-Familie bzw. Gerätesitzung widerrufen.
|
||
- `POST /api/auth/logout` auf Widerruf der Gerätesitzung erweitern; optional Endpunkte zum Anzeigen und Widerrufen eigener Geräte-Sitzungen vorsehen.
|
||
- Kontodeaktivierung und Passwortänderung müssen sämtliche Refresh-Sitzungen des Benutzers widerrufen.
|
||
- Rate-Limits und Audit-Events für Login, Refresh-Erfolg/-Fehlschlag, Wiederverwendung und Widerruf ergänzen.
|
||
- Android-Arbeitspaket:
|
||
- `AuthRepository` auf Access-Token, Refresh-Token und Session-ID erweitern; Speicherung weiter über Keystore-geschützte Preferences.
|
||
- `ApiService`/DTOs um Refresh-Request und Token-Paar-Antwort ergänzen.
|
||
- Einen OkHttp-`Authenticator` einsetzen, der auf `401` einmalig ein Access-Token erneuert, parallele Refreshes synchronisiert und den ursprünglichen Request wiederholt.
|
||
- Beim App-Start zunächst Access-Token prüfen und bei Ablauf transparent mit dem Refresh-Token erneuern; nur bei fehlgeschlagenem Refresh zum Login zurückkehren.
|
||
- Beim Logout lokale Tokens auch bei Netzwerkfehler entfernen; serverseitiger Widerruf erfolgt best effort bzw. bei nächster Konnektivität.
|
||
- Sicherheitsregeln:
|
||
- Kein gemeinsamer App-Key und kein statisches Client-Secret in Sourcecode, `BuildConfig` oder APK.
|
||
- Refresh-Tokens nie im Klartext serverseitig speichern oder protokollieren.
|
||
- Nur HTTPS für Test-/Produktionsumgebungen; Token-Werte nicht in Logging-Interceptors ausgeben.
|
||
- Optional nach MVP: App erzeugt pro Installation ein Keystore-Schlüsselpaar; Backend bindet Refresh-Sitzungen an den öffentlichen Schlüssel und prüft signierte Refresh-Anfragen.
|
||
|
||
---
|
||
Datei: [ANDROID_KOTLIN_PLAN.md](ANDROID_KOTLIN_PLAN.md)
|
||
|
||
**CMS-Verbesserungsplan (Analyse → Umsetzung)**
|
||
|
||
Ziel: Alle `cms/*`-Screens von rudimentärem Status zu vollständigen, getesteten Admin-Tools weiterentwickeln. Fokus: Datenintegrität, Berechtigungen, bessere UI/UX, Offline-Verhalten und Tests.
|
||
|
||
Kurzüberblick (3 Phasen):
|
||
- Phase A — Analyse (1-2 Tage): Inventar aller CMS-Endpunkte, fehlende CRUD-Workflows identifizieren, Prioritäten setzen (News, Benutzer, Kontaktanfragen, Newsletter, Config). Ergebnis: Aufgabenliste mit Aufwandsschätzung.
|
||
- Phase B — Implementierung MVP (1-2 Wochen): Kernfunktionen pro Bereich implementieren (News CRUD mit RichText-Vorschau, Benutzerliste + Rollen-Edit, Kontaktanfragen Detail & Antwort-Workflow, Newsletter-Gruppen-Management, Config-Editor inklusive Satzung-PDF-Feld). Unit- / Integrationstests für ViewModels.
|
||
- Phase C — Harden, UX & Tests (1 Woche): Validierung, Fehlermeldungen, Offline-Caching (verschlüsselt für geschützte Daten), Compose-UI-Tests, Accessibility-, Performance-Feinschliff.
|
||
|
||
Detaillierte Aufgaben (priorisiert):
|
||
- A1: Audit `CmsViewModel`-State vs. Backend-Responses — fehlen Felder/Fehlerfälle? (bereits teilweise umgesetzt)
|
||
- A2: Prüfen, ob API-Fehler (4xx/5xx) sauber an `FormMessages`/UI gemeldet werden — Standardisiere Fehlermeldungen.
|
||
- A3: Prüfen, ob `NativeRichTextEditor` HTML speichert, das Web-Editor-kompatibel bleibt (Quill/HTML). Schreibe Roundtrip-Tests.
|
||
- B1: News-Management
|
||
- B1.1: News-CRUD: Create/Update/Delete mit Vorschau (RichText-Preview) und Validierung (Titel Pflicht, Inhalt Mindestlänge)
|
||
- B1.2: Bulk-Aktionen: Sichtbar/Unsichtbar/ExpiresAt setzen
|
||
- B1.3: Unit-Tests für `NewsViewModel` + `CmsViewModel`-Integrationspfad
|
||
- B2: Benutzer-Management
|
||
- B2.1: Rollen-Edit (admin/vorstand/trainer/newsletter) in `CmsBenutzerScreen` (Inline-Action oder Detail-Dialog)
|
||
- B2.2: Aktiv/Inaktiv Toggle + Resend-Invite (falls API unterstützt)
|
||
- B2.3: Tests: `CmsViewModel.users()` Verhalten bei Pagination/Leeren Listen
|
||
- B3: Kontaktanfragen
|
||
- B3.1: Detailansicht mit Antwort-Option (falls Backend Mail-Sende-Endpunkt vorhanden)
|
||
- B3.2: Status-Filter (offen/beantwortet) und Bulk-Archiv
|
||
- B4: Newsletter
|
||
- B4.1: Entwurf -> Senden Flow mit Preview (falls Backend zulässt)
|
||
- B4.2: Gruppenverwaltung (CRUD) + Subscribe/Unsubscribe-Preview
|
||
- B5: Config / Seiten (Inhalte)
|
||
- B5.1: Sichern/Zurücksetzen von Seiteninhalten mit Undo-Hinweis
|
||
- B5.2: Satzung: PDF-Upload-Feld und native PDF-Viewer-Integration (falls serverseitig gespeichert)
|
||
- B5.6: Android-Startseite weiter ausbauen: Nutzer sollen Elemente und Reihenfolge der Startseite selbst zusammenstellen koennen; Detailkonzept und Feinschliff folgen spaeter
|
||
- B6: Diagnostics / Passwort-Reset-Diagnose
|
||
- B6.1: Detail-View mit exportierbaren Logs (bei Bedarf)
|
||
- C1: Offline-/Caching-Strategie
|
||
- C1.1: Verschlüsseltes lokales Caching für CMS-Daten (EncryptedSharedPreferences/Room)
|
||
- C1.2: Sync-Strategie: lokale Änderungen buffernd senden, Konflikt-UI
|
||
- C2: Tests & CI
|
||
- C2.1: ViewModel-Unit-Tests für alle CMS-Flows
|
||
- C2.2: Compose-UI-Tests für kritische Pfade (News erstellen, Benutzerrolle ändern, Config speichern)
|
||
- C2.3: androidTest Hilt-Stubs erweitern (falls nötig)
|
||
|
||
Minor UX-Verbesserungen (parallel möglich):
|
||
- konsistente Buttons/Labels (`Speichern` vs `Inhalt speichern`), Ladezustand-UI, einzeilige Success-/Error-Banner, Inline-Validierungen.
|
||
|
||
Deliverables & Milestones:
|
||
- M1 (nach Analyse): Priorisierte Aufgabenliste + Schätzung (mehrere PRs)
|
||
- M2 (nach MVP-Implementierung): News + Benutzer + ContactRequests + Config Editor + Tests (smoke)
|
||
- M3 (Final): Offline, UI-Tests, Accessibility, Performance
|
||
|
||
Zeitplanung (empfohlen):
|
||
- Analyse: 2 Arbeitstage
|
||
- MVP-Implementierung: 7–10 Arbeitstage
|
||
- Hardening + Tests: 3–5 Arbeitstage
|
||
|
||
Wenn du willst, trage ich die einzelnen Subtickets in unserem lokalen Issue-Tracker (oder als separate TODOs) ein und beginne mit A1/A2.
|
||
|
||
**TODO (zum Abhaken) — CMS-Implementierung**
|
||
|
||
- [x] A1: Audit `CmsViewModel` vs Backend-Responses (Fehleraggregation implementiert)
|
||
- [x] A2: Standardisiere API-Fehlerdarstellung in UI (`FormMessages` / globale Errors)
|
||
- [x] A3: Roundtrip-Tests `NativeRichTextEditor` ↔ Backend-HTML (Kompatibilität / Quill)
|
||
- [x] B1: News-Management
|
||
- [x] B1.1: News-CRUD (Create/Update/Delete) mit RichText-Vorschau
|
||
- [x] B1.2: Bulk-Aktionen (sichtbar/unsichtbar, expiresAt)
|
||
- [x] B1.3: Unit-Tests für `NewsViewModel`
|
||
|
||
- [x] B2: Benutzer-Management
|
||
- [x] B2.1: Rollen-Edit (Inline oder Detail-Dialog)
|
||
- [x] B2.2: Aktiv/Inaktiv Toggle, Resend-Invite
|
||
- [x] B2.3: Tests für Pagination/Leere Listen
|
||
|
||
- [x] B3: Kontaktanfragen
|
||
- [x] B3.1: Detailansicht + Antwort-Option
|
||
- [x] B3.2: Status-Filter + Archiv
|
||
|
||
- [ ] B4: Newsletter
|
||
- [x] B4.1: Entwurf → Senden Flow mit Preview
|
||
- [x] B4.2: Gruppenverwaltung (CRUD)
|
||
|
||
- [x] B5: Config / Seiten
|
||
- Web‑Status: Die Web‑UI bietet bereits umfassende CMS‑UIs für `cms/startseite`, `cms/vereinsmeisterschaften`, `cms/sportbetrieb` und `cms/einstellungen` (Drag&Drop, CSV‑Import/Export, Tabbed‑UIs, ImageUpload, native‑like Modals). `cms/startseite` speichert `homepage.sections` via `PUT /api/config`, `vereinsmeisterschaften` arbeitet mit CSV‑Export/Import, `sportbetrieb` kapselt Termine/Mannschaften/Spielpläne in Tabs, `einstellungen` ist ein umfangreicher Config‑Editor.
|
||
- Android‑Status: Implementiert — die Android‑App enthält native CMS‑Screens (`CmsStartseiteScreen`, `CmsVereinsmeisterschaftenScreen`, `CmsSportbetriebScreen`, `CmsEinstellungenScreen`) mit Save/Load‑Flows via `CmsViewModel`.
|
||
- Umsetzung (B5.x):
|
||
- [x] B5.1: `cms/startseite` (Startseiten‑Layout) — Reorderable/Visibility + Save → `PUT /api/config` (via `CmsViewModel`).
|
||
- [x] B5.2: `cms/vereinsmeisterschaften` — CSV‑Parser/CSV‑Save integration and modal CRUD (native UI present).
|
||
- [x] B5.3: `cms/sportbetrieb` — Tabbed UI reusing `Termine`, `Mannschaften`, `Spielplan` components.
|
||
- [x] B5.4: `cms/einstellungen` — Tabbed config editor with Vereinsdaten/Training/Trainer/Mitgliedschaft and save.
|
||
- [x] B5.5: Roundtrip & Tests — basic ViewModel unit tests and roundtrip checks exist; Compose UI smoke tests remain for hardening.
|
||
- [x] B5.6: Startseite weiter ausgebaut — zusaetzliche Elemente (`training`, `links`, `vereinsmeisterschaften`) sind konfigurierbar; Android kann Reihenfolge/Sichtbarkeit lokal speichern und Web nutzt Marker (`cookie`, `eingeloggt`) mit marker-spezifischer Persistenz: `eingeloggt` wird als individuelles User-Setting serverseitig gespeichert, `cookie` wird ausschliesslich im Browser-Cookie gehalten. Neu umgesetzt: konfigurierbare Startseiten-Widgets vom Typ `spielplan_team` (Saison + Mannschaft beim Hinzufuegen waehlbar, spaeter jederzeit aenderbar, mehrfach pro Startseite moeglich, persistiert ueber `key` + `config`).
|
||
|
||
- [x] B6: Diagnostics / Passwort-Reset-Diagnose (Export/Detail)
|
||
- Web‑Status: `cms/passwort-reset-diagnose` zeigt vollständige Diagnose‑UI mit Suche, Maskierung, Filter (nur Auffälligkeiten) und listbaren Reset‑Versuchen; Backend: `/api/cms/password-reset-diagnostics` liefert `matchingUsers`, `attempts`, `retentionHours`.
|
||
- Android‑Status: umgesetzt — native Diagnose‑UI mit Suche (`email`/Name), Filter `Nur Auffälligkeiten`, `matchingUsers`‑Liste mit Schnellfilter, detaillierter Schrittansicht je Versuch (Zeit/Schritt/Status/Grund), Refresh und Share‑Export der maskierten Logs.
|
||
- Konkrete Android‑ToDos (B6.x):
|
||
- [x] B6.1: Implementieren Suche + Filter UI, Rendering der `attempts` mit Zeitstempeln, Status‑Badges und Details.
|
||
- [x] B6.2: Logs exportieren / share (falls API Export unterstützt) und Datenschutz: E‑Mail Maskierung beibehalten.
|
||
|
||
- [x] C1: Offline-/Caching-Strategie (verschlüsselt für geschützte CMS-Daten)
|
||
- Umgesetzt: EncryptedSharedPreferences-basierter Offline-Cache mit Zeitstempel/TTL pro Cache-Key (CMS standard 24h, Reset-Diagnose 6h).
|
||
- Umgesetzt: Fallback auf verschlüsselte Cache-Daten bei Ladefehlern nur innerhalb der TTL, um veraltete geschützte CMS-Daten zu begrenzen.
|
||
- Umgesetzt: Gezielte Cache-Invalidierung bei schreibenden CMS-Operationen (Konfiguration, Benutzerverwaltung, Kontaktanfragen, Newsletter, interne News), damit Offline-Daten nach Änderungen konsistent bleiben.
|
||
- Umgesetzt: Passwort-Reset-Diagnose-Cache wird nur für den Standardfilter (ohne Suchbegriff) verwendet, um falsche Treffer bei gefilterten Diagnosen zu vermeiden.
|
||
- [x] C2: Tests & CI
|
||
- [x] C2.1: ViewModel-Unit-Tests für CMS-Flows (`CmsViewModel.load()` / `saveConfig()`)
|
||
- Status: `:app:testLocalDebugUnitTest` läuft grün; `CmsViewModelTest` wurde auf aktuelle Repository-Signaturen und vollständige `load()`-Abhängigkeiten (inkl. `vereinsmeisterschaften`) aktualisiert.
|
||
- [x] C2.2: Compose-UI-Tests für kritische Flows
|
||
- Status: neuer Instrumentation-Test für `CmsPasswordResetDiagnosticsScreen` ergänzt (`diagnosticsScreen_showsFilterAndAttemptDetails`) und gezielt per `connectedLocalDebugAndroidTest` erfolgreich ausgeführt.
|
||
- [x] C2.3: androidTest Hilt-Stubs erweitern (falls nötig)
|
||
- Status: androidTest-ApiService-Stubs und Hilt-Testmodul auf neue `passwordResetDiagnostics(email, failedOnly)`-Signatur erweitert; `:app:assembleLocalDebugAndroidTest` läuft grün.
|
||
|
||
Markiere die Items, wenn erledigt — ich kann die einzelnen Punkte jetzt in Branches/PRs umsetzen.
|
||
|