- Changed file permissions from 644 to 755 for various files in the mobile-app and mobile-app_legacy_rn_expo directories, ensuring executable permissions where necessary. - Added a new SQL migration script to the backend to introduce missing columns for club billing and invoice settings in the clubs table, maintaining synchronization with the current Sequelize model.
7.7 KiB
Executable File
Development
Architektur Phase 0 (abgeschlossen)
Die folgenden Punkte entsprechen Phase 0 in TODO.md: festgelegte Entscheidungen und Ist-Zustand der Codebasis, ohne dass die App komplett neu strukturiert wird.
Navigation
- Single Activity, Haupt-UI in
AppRoot.kt: eingeloggt →MainTabsmitMainTab(Start, Tagebuch, Mitglieder, …). - Breit / schmal: ab ca. 600 dp
MainNavigationRail, sonstBottomNavigation(sieheMAIN_NAV_RAIL_MIN_WIDTH_DP). - Unter-Navigation / Tiefe: kein zentraler Navigation-Compose-
NavHostfür die Shell; stattdessen expliziter Zustand (rememberSaveable/remember), z. B.diarySelectedEntryId,membersNestedOpen,billingOrdersSection. Zurück überBackHandlerund Tab-Wechsel, der Detailzustand zurücksetzt (selectMainTab). - Auth: eigener Flow (
AuthFlowHost) vor Club-Auswahl – ebenfalls ohne separates Nav-Graph-Modul. - Begründung (kein zentraler NavHost): geringere Migrationskosten, vorhandenes Verhalten beibehalten. Ein späterer Umstieg auf
NavHost(z. B. pro Tab oder für Deep Links) ist möglich. - Start-Hub (
HomeScreen): Nur Willkommen + Vereinsinfos (Karte); keine Navigations-Kacheln mehr (vermeidet leere Abschnitte und Doppelung mit der Rail). - Navigation Rail (Tablet / breit): Drei aufklappbare Blöcke wie die Web-Sidebar – Tagesgeschäft, Wettbewerb, Einstellungen – mit allen Einträgen inkl. Freigaben, Turnierteilnahmen (Browser), Vereinseinstellungen, Vordefinierte Aktivitäten, Team (Browser), Abrechnung, Bestellungen; oben Start, unten Mehr. Zustand der Aufklappung per
rememberSaveable. - Smartphone: Weiterhin untere Tab-Leiste (
visibleMainTabs) + vollständige Einstellungen unter Mehr; Kurzhinweis auf der Startseite. - Tab-Sichtbarkeit: Entspricht grob den Web-
v-if-Bedingungen (visibleMainTabsinAppRoot.kt, u. a. Kalender nur bei Tagebuch-, Terminplan- oder Turnier-Leserecht).
Feature-Paketierung (Richtlinie + Ist)
shared: HTTP-APIs (shared/.../api), DTOs (api/models), zustandsführende Manager (shared/.../state), i18n.composeApp: Android-UI untercomposeApp/.../ui/mit dateiweise Feature-Namen (Diary*,Members*,Schedule*,CalendarScreen, …) sowieAppRoot.kt,AppDependencies.kt.- Zielbild: Neue Features als eigene Dateien/ Unterpakete
ui/<bereich>/anlegen; keine weiteren riesigen Monolithen nebenAppRootanhäufen, sondern schrittweise auslagern (laufende Arbeit).
Use-Cases / Geschäftslogik
- Primär
shared:*Manager-Klassen kapseln API + Caching/Flow (z. B.DiaryManager,ClubManager). - Plattformnah Android: reine UI-Hilfen oder
java.time-lastige Aggregation bleiben incomposeApp(z. B.calendar/CalendarAggregator.kt), angebunden überAppDependencies. - Composables: möglichst nur Zustand,
LaunchedEffect, Aufrufe in Manager/APIs; komplexe Ableitungen in wiederverwendbaren Funktionen/Klassen statt inline riesiger Blöcke.
Echtzeit (optional / Web-Parität)
- Web nutzt u. a. Socket-Updates; Android v1: bewusst ohne parallelen Socket-Client.
- Aktualisierung:
LaunchedEffectbei Screen-Fokus /clubId/ relevanten Keys, nach Schreiboperationen (dataGeneration++o. ä.) oder Tabwechsel. Polling nur dort, wo bereits im Code nachvollziehbar (kein globales Intervall-Polling). - Später: optional
socket.io-Client imshared(Dependency existiert bereits) anbinden oder dokumentiertes Polling – sieheTODO.mdBacklog.
Medien (Bilder / PDF)
- Bilder: Coil (
coil-compose), authentifizierte Requests wo nötig (diaryAuthHeaders/AuthenticatedAsyncImage). - PDF / Teilen: Generierung im App-Code, Ausgabe über FileProvider und System-Intent (
sharePdfFileu. a. im Tagebuch-Flow). - Cache: Standard Coil-/Systemverhalten; kein separates Offline-Framework in Phase 0.
Backend-URL
Standard: https://tt-tagebuch.de – gesetzt in gradle.properties (backendBaseUrl=…) und als Fallback in composeApp/build.gradle.kts.
Für lokale Entwicklung läuft der Backend-Server auf deinem Rechner typischerweise unter http://localhost:3005.
Die Android-Studio-VM (Emulator) kann localhost / 127.0.0.1 nicht für diesen lokalen Server nutzen: dort ist „localhost“ der Emulator selbst, nicht dein PC. Für lokale Emulator-Tests nutze http://10.0.2.2:3005.
HTTP / Cleartext: Ab Android 9 blockiert das System unverschlüsseltes HTTP standardmäßig. Für die lokale Dev-URL ist das in composeApp/src/androidMain/res/xml/network_security_config.xml für 10.0.2.2, localhost und 127.0.0.1 freigegeben.
Testest du mit der LAN-IP deines PCs (echtes Gerät), musst du diese IP dort als weiteres <domain> ergänzen oder kurzzeitig HTTPS nutzen.
Wenn die App trotz Rebuild noch localhost zeigt
-
Android Studio überschreibt Gradle:
Settings → Build, Execution, Deployment → Build Tools → Gradle
beim Projektmobile-appprüfen, ob unter Command-line options etwas wie
-PbackendBaseUrl=http://localhost:3005steht – das entfernen oder bewusst setzen. -
Alte Installation / Build-Cache: Emulator-App deinstallieren, Clean, neu installieren:
cd mobile-app adb uninstall de.tsschulz.tt_tagebuch ./gradlew :composeApp:clean :composeApp:installDebug --no-configuration-cacheOder das Skript:
./scripts/install-debug-emulator.sh -
BuildConfig prüfen: Nach dem Build in
composeApp/build/generated/.../BuildConfig.java
den Wert vonBACKEND_BASE_URLansehen – der musshttps://tt-tagebuch.desein (oder deine bewusste Override-URL).
Android Studio „Run“ geht nicht
- Projekt
mobile-app/als Root öffnen (nicht nur den übergeordneten Monorepo-Ordner, wenn Studio das Modul nicht erkennt). - Run → Edit Configurations → Android App: Modul
composeAppwählen. - Alternativ immer über die Kommandozeile installieren (siehe oben) und die App im Emulator starten.
Überschreiben per Gradle-Property, z. B. lokaler Emulator:
./gradlew :composeApp:installDebug -PbackendBaseUrl=http://10.0.2.2:3005
Alternative: Port vom PC auf den Emulator weiterleiten, dann geht wieder localhost:
adb reverse tcp:3005 tcp:3005
./gradlew :composeApp:installDebug -PbackendBaseUrl=http://localhost:3005
Smoke flow (Android)
- Start backend (default
http://localhost:3005) - Start Android emulator
- App installieren:
./scripts/install-debug-emulator.shoder Run in Studio (ModulcomposeApp) - Login → Club auswählen → Rolle wird angezeigt
- Open
Tagebuch→ die letzten Einträge werden angezeigt
Phase 14 – Unit-Tests, Regressionsliste, R8
- Automatisierte Tests (shared):
./gradlew :shared:testDebugUnitTest(JVM-Unit-Tests untershared/src/androidUnitTest/, u. a. Serialisierung kritischer DTOs). - Manuelle Regression:
REGRESSION_CHECKLIST.mdim Ordnermobile-app/. - R8/ProGuard:
composeApp/proguard-rules.proist an die Release-Variante angebunden;isMinifyEnabledbleibt vorerstfalse, bis ein Release mit Schrumpfung gezielt getestet wurde.
Gradle Wrapper
Use the wrapper from mobile-app/:
cd mobile-app
./gradlew tasks
Note (Codex sandbox only): the sandbox home directory is read-only, so run with:
GRADLE_USER_HOME=/tmp/gradle-home ./gradlew tasks
i18n generation
node scripts/generate-mobile-i18n.js
This reads all web locale JSON files and writes the generated KMP bundle to
mobile-app/shared/src/commonMain/kotlin/de/tt_tagebuch/shared/i18n/MobileStrings.kt.
Build
Recommended:
- Open
mobile-app/in Android Studio and run thecomposeAppconfiguration.