feat(android): configure API and socket endpoints for debug and release builds
- Added API and socket base URLs for both debug and release configurations in gradle.properties. - Enhanced build.gradle.kts to utilize environment variables for dynamic endpoint configuration. - Updated debug build type with specific application ID suffix and version name suffix for better differentiation. - Included necessary dependencies for improved functionality and compatibility.
This commit is contained in:
51
docs/club_members_block_port.md
Normal file
51
docs/club_members_block_port.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Club/Members/Admin Block Port
|
||||
|
||||
Stand: 2026-03-06
|
||||
|
||||
## Umgesetzte Features
|
||||
- `MembersView.vue`: Android vorhanden (`MembersScreen`, `MembersViewModel`) inkl. Member-Liste, Edit/Create, Kontakte, Trainingsgruppen, Notizen, Bilder, Quick-Actions.
|
||||
- `ClubView.vue`: Android vorhanden (`ShowClubScreen`, `ShowClubViewModel`) inkl. Club-Details, Access-Request-Flow, offene Anfragen.
|
||||
- `ClubSettings.vue`: Android vorhanden (`ClubSettingsScreen`, `ClubSettingsViewModel`) inkl. Settings + Trainingsgruppen + Trainingszeiten.
|
||||
- `CreateClub.vue`: Android vorhanden (`CreateClubScreen`, `CreateClubViewModel`) inkl. Create-Flow.
|
||||
- `MemberTransferSettingsView.vue`: Android vorhanden (`MemberTransferSettingsScreen`, `MemberTransferSettingsViewModel`) inkl. Config + Execute.
|
||||
- `PendingApprovalsView.vue`: Android vorhanden (`PendingApprovalsScreen`, `PendingApprovalsViewModel`) inkl. Approve/Reject.
|
||||
- `PermissionsView.vue`: neu als Android umgesetzt (`PermissionsScreen`, `PermissionsViewModel`, `PermissionsService`) inkl. Rollen laden, Struktur laden, Mitglieder laden, Rolle ändern, Status ändern, Custom-Permissions speichern.
|
||||
- `TeamManagementView.vue`: neu als Android umgesetzt (`TeamManagementScreen`, `TeamManagementViewModel`, `TeamManagementService`) inkl. Teams/Ligen laden, Team create/update/delete, Team-Dokumente laden/parsen, Scheduler-Job-Info, MyTischtennis URL-Parse + Team/Liga konfigurieren + Async-Fetch-Job polling, Spieler-Statistik laden.
|
||||
- Navigation ergänzt: Home bietet jetzt direkte Einstiege für Members, Permissions, Team-Management, Member-Transfer.
|
||||
|
||||
## Genutzte API-Endpunkte
|
||||
- Club/Members/Admin bestehend:
|
||||
- `GET /clubs`, `POST /clubs`, `GET /clubs/{clubId}`, `GET /clubs/request/{clubId}`
|
||||
- `GET /clubs/pending/{clubId}`, `POST /clubs/approve`, `POST /clubs/reject`
|
||||
- `PUT /clubs/{clubId}/settings`
|
||||
- `GET/POST/PUT/DELETE /training-groups/{clubId}*`
|
||||
- `GET/POST/PUT/DELETE /training-times/{clubId}*`
|
||||
- `GET/POST/DELETE /member-transfer-config/{clubId}`, `POST /clubmembers/transfer/{clubId}`
|
||||
- `GET/POST/DELETE /membernotes*`, `GET/POST/DELETE /clubmembers/image/{clubId}/{memberId}*`, `GET /clubmembers/gallery/{clubId}`
|
||||
- Permissions neu:
|
||||
- `GET /permissions/roles/available`
|
||||
- `GET /permissions/structure/all`
|
||||
- `GET /permissions/{clubId}/members?t=...`
|
||||
- `PUT /permissions/{clubId}/user/{userId}/role`
|
||||
- `PUT /permissions/{clubId}/user/{userId}/status`
|
||||
- `PUT /permissions/{clubId}/user/{userId}/permissions`
|
||||
- Team-Management neu:
|
||||
- `GET /club-teams/club/{clubId}?seasonid=...`
|
||||
- `GET /club-teams/leagues/{clubId}?seasonid=...`
|
||||
- `POST /club-teams/club/{clubId}`
|
||||
- `PUT /club-teams/{clubTeamId}`
|
||||
- `DELETE /club-teams/{clubTeamId}`
|
||||
- `GET /team-documents/club-team/{clubTeamId}`
|
||||
- `POST /team-documents/{documentId}/parse?leagueid=...`
|
||||
- `GET /logs/scheduler/last-executions?clubId=...`
|
||||
- `GET /matches/leagues/{clubId}/stats/{leagueId}?seasonid=...`
|
||||
- `POST /mytischtennis/parse-url`
|
||||
- `POST /mytischtennis/configure-team`
|
||||
- `POST /mytischtennis/configure-league`
|
||||
- `POST /mytischtennis/fetch-team-data/async`
|
||||
- `GET /mytischtennis/fetch-team-data/jobs/{jobId}`
|
||||
|
||||
## Offene Abweichungen zur Vue-Version
|
||||
- TeamManagement-Datei-Upload/Download (Datei-Picker/PDF-Viewer) ist im aktuellen Android-Block nicht vollparitätisch umgesetzt; Dokumente werden geladen und Parse-Flow ist umgesetzt.
|
||||
- Permissions-Dialog ist funktional umgesetzt, aber UI/Interaktionsdetails (Tri-State-Darstellung, Legende, Styling) sind vereinfacht gegenüber Vue.
|
||||
- TeamManagement-SeasonSelector ist aktuell als freie `seasonId`-Eingabe umgesetzt, nicht als kompletter SeasonSelector-Dialog wie im Web.
|
||||
64
docs/final_migration_review.md
Normal file
64
docs/final_migration_review.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Final Migration Review (Android)
|
||||
|
||||
Stand: 2026-03-06 (nach Open-Gaps-Abarbeitung)
|
||||
|
||||
## Scope
|
||||
Geprüft wurden:
|
||||
- `docs/implementation_status.md` (alle 26 Views)
|
||||
- `docs/mobile_spec.md`
|
||||
- `docs/frontend_dependency_graph.md`
|
||||
- Android-Code unter `android-app` (Navigation, Screens, ViewModels, Services/Repository, Network, Socket, Session/Auth)
|
||||
|
||||
## Direkt behobene Inkonsistenzen (klein/mittel)
|
||||
1. Home-Navigation vervollständigt für bereits implementierte Screens:
|
||||
- `training-stats`, `predefined-activities`, `mytischtennis-account`, `logs`, `personal-settings`, `impressum`, `datenschutz`
|
||||
|
||||
2. Selektive Feature-Deep-Links ergänzt:
|
||||
- `home`, `showclub/{clubId}`, `members`, `diary`, `schedule`, `tournaments`, `training-stats`
|
||||
|
||||
3. Startup-Routing verbessert (club-basiert):
|
||||
- `currentClub == "new"` -> `createclub`
|
||||
- `currentClub` gesetzt -> `training-stats`
|
||||
- sonst -> `home`
|
||||
|
||||
4. Socket/API-Basis-URLs zentralisiert:
|
||||
- `BuildConfig.API_BASE_URL`
|
||||
- `BuildConfig.SOCKET_BASE_URL`
|
||||
|
||||
## Systematische Prüfung
|
||||
|
||||
### 1) Views laut `implementation_status.md`
|
||||
- Ergebnis: 26/26 Views als Android-Screens/Flows vorhanden.
|
||||
- Quercheck Navigation: alle in `AppRoute` und `AppNavGraph` enthalten.
|
||||
- Quercheck Architektur: pro Bereich ViewModel + Service/Repository vorhanden.
|
||||
|
||||
### 2) Navigation + Deep Links
|
||||
- Interne Navigation: vollständig für dokumentierte Routen vorhanden.
|
||||
- Auth-Deep-Links und selektive Feature-Deep-Links sind in `AppNavGraph` + Manifest hinterlegt.
|
||||
|
||||
### 3) API-Integration
|
||||
- `ApiService` deckt die benötigten Endpunkte in den portierten Bereichen ab.
|
||||
- Repository/Service-Schicht ist durchgängig angebunden.
|
||||
|
||||
### 4) Socket-Integration
|
||||
- Zentrale Architektur vorhanden (`SocketManager` + Domain-Event-Mapping im Repository).
|
||||
- Event-Subscriptions in den relevanten ViewModels (Diary/Schedule/Tournament) sind aktiv.
|
||||
- Reconnect/Backoff + Foreground-Lifecycle-Verhalten sind implementiert.
|
||||
|
||||
### 5) Session/Auth-Flows
|
||||
- Request-Auth global über `NetworkModule`-Interceptor (`authcode`, `userid`).
|
||||
- 401/403-Handling inkl. API-Code-Prüfung vorhanden.
|
||||
- Unauthorized -> Session-Clear + globales Login-Redirect über `AuthEventBus`/`AppNavGraph`.
|
||||
- Socket Connect/Disconnect an Login/Logout gekoppelt.
|
||||
|
||||
### 6) Error/Loading/Retry
|
||||
- In den Screens konsistent mit ErrorBanner/ErrorSnackbarHost, Loading-Indikatoren und Retry-Actions umgesetzt.
|
||||
|
||||
### 7) Abweichungen zu `mobile_spec.md` / `frontend_dependency_graph.md`
|
||||
- Kernabhängigkeiten sind portiert.
|
||||
- Verbleibende größere/strategische Punkte sind in `docs/open_gaps.md` dokumentiert.
|
||||
|
||||
## Ergebnis
|
||||
- Migration ist funktional konsistent und vollständig nutzbar.
|
||||
- Kleine/mittlere offene Punkte aus dem vorherigen Review wurden abgearbeitet.
|
||||
- Verbleibende Themen sind bewusst priorisierte Restpunkte (siehe `docs/open_gaps.md`).
|
||||
@@ -5,47 +5,45 @@ Stand: 2026-03-06
|
||||
Quellen:
|
||||
- `docs/frontend_dependency_graph.md`
|
||||
- `docs/mobile_spec.md`
|
||||
- `android-app` (Navigation/Screens/ViewModels/Repository)
|
||||
- `android-app` (Navigation/Screens/ViewModels/Services/Repository)
|
||||
|
||||
Status-Legende:
|
||||
- `Implemented`: eigener Android Screen + ViewModel + Repository-Anbindung vorhanden
|
||||
- `Partial`: funktional vorhanden, aber klar reduzierte/paritätisch unvollständige Umsetzung
|
||||
- `Placeholder`: Route vorhanden, aber nur Platzhalter-Screen
|
||||
- `Missing`: keine Android-Route/kein Android-Screen vorhanden
|
||||
## Status-Legende
|
||||
- `Fully implemented`: eigener Android Screen + ViewModel + Service/Repository-Anbindung, fachlicher Kernflow vorhanden
|
||||
- `Partially implemented`: Screen/ViewModel vorhanden, aber wesentliche Web-Teilfunktion(en) reduziert/noch offen
|
||||
- `Placeholder`: Route vorhanden, aber Platzhalter-Screen ohne Fachlogik
|
||||
- `Missing`: keine echte Android-Umsetzung für diese View/Funktion
|
||||
|
||||
| Vue View | Android Screen/Route | Status | Details |
|
||||
|---|---|---|---|
|
||||
| Activate.vue | `ActivateScreen` / `activate/{activationCode}` | Implemented | Dateien: `ui/screens/ActivateScreen.kt`, `viewmodel/ActivateViewModel.kt`, `repository/TrainingstagebuchRepository.kt` (`activate`). API: `GET /auth/activate/{activationCode}`. Socket: - |
|
||||
| ClubSettings.vue | `ClubSettingsScreen` / `club-settings` | Implemented | Dateien: `ui/screens/ClubSettingsScreen.kt`, `viewmodel/ClubSettingsViewModel.kt`, `repository/TrainingstagebuchRepository.kt` (`loadClubSettings`, `saveClubSettings`, `loadClubTrainingGroups`, `create/update/deleteClubTrainingGroup`, `load/create/update/deleteClubTrainingTime`). API: `GET /clubs/{clubId}`, `PUT /clubs/{clubId}/settings`, `GET/POST/PUT/DELETE /training-groups/{clubId}*`, `GET/POST/PUT/DELETE /training-times/{clubId}*`. Socket: - |
|
||||
| ClubView.vue | `ShowClubScreen` / `showclub/{clubId}` | Implemented | Dateien: `ui/screens/ShowClubScreen.kt`, `viewmodel/ShowClubViewModel.kt`, `repository/TrainingstagebuchRepository.kt` (`loadClub`, `requestClubAccess`). API: `GET /clubs/{clubId}`, `GET /clubs/request/{clubId}`. Socket: - |
|
||||
| CreateClub.vue | `CreateClubScreen` / `createclub` | Implemented | Dateien: `ui/screens/CreateClubScreen.kt`, `viewmodel/CreateClubViewModel.kt`, `repository/TrainingstagebuchRepository.kt` (`createClub`). API: `POST /clubs`. Socket: - |
|
||||
| Datenschutz.vue | `DatenschutzScreen` / `datenschutz` | Placeholder | Platzhalter über `ui/screens/PlaceholderScreens.kt`. |
|
||||
| DiaryView.vue | `DiaryScreen` / `diary` | Partial | Dateien: `ui/screens/DiaryScreen.kt`, `viewmodel/DiaryViewModel.kt`, `repository/TrainingstagebuchRepository.kt` (Diary-Block: Dates, Participants, Activities, Tags, Notes, Plan, Groups, Group-Activity, Activity-Member-Assignments, Accident, Stats, Predefined Search). API (zentral): `GET/POST/PUT/DELETE /diary/{clubId}*`, `/participants/*`, `/activities/*`, `/group/*`, `/tags`, `/diary/tag/*`, `/diarymember/{clubId}/note*`, `/diary-date-activities/*`, `/diary-date-activities/group*`, `/diary-member-activities/*`, `/accident*`, `/member-activities/*`, `/predefined-activities/search/query`. Socket: `participant:*`, `diary:*`, `activity-member:*`, `activity:changed`, `member:changed`, `group:changed` (über `network/SocketManager.kt` + `viewmodel/DiaryViewModel.kt`). |
|
||||
| ForgotPassword.vue | `ForgotPasswordScreen` / `forgot-password` | Implemented | Dateien: `ui/screens/ForgotPasswordScreen.kt`, `viewmodel/ForgotPasswordViewModel.kt`, `repository/TrainingstagebuchRepository.kt` (`forgotPassword`). API: `POST /auth/forgot-password`. Socket: - |
|
||||
| Home.vue | `HomeScreen` / `home` | Implemented | Dateien: `ui/screens/HomeScreen.kt`, `viewmodel/HomeViewModel.kt`, `repository/TrainingstagebuchRepository.kt` (`loadHomeData`). API: `GET /clubs`. Socket: - |
|
||||
| Impressum.vue | `ImpressumScreen` / `impressum` | Placeholder | Platzhalter über `ui/screens/PlaceholderScreens.kt`. |
|
||||
| Login.vue | `LoginScreen` / `login` | Implemented | Dateien: `ui/screens/LoginScreen.kt`, `viewmodel/LoginViewModel.kt`, `repository/TrainingstagebuchRepository.kt` (`login`). API: `POST /auth/login` (plus Session-Validierung global über `GET /session/status`). Socket: Connect-on-login erfolgt über `repository/connectSocketOnLogin`. |
|
||||
| LogsView.vue | `LogsScreen` / `logs` | Placeholder | Platzhalter über `ui/screens/PlaceholderScreens.kt`. |
|
||||
| MemberTransferSettingsView.vue | `MemberTransferSettingsScreen` / `member-transfer-settings` | Implemented | Dateien: `ui/screens/MemberTransferSettingsScreen.kt`, `viewmodel/MemberTransferSettingsViewModel.kt`, `repository/TrainingstagebuchRepository.kt` (`load/save/deleteMemberTransferConfig`, `executeMemberTransfer`). API: `GET/POST/DELETE /member-transfer-config/{clubId}`, `POST /clubmembers/transfer/{clubId}`. Socket: - |
|
||||
| MembersView.vue | `MembersScreen` / `members` | Partial | Dateien: `ui/screens/MembersScreen.kt`, `viewmodel/MembersViewModel.kt`, `repository/TrainingstagebuchRepository.kt` (Members-Block). API (zentral): `GET /clubmembers/get/{clubId}/{showAll}`, `POST /clubmembers/set/{clubId}`, `POST /clubmembers/quick-update-test-membership/{clubId}/{memberId}`, `POST /clubmembers/quick-deactivate/{clubId}/{memberId}`, `POST/DELETE /clubmembers/image/{clubId}/{memberId}*`, `GET /clubmembers/gallery/{clubId}`, `GET/POST/DELETE /membernotes*`, `GET /training-groups/{clubId}`, `GET /training-groups/{clubId}/member/{memberId}`, `POST/DELETE /training-groups/{clubId}/{groupId}/member/{memberId}`. Socket: - |
|
||||
| MyTischtennisAccount.vue | `MyTischtennisAccountScreen` / `mytischtennis-account` | Placeholder | Platzhalter über `ui/screens/PlaceholderScreens.kt`. |
|
||||
| OfficialTournaments.vue | - | Missing | Fehlende Abhängigkeiten aus Graph: Components `BaseDialog.vue`, `ConfirmDialog.vue`, `InfoDialog.vue`, `MemberSelectionDialog.vue`, `PDFGenerator.js`; Services `-`; Store `getter: currentClub`; Socket `-`. |
|
||||
| PendingApprovalsView.vue | `PendingApprovalsScreen` / `pending-approvals` | Implemented | Dateien: `ui/screens/PendingApprovalsScreen.kt`, `viewmodel/PendingApprovalsViewModel.kt`, `repository/TrainingstagebuchRepository.kt` (`loadPendingApprovals`, `approvePendingUser`, `rejectPendingUser`). API: `GET /clubs/pending/{clubId}`, `POST /clubs/approve`, `POST /clubs/reject`. Socket: - |
|
||||
| PermissionsView.vue | `PermissionsScreen` / `permissions` | Placeholder | Platzhalter über `ui/screens/PlaceholderScreens.kt`. |
|
||||
| PersonalSettings.vue | `PersonalSettingsScreen` / `personal-settings` | Placeholder | Platzhalter über `ui/screens/PlaceholderScreens.kt`. |
|
||||
| PredefinedActivities.vue | `PredefinedActivitiesScreen` / `predefined-activities` | Implemented | Dateien: `ui/screens/PredefinedActivitiesScreen.kt`, `viewmodel/PredefinedActivitiesViewModel.kt`, `services/PredefinedActivitiesService.kt`, `repository/TrainingstagebuchRepository.kt` (`load/search/create/update/merge/deduplicate/deleteImage`). API: `GET /predefined-activities`, `GET /predefined-activities/{id}`, `GET /predefined-activities/search/query`, `POST /predefined-activities`, `PUT /predefined-activities/{id}`, `POST /predefined-activities/merge`, `POST /predefined-activities/deduplicate`, `DELETE /predefined-activities/{id}/image/{imageId}`. Socket: - |
|
||||
| Register.vue | `RegisterScreen` / `register` | Implemented | Dateien: `ui/screens/RegisterScreen.kt`, `viewmodel/RegisterViewModel.kt`, `repository/TrainingstagebuchRepository.kt` (`register`). API: `POST /auth/register`. Socket: - |
|
||||
| ResetPassword.vue | `ResetPasswordScreen` / `reset-password/{token}` | Implemented | Dateien: `ui/screens/ResetPasswordScreen.kt`, `viewmodel/ResetPasswordViewModel.kt`, `repository/TrainingstagebuchRepository.kt` (`resetPassword`). API: `POST /auth/reset-password`. Socket: - |
|
||||
| ScheduleView.vue | `ScheduleScreen` / `schedule` | Placeholder | Platzhalter über `ui/screens/PlaceholderScreens.kt`. |
|
||||
| TeamManagementView.vue | `TeamManagementScreen` / `team-management` | Placeholder | Platzhalter über `ui/screens/PlaceholderScreens.kt`. |
|
||||
| TournamentTab.vue | - | Missing | Fehlende Abhängigkeiten aus Graph: Components `TournamentConfigTab.vue`, `TournamentGroupsTab.vue`, `TournamentParticipantsTab.vue`, `TournamentResultsTab.vue`, `TournamentPlacementsTab.vue`, `ConfirmDialog.vue`, `InfoDialog.vue`, `PDFGenerator.js`; Services `socketService.js`; Store `getters: currentClub, isAuthenticated`; Socket `tournament:changed`. |
|
||||
| TournamentsView.vue | `TournamentsScreen` / `tournaments` | Placeholder | Platzhalter über `ui/screens/PlaceholderScreens.kt`. |
|
||||
| TrainingStatsView.vue | `TrainingStatsScreen` / `training-stats` | Implemented | Dateien: `ui/screens/TrainingStatsScreen.kt`, `viewmodel/TrainingStatsViewModel.kt`, `services/TrainingStatsService.kt`, `repository/TrainingstagebuchRepository.kt` (`loadTrainingStats`, `loadMemberActivityStats`). API: `GET /training-stats/{clubId}`, `GET /member-activities/{clubId}/{memberId}?period=all`, `GET /member-activities/{clubId}/{memberId}/last-participations?limit=3`. Socket: - |
|
||||
| Vue View | Android Screen/Route | Status | Wichtigste Android-Dateien | API-/Socket-Abhängigkeiten |
|
||||
|---|---|---|---|---|
|
||||
| Activate.vue | `ActivateScreen` / `activate/{activationCode}` | Fully implemented | `ui/screens/ActivateScreen.kt`, `viewmodel/ActivateViewModel.kt`, `repository/TrainingstagebuchRepository.kt` | API: `GET /auth/activate/{activationCode}`; Socket: - |
|
||||
| ClubSettings.vue | `ClubSettingsScreen` / `club-settings` | Fully implemented | `ui/screens/ClubSettingsScreen.kt`, `viewmodel/ClubSettingsViewModel.kt`, `services/ClubSettingsService.kt`, `repository/TrainingstagebuchRepository.kt` | API: `GET /clubs/{clubId}`, `PUT /clubs/{clubId}/settings`, `GET/POST/PUT/DELETE /training-groups/{clubId}*`, `GET/POST/PUT/DELETE /training-times/{clubId}*`; Socket: - |
|
||||
| ClubView.vue | `ShowClubScreen` / `showclub/{clubId}` | Fully implemented | `ui/screens/ShowClubScreen.kt`, `viewmodel/ShowClubViewModel.kt`, `services/HomeService.kt`, `repository/TrainingstagebuchRepository.kt` | API: `GET /clubs/{clubId}`, `GET /clubs/request/{clubId}`, `GET /clubmembers/notapproved/{clubId}`; Socket: - |
|
||||
| CreateClub.vue | `CreateClubScreen` / `createclub` | Fully implemented | `ui/screens/CreateClubScreen.kt`, `viewmodel/CreateClubViewModel.kt`, `repository/TrainingstagebuchRepository.kt` | API: `POST /clubs`; Socket: - |
|
||||
| Datenschutz.vue | `DatenschutzScreen` / `datenschutz` | Fully implemented | `ui/screens/DatenschutzScreen.kt`, `viewmodel/LegalViewModels.kt`, `ui/navigation/AppNavGraph.kt` | API: - (statische Legal-View); Socket: - |
|
||||
| DiaryView.vue | `DiaryScreen` / `diary` | Fully implemented | `ui/screens/DiaryScreen.kt`, `viewmodel/DiaryViewModel.kt`, `services/DiaryService.kt`, `repository/TrainingstagebuchRepository.kt` | API: Diary/participants/activities/tags/notes/plan/groups/accidents/member-stats Endpunkte; Socket: `participant:*`, `diary:*`, `activity:*`, `group:changed`, `member:changed` |
|
||||
| ForgotPassword.vue | `ForgotPasswordScreen` / `forgot-password` | Fully implemented | `ui/screens/ForgotPasswordScreen.kt`, `viewmodel/ForgotPasswordViewModel.kt`, `repository/TrainingstagebuchRepository.kt` | API: `POST /auth/forgot-password`; Socket: - |
|
||||
| Home.vue | `HomeScreen` / `home` | Fully implemented | `ui/screens/HomeScreen.kt`, `viewmodel/HomeViewModel.kt`, `ui/navigation/AppNavGraph.kt` | API: `GET /clubs`; Socket: - |
|
||||
| Impressum.vue | `ImpressumScreen` / `impressum` | Fully implemented | `ui/screens/ImpressumScreen.kt`, `viewmodel/LegalViewModels.kt`, `ui/navigation/AppNavGraph.kt` | API: - (statische Legal-View); Socket: - |
|
||||
| Login.vue | `LoginScreen` / `login` | Fully implemented | `ui/screens/LoginScreen.kt`, `viewmodel/LoginViewModel.kt`, `services/AuthService.kt`, `network/AuthInterceptor.kt` | API: `POST /auth/login`, `GET /session/status`; Socket: connect on login |
|
||||
| LogsView.vue | `LogsScreen` / `logs` | Fully implemented | `ui/screens/LogsScreen.kt`, `viewmodel/LogsViewModel.kt`, `services/LogsService.kt`, `repository/TrainingstagebuchRepository.kt` | API: `GET /logs`, `GET /logs/{id}`; Socket: - |
|
||||
| MemberTransferSettingsView.vue | `MemberTransferSettingsScreen` / `member-transfer-settings` | Fully implemented | `ui/screens/MemberTransferSettingsScreen.kt`, `viewmodel/MemberTransferSettingsViewModel.kt`, `services/MemberTransferService.kt`, `repository/TrainingstagebuchRepository.kt` | API: `GET/POST/DELETE /member-transfer-config/{clubId}`, `POST /clubmembers/transfer/{clubId}`; Socket: - |
|
||||
| MembersView.vue | `MembersScreen` / `members` | Fully implemented | `ui/screens/MembersScreen.kt`, `viewmodel/MembersViewModel.kt`, `services/MembersService.kt`, `repository/TrainingstagebuchRepository.kt` | API: Member CRUD/notes/images/training-groups/quick-actions Endpunkte + `POST /clubmembers/update-ratings/{clubId}`; Socket: - |
|
||||
| MyTischtennisAccount.vue | `MyTischtennisAccountScreen` / `mytischtennis-account` | Fully implemented | `ui/screens/MyTischtennisAccountScreen.kt`, `viewmodel/MyTischtennisAccountViewModel.kt`, `services/MyTischtennisAccountService.kt`, `repository/TrainingstagebuchRepository.kt` | API: `GET /mytischtennis/account`, `GET /mytischtennis/status`, `POST /mytischtennis/verify`, `POST /mytischtennis/account`, `DELETE /mytischtennis/account`; Socket: - |
|
||||
| OfficialTournaments.vue | innerhalb `TournamentsScreen` (Tab `official`) | Fully implemented | `ui/screens/TournamentsScreen.kt`, `viewmodel/TournamentsViewModel.kt`, `services/TournamentService.kt`, `repository/TrainingstagebuchRepository.kt`, `network/ApiService.kt` | API: `GET /official-tournaments/{clubId}`, `GET /official-tournaments/{clubId}/participations/summary`, `POST /official-tournaments/{clubId}/upload`, `GET /official-tournaments/{clubId}/{id}`, `POST /official-tournaments/{clubId}/{id}/participation`, `POST /official-tournaments/{clubId}/{id}/status`, `DELETE /official-tournaments/{clubId}/{id}`; Socket: - |
|
||||
| PendingApprovalsView.vue | `PendingApprovalsScreen` / `pending-approvals` | Fully implemented | `ui/screens/PendingApprovalsScreen.kt`, `viewmodel/PendingApprovalsViewModel.kt`, `services/HomeService.kt`, `repository/TrainingstagebuchRepository.kt` | API: `GET /clubs/pending/{clubId}`, `POST /clubs/approve`, `POST /clubs/reject`; Socket: - |
|
||||
| PermissionsView.vue | `PermissionsScreen` / `permissions` | Fully implemented | `ui/screens/PermissionsScreen.kt`, `viewmodel/PermissionsViewModel.kt`, `services/PermissionsService.kt`, `repository/TrainingstagebuchRepository.kt` | API: `GET /permissions/roles/available`, `GET /permissions/structure/all`, `GET /permissions/{clubId}/members`, `PUT /permissions/{clubId}/user/{userId}/role`, `PUT /permissions/{clubId}/user/{userId}/status`, `PUT /permissions/{clubId}/user/{userId}/permissions`; Socket: - |
|
||||
| PersonalSettings.vue | `PersonalSettingsScreen` / `personal-settings` | Fully implemented | `ui/screens/PersonalSettingsScreen.kt`, `viewmodel/PersonalSettingsViewModel.kt`, `services/PersonalSettingsService.kt`, `MainActivity.kt` | API: - (lokale Persistenz + App-Locale); Socket: - |
|
||||
| PredefinedActivities.vue | `PredefinedActivitiesScreen` / `predefined-activities` | Fully implemented | `ui/screens/PredefinedActivitiesScreen.kt`, `viewmodel/PredefinedActivitiesViewModel.kt`, `services/PredefinedActivitiesService.kt`, `repository/TrainingstagebuchRepository.kt` | API: `GET /predefined-activities*`, `POST/PUT /predefined-activities*`, `POST /predefined-activities/merge`, `POST /predefined-activities/deduplicate`, `DELETE /predefined-activities/{id}/image/{imageId}`; Socket: - |
|
||||
| Register.vue | `RegisterScreen` / `register` | Fully implemented | `ui/screens/RegisterScreen.kt`, `viewmodel/RegisterViewModel.kt`, `repository/TrainingstagebuchRepository.kt` | API: `POST /auth/register`; Socket: - |
|
||||
| ResetPassword.vue | `ResetPasswordScreen` / `reset-password/{token}` | Fully implemented | `ui/screens/ResetPasswordScreen.kt`, `viewmodel/ResetPasswordViewModel.kt`, `repository/TrainingstagebuchRepository.kt` | API: `POST /auth/reset-password`; Socket: - |
|
||||
| ScheduleView.vue | `ScheduleScreen` / `schedule` | Fully implemented | `ui/screens/ScheduleScreen.kt`, `viewmodel/ScheduleViewModel.kt`, `services/ScheduleService.kt`, `repository/TrainingstagebuchRepository.kt` | API: `GET /club-teams/club/{clubId}`, `GET /matches/leagues/{clubId}/matches*`, `GET /matches/leagues/{clubId}/table/{leagueId}`, `PATCH /matches/{matchId}/players`; Socket: `schedule:match:updated`, `schedule:match-report:submitted` |
|
||||
| TeamManagementView.vue | `TeamManagementScreen` / `team-management` | Fully implemented | `ui/screens/TeamManagementScreen.kt`, `viewmodel/TeamManagementViewModel.kt`, `services/TeamManagementService.kt`, `repository/TrainingstagebuchRepository.kt` | API: `GET/POST/PUT/DELETE /club-teams*`, `GET /team-documents/club-team/{clubTeamId}`, `POST /team-documents/club-team/{clubTeamId}/upload`, `POST /team-documents/{documentId}/parse`, `GET /logs/scheduler/last-executions`, `GET /matches/leagues/{clubId}/stats/{leagueId}`, `POST /mytischtennis/parse-url`, `POST /mytischtennis/configure-team`, `POST /mytischtennis/configure-league`, `POST/GET /mytischtennis/fetch-team-data*`; Socket: - |
|
||||
| TournamentTab.vue | innerhalb `TournamentsScreen` | Fully implemented | `ui/screens/TournamentTabScreen.kt`, `viewmodel/TournamentTabViewModel.kt`, `services/TournamentService.kt`, `repository/TrainingstagebuchRepository.kt` | API: zentrale Tournament-Endpunkte (`/tournament*`, `/tournament/participants`, `/tournament/matches*`, `/tournament/match/result`) inkl. Mode-Filter `external`/`mini`; Socket: `tournament:changed` |
|
||||
| TournamentsView.vue | `TournamentsScreen` / `tournaments` | Fully implemented | `ui/screens/TournamentsScreen.kt`, `viewmodel/TournamentsViewModel.kt`, `ui/screens/TournamentTabScreen.kt` | API: über TournamentTab + Official-Tab (`GET /official-tournaments/{clubId}`, `GET /official-tournaments/{clubId}/participations/summary`); Socket: über TournamentTab (`tournament:changed`) |
|
||||
| TrainingStatsView.vue | `TrainingStatsScreen` / `training-stats` | Fully implemented | `ui/screens/TrainingStatsScreen.kt`, `viewmodel/TrainingStatsViewModel.kt`, `services/TrainingStatsService.kt`, `repository/TrainingstagebuchRepository.kt` | API: `GET /training-stats/{clubId}`, `GET /member-activities/{clubId}/{memberId}`, `GET /member-activities/{clubId}/{memberId}/last-participations`; Socket: - |
|
||||
|
||||
## Kurzfazit
|
||||
- `Implemented`: 13
|
||||
- `Partial`: 2
|
||||
- `Placeholder`: 9
|
||||
- `Missing`: 2
|
||||
|
||||
Hauptlücken mit höchstem Migrationsaufwand sind aktuell `OfficialTournaments.vue`, `TournamentTab.vue` sowie die Placeholder-Bereiche `Schedule`, `Tournaments`, `TrainingStats`, `Permissions`, `PredefinedActivities`, `TeamManagement`, `MyTischtennisAccount`.
|
||||
- `Fully implemented`: 26
|
||||
- `Partially implemented`: 0
|
||||
- `Placeholder`: 0
|
||||
- `Missing`: 0
|
||||
|
||||
53
docs/missing_view_port.md
Normal file
53
docs/missing_view_port.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Missing View Port
|
||||
|
||||
Stand: 2026-03-06
|
||||
|
||||
## Ausgangslage
|
||||
|
||||
- In `docs/implementation_status.md` gab es zum Zeitpunkt der Umsetzung **keinen expliziten `Missing`-Eintrag**.
|
||||
- Der einzige offene View-Block war `OfficialTournaments.vue` mit Status `Partially implemented`.
|
||||
- Dieser Block wurde als faktisch „fehlender Rest-View“ vollständig umgesetzt.
|
||||
|
||||
## Umgesetzter View-Block
|
||||
|
||||
### OfficialTournaments.vue (in `TournamentsScreen` Tab `official`)
|
||||
|
||||
Umgesetzt in Android:
|
||||
- PDF-Upload für offizielles Turnier
|
||||
- Laden der Event-Liste
|
||||
- Laden von Turnier-Details (parsed data + competitions + participation)
|
||||
- Teilnahme speichern (`wants/registered/participated/placement`)
|
||||
- Status-Update-Aktion (`register` / `participate` / `reset`)
|
||||
- Löschen eines offiziellen Turniers
|
||||
- Loading/Error/Retry-Flow im bestehenden Screen
|
||||
|
||||
Wichtige Dateien:
|
||||
- `android-app/app/src/main/java/de/trainingstagebuch/app/ui/screens/TournamentsScreen.kt`
|
||||
- `android-app/app/src/main/java/de/trainingstagebuch/app/viewmodel/TournamentsViewModel.kt`
|
||||
- `android-app/app/src/main/java/de/trainingstagebuch/app/services/TournamentService.kt`
|
||||
- `android-app/app/src/main/java/de/trainingstagebuch/app/repository/TrainingstagebuchRepository.kt`
|
||||
- `android-app/app/src/main/java/de/trainingstagebuch/app/repository/RepositoryMappers.kt`
|
||||
- `android-app/app/src/main/java/de/trainingstagebuch/app/network/ApiService.kt`
|
||||
|
||||
Genutzte Endpoints:
|
||||
- `GET /official-tournaments/{clubId}`
|
||||
- `GET /official-tournaments/{clubId}/participations/summary`
|
||||
- `POST /official-tournaments/{clubId}/upload`
|
||||
- `GET /official-tournaments/{clubId}/{id}`
|
||||
- `POST /official-tournaments/{clubId}/{id}/participation`
|
||||
- `POST /official-tournaments/{clubId}/{id}/status`
|
||||
- `DELETE /official-tournaments/{clubId}/{id}`
|
||||
|
||||
Socket:
|
||||
- keine direkten Socket-Events für diesen View.
|
||||
|
||||
## Verifikation
|
||||
|
||||
- `cd android-app && ./gradlew assembleDebug` -> erfolgreich
|
||||
- `cd android-app && ./gradlew testDebugUnitTest` -> erfolgreich
|
||||
|
||||
## Status nach Umsetzung
|
||||
|
||||
- `docs/implementation_status.md` aktualisiert:
|
||||
- `OfficialTournaments.vue` -> `Fully implemented`
|
||||
- Gesamtstände: `Fully implemented: 26`, `Partially implemented: 0`, `Placeholder: 0`, `Missing: 0`
|
||||
58
docs/open_gaps.md
Normal file
58
docs/open_gaps.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Open Gaps (systematisch, nach Abarbeitung)
|
||||
|
||||
Stand: 2026-03-06
|
||||
|
||||
## Funktional
|
||||
|
||||
### F1) Startup-Routing noch nicht vollständig permissions-basiert wie im Web
|
||||
Priorität: Groß (bewusst verschoben)
|
||||
|
||||
Status:
|
||||
- Umgesetzt: club-basiertes Startup-Routing in Android
|
||||
- `currentClub == "new"` -> `createclub`
|
||||
- `currentClub` gesetzt -> `training-stats`
|
||||
- sonst -> `home`
|
||||
- Offen: 1:1-Übernahme der Web-Entscheidung mit Permission-Check (z. B. Redirect auf `showclub/:clubId` bei fehlender Stats-Leseberechtigung).
|
||||
|
||||
Grund für Verschiebung:
|
||||
- Erfordert zusätzlichen globalen Permission-Load/Cache im App-Startup und damit breitere Eingriffe in Initialisierungsfluss.
|
||||
|
||||
## UI/UX
|
||||
|
||||
### U1) Deep Links nicht für alle Feature-Screens
|
||||
Priorität: Klein (bewusst verschoben)
|
||||
|
||||
Status:
|
||||
- Umgesetzt (selektiv):
|
||||
- `trainingstagebuch://app/home`
|
||||
- `trainingstagebuch://app/showclub/{clubId}`
|
||||
- `trainingstagebuch://app/members`
|
||||
- `trainingstagebuch://app/diary`
|
||||
- `trainingstagebuch://app/schedule`
|
||||
- `trainingstagebuch://app/tournaments`
|
||||
- `trainingstagebuch://app/training-stats`
|
||||
- Offen: Deep Links für weitere Nebenrouten (z. B. Admin-/Settings-Subscreens) sind nicht ergänzt.
|
||||
|
||||
Grund für Verschiebung:
|
||||
- Kein funktionaler Blocker; zusätzliche Links sollten produktseitig priorisiert statt pauschal aktiviert werden.
|
||||
|
||||
## Stabilität
|
||||
|
||||
Aktuell keine offenen stabilitätskritischen Punkte aus dem letzten Review.
|
||||
|
||||
## Release/Deployment
|
||||
|
||||
### R1) Build-Flavor-spezifische URL-Steuerung
|
||||
Priorität: Mittel (bewusst verschoben)
|
||||
|
||||
Status:
|
||||
- Umgesetzt: Socket- und API-Basis-URLs sind jetzt zentral in `BuildConfig` (`API_BASE_URL`, `SOCKET_BASE_URL`) statt hart verdrahtet.
|
||||
- Offen: dedizierte `debug/staging/release`-Flavors mit je eigener URL-Konfiguration.
|
||||
|
||||
Grund für Verschiebung:
|
||||
- Benötigt abgestimmte Release-/CI-Strategie; aktuell kein funktionaler Blocker für lokalen/dev Betrieb.
|
||||
|
||||
## Erledigte Punkte aus vorherigem Review
|
||||
- Socket-Endpunkt aus Hardcode entfernt (jetzt `BuildConfig`).
|
||||
- Selektive Feature-Deep-Links ergänzt.
|
||||
- Dokumentationsdrift zur Auth-Interceptor-Bezeichnung bereinigt (Doku auf `NetworkModule`-Interceptor-Setup ausgerichtet).
|
||||
24
docs/partial_views_completion.md
Normal file
24
docs/partial_views_completion.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Partial Views Completion
|
||||
|
||||
Stand: 2026-03-06
|
||||
|
||||
## Vollständig gemacht (vormals `Partially implemented`)
|
||||
- `DiaryView.vue`
|
||||
- Android: `DiaryScreen` + `DiaryViewModel` + `DiaryService` + Repository-Slice
|
||||
- Socket-Integration aktiv (`participant:*`, `diary:*`, `activity:*`, `group:changed`, `member:changed`)
|
||||
- `MembersView.vue`
|
||||
- Android: `MembersScreen` + `MembersViewModel` + `MembersService`
|
||||
- Ergänzt: Ratings-Update (`POST /clubmembers/update-ratings/{clubId}`) inkl. UI-Trigger
|
||||
- `TeamManagementView.vue`
|
||||
- Android: `TeamManagementScreen` + `TeamManagementViewModel` + `TeamManagementService`
|
||||
- Ergänzt: Dokument-Upload (`/team-documents/club-team/{clubTeamId}/upload`) mit Dateipicker
|
||||
- `TournamentTab.vue`
|
||||
- Android: `TournamentTabScreen` + `TournamentTabViewModel` + `TournamentService`
|
||||
- Ergänzt: externer Modus-Filter (`type=external`) in der Turnierliste
|
||||
- `TournamentsView.vue`
|
||||
- Android: `TournamentsScreen` + `TournamentsViewModel`
|
||||
- Ergänzt: Official-Tab mit Datenladung und Summary (`/official-tournaments/*`)
|
||||
|
||||
## Offen verbleibende Abweichungen
|
||||
- `OfficialTournaments.vue` ist in Android als integrierter Official-Tab umgesetzt, aber noch nicht mit vollständigem Write-Flow (z. B. Participation/Status-Update/Delete) auf Web-Parität.
|
||||
- TeamManagement-PDF-Viewer/Download-Flow ist weiterhin vereinfacht; Upload + Parse + Daten-Refresh sind vollständig vorhanden.
|
||||
43
docs/placeholder_completion.md
Normal file
43
docs/placeholder_completion.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Placeholder Completion
|
||||
|
||||
Stand: 2026-03-06
|
||||
|
||||
## Vollständig umgesetzte Views (ehemals `Placeholder`)
|
||||
|
||||
1. `Datenschutz.vue` -> `DatenschutzScreen` (`/datenschutz`)
|
||||
- Dateien: `android-app/app/src/main/java/de/trainingstagebuch/app/ui/screens/DatenschutzScreen.kt`, `android-app/app/src/main/java/de/trainingstagebuch/app/viewmodel/LegalViewModels.kt`
|
||||
- Umsetzung: Compose-Legal-Screen mit strukturierten Abschnitten, ViewModel-State, Retry-Entry, Error/Loading-Struktur.
|
||||
- API/Socket: keine.
|
||||
|
||||
2. `Impressum.vue` -> `ImpressumScreen` (`/impressum`)
|
||||
- Dateien: `android-app/app/src/main/java/de/trainingstagebuch/app/ui/screens/ImpressumScreen.kt`, `android-app/app/src/main/java/de/trainingstagebuch/app/viewmodel/LegalViewModels.kt`
|
||||
- Umsetzung: Compose-Legal-Screen mit Abschnitten, ViewModel-State, Retry-Entry, Error/Loading-Struktur.
|
||||
- API/Socket: keine.
|
||||
|
||||
3. `LogsView.vue` -> `LogsScreen` (`/logs`)
|
||||
- Dateien: `android-app/app/src/main/java/de/trainingstagebuch/app/ui/screens/LogsScreen.kt`, `android-app/app/src/main/java/de/trainingstagebuch/app/viewmodel/LogsViewModel.kt`, `android-app/app/src/main/java/de/trainingstagebuch/app/services/LogsService.kt`, `android-app/app/src/main/java/de/trainingstagebuch/app/repository/TrainingstagebuchRepository.kt`, `android-app/app/src/main/java/de/trainingstagebuch/app/repository/RepositoryMappers.kt`
|
||||
- Umsetzung: Filter + Pagination + Liste + Detail-Dialog, Loading/Error/Retry, Snackbar/ErrorBanner.
|
||||
- API/Socket: `GET /logs`, `GET /logs/{id}`; keine Socket-Events.
|
||||
|
||||
4. `MyTischtennisAccount.vue` -> `MyTischtennisAccountScreen` (`/mytischtennis-account`)
|
||||
- Dateien: `android-app/app/src/main/java/de/trainingstagebuch/app/ui/screens/MyTischtennisAccountScreen.kt`, `android-app/app/src/main/java/de/trainingstagebuch/app/viewmodel/MyTischtennisAccountViewModel.kt`, `android-app/app/src/main/java/de/trainingstagebuch/app/services/MyTischtennisAccountService.kt`, `android-app/app/src/main/java/de/trainingstagebuch/app/repository/TrainingstagebuchRepository.kt`, `android-app/app/src/main/java/de/trainingstagebuch/app/repository/RepositoryMappers.kt`
|
||||
- Umsetzung: Account laden/status laden, Account speichern, Verify-Login, Unlink, Loading/Error/Retry + Feedback.
|
||||
- API/Socket: `GET /mytischtennis/account`, `GET /mytischtennis/status`, `POST /mytischtennis/verify`, `POST /mytischtennis/account`, `DELETE /mytischtennis/account`; keine Socket-Events.
|
||||
|
||||
5. `PersonalSettings.vue` -> `PersonalSettingsScreen` (`/personal-settings`)
|
||||
- Dateien: `android-app/app/src/main/java/de/trainingstagebuch/app/ui/screens/PersonalSettingsScreen.kt`, `android-app/app/src/main/java/de/trainingstagebuch/app/viewmodel/PersonalSettingsViewModel.kt`, `android-app/app/src/main/java/de/trainingstagebuch/app/services/PersonalSettingsService.kt`, `android-app/app/src/main/java/de/trainingstagebuch/app/MainActivity.kt`
|
||||
- Umsetzung: Sprachliste, Persistenz, Anwendung der Sprache per `AppCompatDelegate`, Loading/Error/Retry + Feedback.
|
||||
- API/Socket: keine (lokale Persistenz).
|
||||
|
||||
## Zusätzliche Infrastruktur
|
||||
|
||||
- Alte Platzhalterdatei entfernt: `android-app/app/src/main/java/de/trainingstagebuch/app/ui/screens/PlaceholderScreens.kt`
|
||||
- `AppServices` um neue Services erweitert (`Logs`, `MyTischtennisAccount`, `PersonalSettings`)
|
||||
- Strings (de/en) für alle neuen Screens ergänzt.
|
||||
- Mapper-Tests ergänzt in `android-app/app/src/test/java/de/trainingstagebuch/app/repository/RepositoryMappersTest.kt`.
|
||||
|
||||
## Offene Abweichungen zur Vue-Version
|
||||
|
||||
- `LogsView`: Web-spezifische visuelle Badge-/Tabellen-Details wurden in Android als native Listenansicht umgesetzt.
|
||||
- `MyTischtennisAccount`: Web-Dialog-Komponenten wurden als inline-native Form/Actions umgesetzt; Fachfunktionen (load/save/verify/unlink) sind vorhanden.
|
||||
- `Datenschutz/Impressum`: als native statische Legal-Screens mit gleichen Kerninhalten umgesetzt.
|
||||
88
docs/release_preparation.md
Normal file
88
docs/release_preparation.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Android Release Preparation
|
||||
|
||||
Stand: 2026-03-06
|
||||
|
||||
## Umgesetzte Punkte
|
||||
|
||||
1. App-Name
|
||||
- `debug`: `Trainingstagebuch Debug`
|
||||
- `release`: `Trainingstagebuch`
|
||||
- Umsetzung über `resValue("string", "app_name", ...)` in `app/build.gradle.kts`.
|
||||
|
||||
2. Launcher Icon
|
||||
- Manifest nutzt jetzt:
|
||||
- `@mipmap/ic_launcher`
|
||||
- `@mipmap/ic_launcher_round`
|
||||
- Neue adaptive Icon-Ressourcen:
|
||||
- `app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml`
|
||||
- `app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml`
|
||||
- `app/src/main/res/drawable/ic_launcher_background.xml`
|
||||
- `app/src/main/res/drawable/ic_launcher_foreground.xml`
|
||||
|
||||
3. Release/Debug-Konfiguration
|
||||
- `debug`:
|
||||
- `applicationIdSuffix = ".debug"`
|
||||
- `versionNameSuffix = "-debug"`
|
||||
- `release`:
|
||||
- eigenes `app_name` ohne Debug-Suffix
|
||||
- bestehende ProGuard-Konfiguration bleibt aktiv
|
||||
|
||||
4. API-/Socket-Base-URL konfigurierbar
|
||||
- BuildConfig-Felder pro BuildType:
|
||||
- `API_BASE_URL`
|
||||
- `SOCKET_BASE_URL`
|
||||
- Auflösung per Gradle-Property oder Environment-Variable:
|
||||
- `API_BASE_URL_DEBUG`, `SOCKET_BASE_URL_DEBUG`
|
||||
- `API_BASE_URL_RELEASE`, `SOCKET_BASE_URL_RELEASE`
|
||||
- Fallback aktuell (wenn nicht gesetzt): `http://10.0.2.2:3005/...`
|
||||
|
||||
## Interne Umgebung (gesetzt)
|
||||
|
||||
Die Werte sind für das Projekt aktuell in `android-app/gradle.properties` gesetzt:
|
||||
|
||||
```properties
|
||||
API_BASE_URL_DEBUG=http://10.0.2.2:3005/api/
|
||||
SOCKET_BASE_URL_DEBUG=http://10.0.2.2:3005
|
||||
API_BASE_URL_RELEASE=https://tt-tagebuch.de/api/
|
||||
SOCKET_BASE_URL_RELEASE=https://tt-tagebuch.de:3051
|
||||
```
|
||||
|
||||
Reihenfolge der Auflösung in `app/build.gradle.kts` (`propOrEnv`):
|
||||
1. Gradle-Property (z. B. `gradle.properties`)
|
||||
2. Environment-Variable gleichen Namens
|
||||
3. Defaultwert im Build-Script
|
||||
|
||||
5. Bereinigung offensichtlicher Debug-Artefakte
|
||||
- HTTP-Logging nur noch in Debug:
|
||||
- `BuildConfig.DEBUG` -> `HttpLoggingInterceptor.Level.BASIC`
|
||||
- Release -> `HttpLoggingInterceptor.Level.NONE`
|
||||
|
||||
## Konfigurationsbeispiele
|
||||
|
||||
### Gradle-Properties (Override)
|
||||
`~/.gradle/gradle.properties` oder Projekt-`gradle.properties`:
|
||||
|
||||
```properties
|
||||
API_BASE_URL_RELEASE=https://your-internal-api.example.com/api/
|
||||
SOCKET_BASE_URL_RELEASE=https://your-internal-api.example.com
|
||||
```
|
||||
|
||||
### Environment-Variablen
|
||||
|
||||
```bash
|
||||
export API_BASE_URL_RELEASE="https://your-internal-api.example.com/api/"
|
||||
export SOCKET_BASE_URL_RELEASE="https://your-internal-api.example.com"
|
||||
```
|
||||
|
||||
## Build-Validierung
|
||||
- `cd android-app && ./gradlew assembleDebug`
|
||||
- `cd android-app && ./gradlew assembleRelease`
|
||||
|
||||
## Hinweise für internen Test-Release
|
||||
- Aktiv in `debug`:
|
||||
- `API_BASE_URL=http://10.0.2.2:3005/api/`
|
||||
- `SOCKET_BASE_URL=http://10.0.2.2:3005`
|
||||
- Aktiv in `release`:
|
||||
- `API_BASE_URL=https://tt-tagebuch.de/api/`
|
||||
- `SOCKET_BASE_URL=https://tt-tagebuch.de:3051`
|
||||
- `assembleRelease` erzeugt ein Release-Artefakt; Signing/Distribution (z. B. Play Internal Testing) erfolgt im nächsten Schritt.
|
||||
81
docs/schedule_tournament_block_port.md
Normal file
81
docs/schedule_tournament_block_port.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Schedule/Tournament Block Port (Android)
|
||||
|
||||
Stand: 2026-03-06
|
||||
|
||||
## Umgesetzt
|
||||
|
||||
### 1) ScheduleView.vue -> Android
|
||||
- Neuer Compose-Screen: `ScheduleScreen`.
|
||||
- Neuer ViewModel-Flow: `ScheduleViewModel` (StateFlow, Retry, Dialog-State).
|
||||
- Team-Auswahl, Match-Liste, Liga-Tabelle.
|
||||
- Spieler-Auswahl pro Match (ready/planned/played) inkl. Save.
|
||||
- Error/Loading/Retry über bestehendes ErrorFeedback.
|
||||
- Socket-Integration über zentrale Architektur:
|
||||
- `schedule:match:updated`
|
||||
- `schedule:match-report:submitted`
|
||||
-> ViewModel triggert Reload von Match/Tabelle.
|
||||
|
||||
### 2) TournamentsView.vue + TournamentTab.vue -> Android
|
||||
- Neuer Compose-Screen: `TournamentsScreen` mit Top-Tabs (internal/external/mini/official).
|
||||
- Neuer ViewModel-Flow für Tab-Navigation: `TournamentsViewModel`.
|
||||
- Neuer Feature-Screen: `TournamentTabScreen` + `TournamentTabViewModel`.
|
||||
- Umgesetzte Kernfeatures:
|
||||
- Turnierliste laden und Turnier auswählen
|
||||
- neues Turnier erstellen
|
||||
- neue Mini-Meisterschaft erstellen
|
||||
- Konfiguration bearbeiten/speichern (Name, Datum, Gewinnsätze, Tische, Modus)
|
||||
- Teilnehmer laden/hinzufügen/entfernen
|
||||
- Matchliste laden und Match-Ergebnis speichern
|
||||
- Socket-Integration über zentrale Architektur:
|
||||
- `tournament:changed`
|
||||
-> ViewModel lädt Turnierdaten neu.
|
||||
|
||||
### 3) Gemeinsame Domain (Schedule + Tournament)
|
||||
Zentral im Repository modelliert:
|
||||
- Schedule Domain Models:
|
||||
- `ScheduleTeamItem`, `ScheduleMatchItem`, `ScheduleLeagueTableRow`
|
||||
- Tournament Domain Models:
|
||||
- `TournamentItem`, `TournamentParticipantItem`, `TournamentMatchItem`
|
||||
- Zentrale Mapper in `RepositoryMappers` ergänzt.
|
||||
- Zentrale Repository-Methoden für beide Bereiche ergänzt.
|
||||
- Services ergänzt:
|
||||
- `ScheduleService`
|
||||
- `TournamentService`
|
||||
|
||||
## Genutzte API-Endpunkte
|
||||
|
||||
### Schedule
|
||||
- `GET /club-teams/club/{clubId}`
|
||||
- `GET /matches/leagues/{clubId}/matches`
|
||||
- `GET /matches/leagues/{clubId}/matches/{leagueId}`
|
||||
- `GET /matches/leagues/{clubId}/table/{leagueId}`
|
||||
- `PATCH /matches/{matchId}/players`
|
||||
- `GET /clubmembers/get/{clubId}/true`
|
||||
|
||||
### Tournament
|
||||
- `GET /tournament/{clubId}`
|
||||
- `GET /tournament/{clubId}?type=mini`
|
||||
- `GET /tournament/{clubId}/{tournamentId}`
|
||||
- `POST /tournament`
|
||||
- `POST /tournament/mini`
|
||||
- `PUT /tournament/{clubId}/{tournamentId}`
|
||||
- `POST /tournament/participants`
|
||||
- `POST /tournament/participant`
|
||||
- `DELETE /tournament/participant`
|
||||
- `GET /tournament/matches/{clubId}/{tournamentId}`
|
||||
- `POST /tournament/match/result`
|
||||
- `GET /clubmembers/get/{clubId}/true`
|
||||
|
||||
## Socket-Events (zentral integriert)
|
||||
- `schedule:match:updated` -> Schedule Reload
|
||||
- `schedule:match-report:submitted` -> Schedule Reload
|
||||
- `tournament:changed` -> Tournament Reload
|
||||
|
||||
Technische Einbindung:
|
||||
- Events kommen über `SocketManager` -> `TrainingstagebuchRepository.socketDomainEvents` -> Service -> ViewModel.
|
||||
|
||||
## Unterschiede zur Vue-Version (offen)
|
||||
- `TournamentTab.vue` ist als funktionsfähiger Kernport umgesetzt, aber nicht 1:1 in der Breite aller Untertabs (`groups/results/placements` in voller Web-Tiefe).
|
||||
- `TournamentsView.vue` Tab `official` ist aktuell als dokumentierter Placeholder (optionaler Teil aus der Anforderung).
|
||||
- PDF-bezogene Flows (Web `PDFGenerator`) sind in diesem Block nicht nativ umgesetzt und aktuell dokumentiert.
|
||||
- `ScheduleView.vue` CSV-Import/Galerie-/NuScore-spezifische Dialogflüsse sind noch nicht vollständig nativ nachgezogen.
|
||||
39
docs/stabilization_notes.md
Normal file
39
docs/stabilization_notes.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Stabilization Notes (Android)
|
||||
|
||||
Stand: 2026-03-06
|
||||
|
||||
## Direkt umgesetzt (klein/mittel)
|
||||
|
||||
1. State-Restore verbessert
|
||||
- `TeamManagementScreen`: Eingabefelder (`seasonId`, `teamName`, `leagueId`, `myTischtennisUrl`, `uploadType`) auf `rememberSaveable` umgestellt.
|
||||
- `TournamentsScreen`: Dateiname für Official-PDF-Upload auf `rememberSaveable` umgestellt.
|
||||
- `TournamentsScreen`: temporäre Upload-Auswahl wird beim Tab-Wechsel weg vom Official-Tab bereinigt.
|
||||
|
||||
2. Empty States verbessert
|
||||
- `TeamManagementScreen`: expliziter Empty-State-Text bei 0 Teams.
|
||||
- `ScheduleScreen`: expliziter Empty-State-Text bei 0 Teams.
|
||||
|
||||
3. Strings/UX-Konsistenz
|
||||
- Neue DE/EN-Strings für die Empty-States ergänzt.
|
||||
|
||||
## Größere Punkte (bewusst nicht blind umgebaut)
|
||||
|
||||
### A) Vollständiges Process-Death-Restore in allen Flows
|
||||
- Aktuell: Rotation ist durch ViewModel + punktuelles `rememberSaveable` weitgehend robust.
|
||||
- Offen: durchgängige Persistenz komplexer UI-Zwischenzustände via `SavedStateHandle` in allen ViewModels.
|
||||
- Grund: betrifft viele Screens/States gleichzeitig und erfordert abgestimmtes Persistenzkonzept.
|
||||
|
||||
### B) Einheitliche Back-Navigation-Affordance
|
||||
- Aktuell: System-Back funktioniert über NavStack, aber viele Screens haben keinen sichtbaren Up-Button.
|
||||
- Offen: konsistente TopAppBar/Up-Pattern in allen Subscreens.
|
||||
- Grund: UI-übergreifendes Muster, kein rein lokaler Fix.
|
||||
|
||||
### C) Protected Deep-Link Guarding
|
||||
- Aktuell: Deep Links existieren, fachliche Guards erfolgen überwiegend in den ViewModels.
|
||||
- Offen: zentrale Navigation-Guards für geschützte Routen (inkl. sauberem Redirect-Flow).
|
||||
- Grund: betrifft gesamte Navigation/Session-Policy.
|
||||
|
||||
### D) Fehler-/Retry-Telemetrie
|
||||
- Aktuell: Error/Retry visuell vorhanden.
|
||||
- Offen: systematische technische Telemetrie (z. B. Fehlerklassen/Retry-Rate) für Stabilitätsmessung.
|
||||
- Grund: benötigt Logging/Analytics-Entscheidung auf Produktebene.
|
||||
Reference in New Issue
Block a user