# 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 → `MainTabs` mit **`MainTab`** (Start, Tagebuch, Mitglieder, …).
- **Breit / schmal:** ab ca. 600 dp `MainNavigationRail`, sonst `BottomNavigation` (siehe `MAIN_NAV_RAIL_MIN_WIDTH_DP`).
- **Unter-Navigation / Tiefe:** kein zentraler **Navigation-Compose**-`NavHost` für die Shell; stattdessen **expliziter Zustand** (`rememberSaveable` / `remember`), z. B. `diarySelectedEntryId`, `membersNestedOpen`, `billingOrdersSection`. **Zurück** über `BackHandler` und 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 (`visibleMainTabs` in `AppRoot.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 unter `composeApp/.../ui/` mit **dateiweise** Feature-Namen (`Diary*`, `Members*`, `Schedule*`, `CalendarScreen`, …) sowie `AppRoot.kt`, `AppDependencies.kt`.
- **Zielbild:** Neue Features als eigene Dateien/ Unterpakete `ui/<bereich>/` anlegen; keine weiteren riesigen Monolithen neben `AppRoot` anhä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 in `composeApp` (z. B. `calendar/CalendarAggregator.kt`), angebunden über `AppDependencies`.
- **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:** `LaunchedEffect` bei 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 im `shared` (Dependency existiert bereits) anbinden oder dokumentiertes Polling – siehe `TODO.md` Backlog.

### 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** (`sharePdfFile` u. 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

1. **Android Studio überschreibt Gradle:**  
   **Settings → Build, Execution, Deployment → Build Tools → Gradle**  
   beim Projekt `mobile-app` prüfen, ob unter **Command-line options** etwas wie  
   `-PbackendBaseUrl=http://localhost:3005` steht – das entfernen oder bewusst setzen.

2. **Alte Installation / Build-Cache:** Emulator-App deinstallieren, Clean, neu installieren:
   ```bash
   cd mobile-app
   adb uninstall de.tt_tagebuch.app
   ./gradlew :composeApp:clean :composeApp:installDebug --no-configuration-cache
   ```
   Oder das Skript: `./scripts/install-debug-emulator.sh`

3. **BuildConfig prüfen:** Nach dem Build in  
   `composeApp/build/generated/.../BuildConfig.java`  
   den Wert von `BACKEND_BASE_URL` ansehen – der muss `https://tt-tagebuch.de` sein (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 **`composeApp`** wählen.
- Alternativ immer über die Kommandozeile installieren (siehe oben) und die App im Emulator starten.

Überschreiben per Gradle-Property, z. B. lokaler Emulator:

```bash
./gradlew :composeApp:installDebug -PbackendBaseUrl=http://10.0.2.2:3005
```

**Alternative:** Port vom PC auf den Emulator weiterleiten, dann geht wieder `localhost`:

```bash
adb reverse tcp:3005 tcp:3005
./gradlew :composeApp:installDebug -PbackendBaseUrl=http://localhost:3005
```

## Smoke flow (Android)
1. Start backend (default `http://localhost:3005`)
2. Start Android emulator
3. App installieren: `./scripts/install-debug-emulator.sh` oder Run in Studio (Modul **`composeApp`**)
4. Login → Club auswählen → Rolle wird angezeigt
5. Open `Tagebuch` → die letzten Einträge werden angezeigt

## Gradle Wrapper
Use the wrapper from `mobile-app/`:
```bash
cd mobile-app
./gradlew tasks
```

Note (Codex sandbox only): the sandbox home directory is read-only, so run with:
```bash
GRADLE_USER_HOME=/tmp/gradle-home ./gradlew tasks
```

## i18n generation
```bash
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 the `composeApp` configuration.
