Files
Torsten Schulz (local) e57cdc6ad8
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 53s
Refactor code structure for improved readability and maintainability
2026-05-27 23:53:41 +02:00

22 KiB
Raw Permalink Blame History

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: Single-Activity-Modell mit MainTab + zustandsbasierter Tiefe (Tagebuch-Tag, Mitglieder-Details, Einstellungen-Unterseiten); Rail/Bottom-Nav; kein zentraler Navigation-Compose-NavHost für die Shell (bewusste Entscheidung, später migrierbar) siehe DEVELOPMENT.md § Architektur Phase 0, Umsetzung AppRoot.kt
  • Feature-Paketierung: Richtlinie und Ist: APIs/DTOs/Manager im shared, UI in composeApp/.../ui/ mit featurebezogenen Dateien; schrittweise Entschlackung großer Dateien DEVELOPMENT.md § Architektur Phase 0
  • Use-Cases: Geschäftslogik überwiegend in shared/state/*Manager und gezielt in plattformnahen Helfern (CalendarAggregator o. ä.); Composables orchestrieren DEVELOPMENT.md § Architektur Phase 0
  • 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): v1 ohne Web-Socket; Aktualisierung über LaunchedEffect / manuelles Neuladen dokumentiert; optional Socket/Polling später DEVELOPMENT.md § Architektur Phase 0
  • Medien: Coil für Bilder, FileProvider + Share-Intents für PDF; dokumentiert in DEVELOPMENT.md § Architektur Phase 0
  • Ö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)

  • Registrierung (Register.vue) Android: RegisterScreen, POST /api/auth/register
  • Account aktivieren (Activate.vue) Android: ActivateAccountScreen, GET /api/auth/activate/:code
  • Passwort vergessen / E-Mail (ForgotPassword.vue) ForgotPasswordScreen, POST /api/auth/forgot-password
  • Passwort setzen mit Token (ResetPassword.vue) ResetPasswordScreen, POST /api/auth/reset-password
  • Home / Landing eingeloggt (Home.vue) Tab Start: Willkommen, Kacheln zu Tagebuch/Mitglieder/Statistik/Mehr, Vereinsinfos via GET /api/clubs/:id (HomeScreen, ClubsApi.getClub)
  • Impressum Einstellungen → öffnet BACKEND_BASE_URL/impressum im Browser
  • 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

  • Verein erstellen (CreateClub.vue) + API POST /api/clubs, ClubSelectScreen + ClubManager.createClub
  • 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

  • Tagebuch-Daten vollständig laden beim Datumswechsel Plan, Trainingsgruppen und Teilnehmer parallel in einem LaunchedEffect (DiaryDetailScreen)
  • Aktivitäten-Liste /activities/:dateIdDiaryApi.listFreeformActivities / addFreeformActivity, Abschnitt „Weitere Tages-Aktivitäten“ im Tagebuch-Detail

3.2 Trainingsplan (CRUD)

  • Plan laden: GET /diary-date-activities/:clubId/:diaryDateIdDiaryApi / Tagebuch-Detail
  • Einträge anlegen: POST /diary-date-activities/:clubId, ggf. Gruppe POST /diary-date-activities/group — Android-Formulare + CreateDiaryPlanActivityRequest / AddDiaryPlanGroupActivityRequest
  • Einträge bearbeiten: PUT /diary-date-activities/:clubId/:id (Zuordnung groupId im Body wie Backend) — Dialog „Bearbeiten“; Unter-Einträge (GroupActivity) bearbeiten, Teilnehmer zuordnen und Drawing pflegen
  • Reihenfolge: PUT .../order — ↑/↓ je Trainingsgruppen-Scope
  • Löschen: DELETE ..., Gruppen-Aktivität DELETE .../group/...
  • Zeitblöcke (isTimeblock) inkl. UX wie Web — Checkbox beim Anlegen, Kennzeichnung in der Karte
  • Gruppen für Plan: GET/POST/PUT/DELETE /api/group — Liste mit Mehrfachanlage, Lead-/Namensbearbeitung und bestaetigtem Loeschen
  • Drawing: Objekt-/String-kompatible API-Daten, Editor mit Folgeschlaegen, Anzeige nur per Icon und Vorschau-Dialog; Backend speichert drawingData ohne doppelte Serialisierung

3.3 Teilnehmer & Status

  • Liste: GET /participants/:dateId

  • Hinzufügen/Entfernen: POST /participants/add, POST /participants/remove

  • Status entschuldigt/abgesagt: PUT /participants/:dateId/:memberId/status

  • Gruppenzuordnung Training: PUT /participants/:dateId/:memberId/groupParticipantsApi.updateParticipantGroup, Dropdown bei anwesenden Teilnehmern wenn Trainingsgruppen existieren

  • UX: Teilnehmerliste im Tagebuch-Detail aufklappbar, standard eingeklappt (DiaryDetailScreen)

  • Testmitglieder-Workflow: Filter/Suche, Schnellanlage im Trainingstag, Formular-Uebergabe und Warnhinweis nach mehreren Teilnahmen

  • GET /diary-member-activities/:clubId/:activityIdDiaryMemberActivitiesApi / „Wer macht mit?“ je Planzeile bzw. Gruppen-Aktivität

  • Zuweisen: POST ... mit participantIds — inkl. ensureParticipantRowId wenn noch keine Teilnehmer-Zeile

  • Entfernen: DELETE .../:participantId

3.5 Mitgliedsbezogene Notizen/Tags im Tagebuch

  • GET/POST .../diarymember/:clubId/note, DELETE .../note/:id (mit diaryDateId/memberId als Query) — DiaryMemberApi / Dialog „Notizen & Tags“ je Teilnehmer
  • GET/POST .../diarymember/:clubId/tag, POST .../tag/remove — bestehende Tags, neu anlegen (POST /tags + Verknüpfung)

3.6 Predefined Activities (Auswahl & Suche im Tagebuch)

  • GET /predefined-activities, GET ...?scope=standard, GET /search/query — Trainingsplan anlegen (global + Gruppe) und Eintrag bearbeiten (Suche / vordefinierte ID)
  • GET /predefined-activities/:idPredefinedActivitiesApi.getById / DiaryManager.getPredefinedActivity (für spätere Detail-UI)

3.7 Unfälle / Vorfälle

  • POST /accident, GET /accident/:clubId/:diaryDateIdAccidentApi / DiaryManager / Abschnitt im Tagebuch-Detail

3.8 Galerie & Bilder

  • Mitgliederbilder: memberProfileImagePath + AuthenticatedAsyncImage (Coil mit diaryAuthHeaders) in der Teilnehmerliste bei diary.read + members.read
  • Übungs-/Predefined-Bilder: DiaryImagePaths (mainActivityImagePath / nestedActivityImagePath) + ApiConfig.toAbsoluteUrl, Vollbild-Dialog im Tagebuch-Detail
  • Gruppenfotos: MemberGroupPhotosApi (GET/POST/DELETE /api/member-group-photos/:clubId), Galerie-Abschnitt + PickVisualMedia in DiaryDetailScreen

3.9 PDF / Export

  • Trainingsplan- und Tages-PDF (DiaryPdfExporter / writeTrainingPlanPdf, writeTrainingDaySummaryPdf), Teilen über FileProvider + sharePdfFile (DiaryPdfShare)
  • Tages-PDF mit Plan-Gruppen und den je Aktivitaet/Unteraktivitaet zugeordneten Teilnehmern

3.10 Sonstiges Diary-UX

  • Web-DiaryView → mobil (Kurzüberblick): Tages-Metadaten, sicher bestaetigtes Loeschen, Plan inkl. Zeitbloecke/Gruppen/Filter/Drawings und korrektem Bereitschaftsstatus, Teilnehmer inkl. Status/Gruppe/Testworkflow, „Wer macht mit?“, Freitext-Aktivitaeten, Tags/Notizen, Unfaelle, Galerie sowie PDF-Exporte.
  • 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

  • Mitglied-CRUD: POST /api/clubmembers/set/:clubIdMembersApi.setMember, MemberSetBody / Member.toSetBody, MembersManager.saveMember; neu + bearbeiten in MemberEditRoute (AppRoot.kt)
  • 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
  • Profilbild: POST /api/clubmembers/image/... (Multipart) — MembersApi.uploadMemberPortrait, Galerie-Pick + UCrop in MemberDetailRoute / MemberPortraitCrop.kt
  • Aktivität / letzte Teilnahmen: GET /api/member-activities/:clubId/:memberId (Perioden-Query), .../last-participationsMemberActivitiesApi, Abschnitte im Profil
  • Trainingsgruppen: GET/POST/DELETE /api/training-groups/...TrainingGroupsApi, Zuweisen/Entfernen im Profil
  • Trainingszeiten (Verein): GET /api/training-times/:clubIdTrainingTimesApi, Anzeige je Gruppe im Profil
  • Bild zuschneiden: Yalantis UCrop nach PickVisualMedia — JitPack, UCropActivity im Manifest

Phase 5 Trainings-Statistik (Parität TrainingStatsView) — erledigt

  • DTO / API: TrainingStats.kt weekdayStats, monthlyTrend, memberDistribution, overview.bestTrainingDay, Mitglied mit birthDate, participationRate12Months, trainingGroups, trainingDetails, lastTrainingTs usw.
  • Ableitungen wie Web: TrainingStatsDerived.kt Filter (Wochentag, Trainingstag, Gruppe), filteredOverview, Monats-/Wochentags-Trends, Mitgliederstruktur, Gruppen-Performance, Altersklassen, Sortierung, CSV
  • UI: TrainingStatsScreen.kt Kennzahlen-Kacheln, Panels, kollabierbare Listen Trainingstage/Mitglieder, Detail-Dialog, CSV-Share (shareFileWithMime in DiaryPdfShare.kt)
  • i18n-Local: LanguageLocals.kt (LocalLanguageCode) aus AppRoot.kt ausgelagert
  • Hinweis: Web hat keinen CSV-Export für diese Statistik; mobil zusätzlich CSV exportieren (gefilterte/sortierte Mitgliederliste)

Phase 6 Terminplan (ScheduleView) — erledigt

  • DTOs: Schedule.kt ClubTeamDto, ScheduleMatchDto, LeagueTableRowDto, UpdateMatchPlayersBody, ScheduleMatchScope, ScheduleViewMode
  • APIs: ClubTeamsApi (GET /api/club-teams/club/:clubId), MatchesApi (/api/matches/leagues/... matches + Tabelle, PATCH /api/matches/:matchId/players)
  • Logik: ScheduleLogic.kt Sortierung, Merge, Filter „Erwachsene“, Mannschafts-Scope wie Web
  • State: ScheduleManager.kt Mannschaften laden, Mannschafts-/Gesamt-/Erwachsenen-Ansicht, Tabelle, Spieler-Patch + Refresh
  • Berechtigungen: canReadSchedule / canWriteSchedule in ClubPermissionHelpers.kt
  • UI: ScheduleScreen.kt Tab Terminplan (MainTab.Schedule), Home-Kachel bei Lese-Recht, Liste + Detail, Aufstellung (R/P/S) bei Schreib-Recht
  • Noch nicht mobil: CSV-Import (POST /api/matches/import), MyTT-Tabellen-Fetch (POST .../table/.../fetch), Galerie/Lineup wie Web bei Bedarf spätere Phase

Phase 7 Turniere

  • Vereins-Turniere (TournamentsView.vue / TournamentTab.vue): GET /api/tournament/:clubId (optional ?type=mini), clientseitig intern/offen wie Web; GET /api/tournament/:clubId/:id für Detail UI TournamentsScreen.kt, TournamentsApi, ClubInternalTournamentsManager
  • Offizielle Teilnahmen (OfficialTournaments.vue): GET /api/official-tournaments/:clubId, GET .../participations/summary OfficialTournamentsApi, OfficialTournamentsReadManager, gleicher Screen
  • Navigation: Tab Turniere (MainTab.Tournaments) bei canReadTournaments(), Start-Kachel; Deep-Link /tournaments für volle Web-Verwaltung
  • Nicht mobil: PDF-Import, Meldungen/ClickTT-Workflows, Spielstände pflegen, Gruppen/K.O. wie Web bewusst Web-only

Phase 8 Freigaben & Verwaltung

  • Ausstehende Freigaben ClubApprovalsApi, PendingApprovalsManager, Screen unter „Mehr“ → Club-Verwaltung (ClubAdminScreens.kt)
  • Team-Management (Mannschaften + Editor) TeamManagementScreen + TeamEditorScreen: Saison, Suche, CRUD Mannschaften; Tabs Stammdaten, Spielerstatistik (Liga), Aufstellung/Meldung, Dokumente, Scheduler-Jobs, MyTT (ClubTeamsApi, MatchesApi, TeamDocumentsApi, ApiLogsApi, MyTischtennisApi, Rechte canReadTeams/canWriteTeams)
  • Mannschafts-Planung (Android) TeamManagementScreen Mannschaften | Planung; TeamPlanningScreen / TeamPlanningLogic; MembersApi Play-Interest (TeamEditorModels) Details Phase 8a
  • Berechtigungen erweiterte PermissionsApi, PermissionsAdminManager, UI Rolle/Status/Anpassen mit RolePermissionMatrix (ClubAdminScreens.kt)
  • Logs ApiLogsApi, ApiLogsManager, Liste + Pagination + Detail (ClubAdminScreens.kt); AppDependencies / Logout / 401 räumen Manager auf

Phase 8a Mannschafts-Planung auf Android (umgesetzt, Stand 2026-05)

  • GET/POST /api/clubmembers/play-interest/:clubId MembersApi + DTOs MemberPlayInterestRowDto / MemberPlayInterestSetBody
  • UI: TeamPlanningScreen.kt Halbserie, Pool, Interesse markieren, Mannschaft hinzufügen, pro Team Stammdaten + Meldung, QTTR-Abstand, „Im Editor öffnen“
  • Einstieg: TeamManagementScreen Segment Mannschaften | Planung
  • Logik: TeamPlanningLogic.kt Normalisierung Zuordnungen, Eligibility über TeamEditorLineupLogic, Default-Halbserie
  • Optional später: Drag-and-Drop statt Menüs; Debounced Autosave wie Web; dedizierte Tests Serialisierung

Hinweis im Code: Tab Aufstellung (TeamEditorScreen) verweist auf den Reiter Planung in derselben Team-Verwaltung.


Phase 9 Vereins- & Stammdaten-Einstellungen

  • ClubSettings (ClubSettings.vue) Kernfelder in ClubStammdatenScreens.kt + Link Web; tiefergehend nur Web
  • Predefined Activities (PredefinedActivities.vue) Liste, Neu, Bearbeiten (PredefinedActivitiesApi); Medien/Web-only falls nötig
  • Mitgliedstransfer (MemberTransferSettingsView.vue) Basis in App, erweitert über Web-Link

Phase 10 Persönliche Konten & Integrationen

  • Persönliche Einstellungen (PersonalSettings.vue) Mehr → Hub: Sprache, MyTT, ClickTT; PersonalHubScreens.kt + AppRoot.kt SettingsScreen
  • MyTischtennis-Konto (MyTischtennisAccount.vue) MyTischtennisApi, Dialog/Verify/Unlink in PersonalHubScreens.kt
  • ClickTT-Konto (ClickTtAccount.vue) ClickTtAccountApi, analog in PersonalHubScreens.kt
  • ClickTT-Ansicht (ClickTtView.vue) Proxy-URL + WebView in ClickTtBrowserScreen

Phase 11 Abrechnung & Bestellungen

  • Orders (OrdersView.vue / OrdersPanel.vue global) MemberOrdersApi, MemberOrderDtos.kt, BillingOrdersScreens.kt (GlobalOrdersScreen)
  • Billing (BillingView.vue) Kernfluss ohne Web-PDF-Mapping-Editor BillingApi, BillingDtos.kt, BillingClubScreen (Vorlagen-Upload, Vorschau, Lauf anlegen, PDF erzeugen/teilen, Läufe); Mapping weiter über Browser
  • Rechtliches/UX: Button Abrechnung im Browser (/billing) für volle Web-Funktion; PDF-Teilen wie Tagebuch-PDF

Phase 12 Kalender (Vereinskalender)

Web-Route: /calendar · Referenz: CalendarView.vue (Aggregation mehrerer Datenquellen in einer Monatsansicht).

  • Navigation & Shell: Haupt-Tab MainTab.Calendar + Start-Hub-Kachel (AppRoot.kt), Monat vor/zurück, „Heute“, Monatsüberschrift (CalendarScreen.kt)
  • Monatsgitter: 7×6, außerhalb Monat / heute, Wochentagskopf (CalendarScreen.kt, CalendarAggregator.kt)
  • Legende / Filter: Eventtypen mit Schalter und Zähler (CalendarScreen.kt)
  • Daten laden (parallel, teilfehlertolerant): supervisorScope + async in CalendarScreen.kt; Quellen: DiaryManager.listDates, Trainingszeiten, TrainingCancellationApi, TournamentsApi, MatchesApi, OfficialTournamentsReadManager, CalendarHolidayApi (CalendarDtos.kt, APIs in shared)
  • Logik: CalendarAggregator.kt (wiederkehrende Zeiten, Merge, Ausfälle) an Web angelehnt
  • Trainingsausfall: Formular + Liste im Monat + API (TrainingCancellationApi, CalendarScreen.kt)
  • Agenda: sortierte Monatsliste (CalendarAggregator.eventsInMonth, CalendarScreen.kt)
  • Event-Aktion: CalendarEventAction → Tagebuch-Tag/Tab, Terminplan, Turniere, Web /tournament-participations (calendar/CalendarAggregator.kt / CalendarScreen.kt, Verdrahtung AppRoot.kt)
  • i18n: MobileStrings-Keys mit Fallback in CalendarScreen.kt / AppRoot.kt (navigation.calendar, home.tileCalendar, mobile.calendar*)
  • Web-Parität (Detail): Meldung wenn alle Kalender-Quellen fehlschlagen; Legenden-Zähler aus allen Events (unabhängig von den Schaltern); Agenda-Datum kurz/lokalisiert; Ausfall-Liste nur wenn Startdatum im Monat liegt (wie CalendarView.vue) CalendarScreen.kt

Phase 13 Backlog (abgeschlossen)

  • i18n: Kalender-Strings (mobile.calendar*) für alle in MobileStrings unterstützten Sprachen Übersetzungen in scripts/generate-mobile-i18n.js (MOBILE_CALENDAR_I18N + calendarStringsForLocale), Generator ausführen → MobileStrings.kt
  • Kalender vs. Web: Offizielle Teilnahmen mobil über Tab Turnierteilnahmen (MainTab.OfficialParticipations); tiefe Verwaltung wie Web unter /tournament-participations bewusst getrennt, angleichen nur bei Bedarf
  • Release / R8: ProGuard-Regeln + proguardFiles in composeApp/build.gradle.kts (Phase 14); isMinifyEnabled bleibt bis gezieltem Release-Test false siehe Phase 14
  • Turniere (Produktiv-Crash): LazyColumn mit eindeutigen Keys (itemsIndexed für Vereins-Turniere, offizielle Liste, Teilnahmen-Zeilen), vermeidet Duplicate-Key-Abstürze; zudem tolerante Deserialisierung für allowsExternal / isDoublesTournament (0/1, Strings) TournamentsScreen.kt, FlexibleBooleanSerializers.kt, TournamentDtos.kt

Phase 14 Qualität, Tests, Release

  • Regression-Checkliste pro Phase (manuell) mobile-app/REGRESSION_CHECKLIST.md
  • Automatisierte Tests: shared Android-Unit-Tests (androidUnitTest), Startpunkt Serialisierung Turnier-DTOs (InternalTournamentSerializationTest.kt); ausführen: ./gradlew :shared:testDebugUnitTest
  • Barrierefreiheit (Basis): Navigation Rail TalkBack-taugliche contentDescription für Sektions-Icons (Ein-/Ausklappen) und zusammengefasste Beschriftung für Blatt-Einträge (NavRailLeafItem); Bottom-Tabs hatten bereits Label + Icon-Beschreibung
  • Performance: manuelle Stichproben und Erwartungen in REGRESSION_CHECKLIST.md (Abschnitt Performance); Paging / Bildcache bei Bedarf spätere Iteration
  • Store / Compliance: Play Console Datenschutz, Berechtigungen (Kamera/Galerie, Internet) Kurzhinweis in REGRESSION_CHECKLIST.md (Abschnitt Store / Compliance); ausführliche Listing-Texte Verantwortung Release
  • Release / R8-Vorbereitung: composeApp/proguard-rules.pro (Ktor, kotlinx.serialization, Koin, BuildConfig) + proguardFiles in composeApp/build.gradle.kts; isMinifyEnabled bleibt false bis gezielter Release-Test

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. Kalender: /calendar → Phase 12.