chore: update .gitignore and enhance backend and mobile app functionality
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 44s

- Added mobile app build directories and configuration files to .gitignore for cleaner repository management.
- Improved error handling in diaryMemberController by requiring diaryDateId and memberId query parameters.
- Refactored DiaryMemberService to log tag IDs instead of raw values for better debugging.
- Enhanced TournamentParticipantsTab and TournamentTab components with improved touch-action properties for better user experience.
- Updated mobile app's gradle.properties and build.gradle.kts for compatibility with AGP 9.x and Kotlin 2.1.21, including new dependencies for Coil and UCrop.
- Refactored MainApplication to simplify initialization and improved MainActivity to handle dependencies more robustly.
- Updated various UI components in the mobile app to enhance layout and functionality, including MemberDetailScreen and MemberEditScreen.
This commit is contained in:
Torsten Schulz (local)
2026-05-12 23:14:31 +02:00
parent 27f8af559b
commit 48f71b9df1
138 changed files with 54488 additions and 56 deletions

212
mobile-app/TODO.md Normal file
View File

@@ -0,0 +1,212 @@
# Mobile App TODO Web-Parität (Android, KMP-Shared)
Dieses Dokument ist die **Arbeitsliste**, um die **funktionale Abdeckung der Web-App** (`frontend/src/router.js`, Views unter `frontend/src/views/`) in der **nativen Android-App** (Jetpack Compose, Shared Code unter `mobile-app/shared`) nachzubauen.
**Wichtig:** Ein „komplettes“ Umsetzen dieser Liste ist ein **Mehrmonats-/Team-Projekt**. Es wird **iterativ** abgearbeitet; unten sind nur die Punkte angehakt, die im Code **tatsächlich** vorhanden sind (Stand siehe Git). Alles andere bleibt offen.
**Legende:** `[x]` umgesetzt · `[ ]` offen · Die „Baseline“ am Ende beschreibt den älteren Grundstock.
**Vorgehen:** Pro Phase vertikale Schnitte (API im `shared` Modul → Manager/Use-Case → UI). Web-Referenz immer die gleichnamige `*.vue`-Datei und `apiClient`-Aufrufe darin.
---
## Bereits umgesetzt (Baseline, Stand 2026-05)
- Auth (`authcode`), Token-Persistenz, 401 → Login
- Club-Auswahl, Permissions, Access-Request
- Tabs inkl. **Start**-Hub (`MainTab.Home`), Unter-Screens (Tagebuch-Tag, Mitglied-Detail), Tab-/Rail ausblenden in Details
- **Tagebuch:** Datenliste, Tag-Detail, Zeiten, Notizen, Tags (Tagesbezug), **Freitext-Aktivitäten** (`/activities`), Trainingsplan **lesen & CRUD** (Phase 3.2), Teilnehmer an/ab (einklappbare Liste, standard eingeklappt), **Zuordnung zu Plan-Aktivitäten** (3.4), **Unfälle/Vorfälle** (3.7), Löschen Tag
- **Mitglieder:** Liste, Suche, statisches Detail
- **Trainings-Statistik:** Basis-KPIs + Top-Liste
- **Einstellungen:** Sprache, Session-Check, Logout, Backend-Anzeige
- i18n-Generator + `MobileStrings`
- Theming näher an Web (`TtTagebuchTheme`)
---
## Phase 0 Architektur & Grundlagen für Vollausbau
- [ ] **Navigation:** Zentraler Nav-Graph (z. B. Navigation Compose) mit Back-Stack pro Tab oder einheitlichem Stack; Tiefe: Club → Modul → Unterseiten
- [ ] **Feature-Paketierung:** UI/API pro Bereich trennen (`diary`, `members`, `schedule`, …), Composables entschlacken
- [ ] **Use-Cases:** Geschäftslogik aus Composables in testbare Funktionen/Klassen im `shared`
- [x] **Fehlerbild (Basis):** JSON-Fehlerbody (`error` / `message`) aus API-Antworten → [ApiException]-Text (`ApiErrorMessage.kt`, authed + public Client); bekannte Tokens (`alreadyexists`, …) → Deutsch; Retries bewusst noch offen
- [ ] **Echtzeit (optional):** Socket-Events wie Web (`socketService`) oder dokumentiertes Polling nach Schreiboperationen
- [ ] **Medien:** Entscheidung Bilder/PDF (Coil, Cache, Download, Intents)
- [x] **Öffentlicher HTTP-Client** ohne Auth-Header (`PublicHttpClient`, `PublicAuthApi` im `shared`)
---
## Phase 1 Auth, Onboarding, öffentliche Seiten
Web-Routen: `/login`, `/register`, `/activate/:code`, `/forgot-password`, `/reset-password/:token`, `/impressum`, `/datenschutz`, `/` (Home öffentlich)
- [x] **Registrierung** (`Register.vue`) Android: `RegisterScreen`, `POST /api/auth/register`
- [x] **Account aktivieren** (`Activate.vue`) Android: `ActivateAccountScreen`, `GET /api/auth/activate/:code`
- [x] **Passwort vergessen / E-Mail** (`ForgotPassword.vue`) `ForgotPasswordScreen`, `POST /api/auth/forgot-password`
- [x] **Passwort setzen mit Token** (`ResetPassword.vue`) `ResetPasswordScreen`, `POST /api/auth/reset-password`
- [x] **Home / Landing eingeloggt** (`Home.vue`) Tab **Start**: Willkommen, Kacheln zu Tagebuch/Mitglieder/Statistik/Mehr, Vereinsinfos via `GET /api/clubs/:id` (`HomeScreen`, `ClubsApi.getClub`)
- [x] **Impressum** Einstellungen → öffnet `BACKEND_BASE_URL/impressum` im Browser
- [x] **Datenschutz** Einstellungen → öffnet `BACKEND_BASE_URL/datenschutz` im Browser
- [ ] SEO-Marketingseiten (`TableTennisClubSoftware`, `ClubMemberManagementPage`, …): **nur falls** im Store gefordert; sonst `[ ] optional / nicht mobil`
---
## Phase 2 Verein anlegen & Vereins-Ansicht
- [x] **Verein erstellen** (`CreateClub.vue`) + API `POST /api/clubs`, `ClubSelectScreen` + `ClubManager.createClub`
- [x] **Vereins-Profil / Show Club** (`ClubView.vue`) Basis: erweitertes `Club`-Modell + Karte auf **Start** (Begrüßung, Verbands-Nr., MyTischtennis-Kürzel); volle Parität (Links, Zahlen) offen
---
## Phase 3 Tagebuch (DiaryView) Hauptblock
Web: `DiaryView.vue` (sehr groß). API-Cluster (Auszug in Web nach `apiClient` verifizieren):
### 3.1 Tages-Metadaten & Listen
- [x] Tagebuch-Daten **vollständig** laden beim Datumswechsel Plan, Trainingsgruppen und Teilnehmer **parallel** in einem `LaunchedEffect` (`DiaryDetailScreen`)
- [x] **Aktivitäten-Liste** `/activities/:dateId``DiaryApi.listFreeformActivities` / `addFreeformActivity`, Abschnitt „Weitere Tages-Aktivitäten“ im Tagebuch-Detail
### 3.2 Trainingsplan (CRUD)
- [x] Plan laden: `GET /diary-date-activities/:clubId/:diaryDateId``DiaryApi` / Tagebuch-Detail
- [x] Einträge anlegen: `POST /diary-date-activities/:clubId`, ggf. **Gruppe** `POST /diary-date-activities/group` — Android-Formulare + `CreateDiaryPlanActivityRequest` / `AddDiaryPlanGroupActivityRequest`
- [x] Einträge bearbeiten: `PUT /diary-date-activities/:clubId/:id` (Zuordnung `groupId` im Body wie Backend) — Dialog „Bearbeiten“; Unter-Einträge (`GroupActivity`): API `updateNestedGroupActivity`, mobil z.B. nur **Löschen**
- [x] Reihenfolge: `PUT .../order` — ↑/↓ je Trainingsgruppen-Scope
- [x] Löschen: `DELETE ...`, Gruppen-Aktivität `DELETE .../group/...`
- [x] **Zeitblöcke** (`isTimeblock`) inkl. UX wie Web — Checkbox beim Anlegen, Kennzeichnung in der Karte
- [x] **Gruppen** für Plan: `GET/POST/DELETE /api/group``GroupApi` + Liste mit Löschen; **PUT** Umbenennen (`changeGroup`) nur API, keine eigene UI
### 3.3 Teilnehmer & Status
- [x] Liste: `GET /participants/:dateId`
- [x] Hinzufügen/Entfernen: `POST /participants/add`, `POST /participants/remove`
- [x] Status **entschuldigt/abgesagt**: `PUT /participants/:dateId/:memberId/status`
- [x] **Gruppenzuordnung Training**: `PUT /participants/:dateId/:memberId/group``ParticipantsApi.updateParticipantGroup`, Dropdown bei anwesenden Teilnehmern wenn Trainingsgruppen existieren
- [x] **UX:** Teilnehmerliste im Tagebuch-Detail **aufklappbar**, standard **eingeklappt** (`DiaryDetailScreen`)
- [x] `GET /diary-member-activities/:clubId/:activityId``DiaryMemberActivitiesApi` / „Wer macht mit?“ je Planzeile bzw. Gruppen-Aktivität
- [x] Zuweisen: `POST ...` mit `participantIds` — inkl. `ensureParticipantRowId` wenn noch keine Teilnehmer-Zeile
- [x] Entfernen: `DELETE .../:participantId`
### 3.5 Mitgliedsbezogene Notizen/Tags im Tagebuch
- [x] `GET/POST .../diarymember/:clubId/note`, `DELETE .../note/:id` (mit `diaryDateId`/`memberId` als Query) — `DiaryMemberApi` / Dialog „Notizen & Tags“ je Teilnehmer
- [x] `GET/POST .../diarymember/:clubId/tag`, `POST .../tag/remove` — bestehende Tags, neu anlegen (`POST /tags` + Verknüpfung)
### 3.6 Predefined Activities (Auswahl & Suche im Tagebuch)
- [x] `GET /predefined-activities`, `GET ...?scope=standard`, `GET /search/query` — Trainingsplan anlegen (global + Gruppe) und Eintrag bearbeiten (Suche / vordefinierte ID)
- [x] `GET /predefined-activities/:id``PredefinedActivitiesApi.getById` / `DiaryManager.getPredefinedActivity` (für spätere Detail-UI)
### 3.7 Unfälle / Vorfälle
- [x] `POST /accident`, `GET /accident/:clubId/:diaryDateId``AccidentApi` / `DiaryManager` / Abschnitt im Tagebuch-Detail
### 3.8 Galerie & Bilder
- [x] Mitgliederbilder: `memberProfileImagePath` + `AuthenticatedAsyncImage` (Coil mit `diaryAuthHeaders`) in der Teilnehmerliste bei `diary.read` + `members.read`
- [x] Übungs-/Predefined-Bilder: `DiaryImagePaths` (`mainActivityImagePath` / `nestedActivityImagePath`) + `ApiConfig.toAbsoluteUrl`, Vollbild-Dialog im Tagebuch-Detail
- [x] **Gruppenfotos:** `MemberGroupPhotosApi` (`GET/POST/DELETE /api/member-group-photos/:clubId`), Galerie-Abschnitt + `PickVisualMedia` in `DiaryDetailScreen`
### 3.9 PDF / Export
- [x] Trainingsplan- und Tages-PDF (`DiaryPdfExporter` / `writeTrainingPlanPdf`, `writeTrainingDaySummaryPdf`), Teilen über `FileProvider` + `sharePdfFile` (`DiaryPdfShare`)
### 3.10 Sonstiges Diary-UX
- [x] **Web-DiaryView → mobil (Kurzüberblick):** Tages-Metadaten, Plan inkl. Zeitblöcke/Gruppen, Teilnehmer inkl. Status/Gruppe, „Wer macht mit?“, Freitext-Aktivitäten, Tags/Notizen, Unfälle, Mitglieds-Notizen/Tags-Dialog, Galerie, PDF-Exporte ohne die vielen Web-Tabs als 1:1-Spiegel; fehlende Parität steht in den Phasen 4+ / offenen Punkten.
- [x] **Berechtigungen:** `ClubPermissionHelpers` (`canReadDiary`, `canWriteDiary`, `canReadMembers`, `canWriteMembers`) Lese-Hinweis, Schreib-Aktionen und Gruppenfoto-Löschen in `AppRoot.kt` / `DiaryDetailScreen` entsprechend gekapselt
---
## Phase 4 Mitglieder (MembersView) — erledigt
- [x] **Mitglied-CRUD:** `POST /api/clubmembers/set/:clubId``MembersApi.setMember`, `MemberSetBody` / `Member.toSetBody`, `MembersManager.saveMember`; neu + bearbeiten in `MemberEditRoute` (`AppRoot.kt`)
- [x] **Felder / Formulare:** Stammdaten, Adresse, **mehrere Telefon- und E-Mail-Zeilen** (Primär, Elternkontakt, Name) wie Web-`contacts`, Status (aktiv, Testmitglied, Formular, Freigaben, Bilder Internet), Geschlecht; TTR/QTTR nur Anzeige beim Bearbeiten
- [x] **Profilbild:** `POST /api/clubmembers/image/...` (Multipart) — `MembersApi.uploadMemberPortrait`, Galerie-Pick + UCrop in `MemberDetailRoute` / `MemberPortraitCrop.kt`
- [x] **Aktivität / letzte Teilnahmen:** `GET /api/member-activities/:clubId/:memberId` (Perioden-Query), `.../last-participations``MemberActivitiesApi`, Abschnitte im Profil
- [x] **Trainingsgruppen:** `GET/POST/DELETE /api/training-groups/...``TrainingGroupsApi`, Zuweisen/Entfernen im Profil
- [x] **Trainingszeiten (Verein):** `GET /api/training-times/:clubId``TrainingTimesApi`, Anzeige je Gruppe im Profil
- [x] **Bild zuschneiden:** Yalantis **UCrop** nach `PickVisualMedia` — JitPack, `UCropActivity` im Manifest
---
## Phase 5 Trainings-Statistik (Parität TrainingStatsView)
- [ ] Alle Kennzahlen/Tabellen/Filter aus Web
- [ ] Zeiträume, Exporte, falls vorhanden
---
## Phase 6 Terminplan (ScheduleView)
- [ ] Kalender-/Listenansicht, CRUD oder Sync wie Web
- [ ] API-Endpunkte aus `ScheduleView.vue` ins `shared` übernehmen
---
## Phase 7 Turniere
- [ ] `TournamentsView.vue` Vereinsturniere
- [ ] `OfficialTournaments.vue` / offizielle Teilnahmen
- [ ] `TournamentTab.vue` eingebettete Logik, soweit mobil relevant
- [ ] API aus jeweiligen Views dokumentieren und abarbeiten
---
## Phase 8 Freigaben & Verwaltung
- [ ] **Ausstehende Freigaben** (`PendingApprovalsView.vue`)
- [ ] **Team-Management** (`TeamManagementView.vue`)
- [ ] **Berechtigungen** (`PermissionsView.vue`) rollenbasiert
- [ ] **Logs** (`LogsView.vue`) eher Admin; nur wenn nötig mobil
---
## Phase 9 Vereins- & Stammdaten-Einstellungen
- [ ] **ClubSettings** (`ClubSettings.vue`) alle Unterbereiche
- [ ] **Predefined Activities Verwaltung** (`PredefinedActivities.vue`) CRUD, Bilder/Zeichnungen falls API
- [ ] **Mitgliedstransfer-Einstellungen** (`MemberTransferSettingsView.vue`)
---
## Phase 10 Persönliche Konten & Integrationen
- [ ] **Persönliche Einstellungen** vollständig (`PersonalSettings.vue` vs. aktuelles „Mehr“)
- [ ] **MyTischtennis-Konto** (`MyTischtennisAccount.vue`)
- [ ] **ClickTT-Konto** (`ClickTtAccount.vue`)
- [ ] **ClickTT-Ansicht** (`ClickTtView.vue`)
---
## Phase 11 Abrechnung & Bestellungen
- [ ] **Orders** (`OrdersView.vue`)
- [ ] **Billing** (`BillingView.vue`)
- [ ] Rechtliches/UX: ggf. WebView oder Deep-Link, wenn Zahlungsflüsse web-only
---
## Phase 12 Qualität, Tests, Release
- [ ] **Regression-Checkliste** pro Phase (manuell)
- [ ] Automatisierte Tests: `shared` (Serialisierung, Mapper), wo möglich UI-Tests kritische Flows
- [ ] **Barrierefreiheit:** Talkback, Kontraste, Touch-Ziele
- [ ] **Performance:** große Listen (Paging), Bildcache
- [ ] Store-Texte, Datenverarbeitung (Play Policy) für Medien und Kontakte
---
## Hinweise zur Pflege dieser Liste
1. Beim Abhaken eines Punktes **kurz** vermerken (Commit-Message oder Unterpunkt), welche Datei/API neu ist.
2. Wenn Web eine Funktion **einstellt** oder API ändert: TODO hier und `DEVELOPMENT.md` anpassen.
3. **DiaryView** zuerst in **Unterkapitel** zerlegen (3.13.10), dann Issues/PRs pro Unterkapitel sonst bleibt der Block unendlich.
---
## Referenz: Web-Routen (Router)
Siehe `frontend/src/router.js` jede `path`-Zeile sollte langfristig einem mobilen Eintrag (oder einer bewussten Ausnahme) zugeordnet sein.