# Socket Contract (Vue <-> Android)

## Zielbild (Android, zentral)
- Eine zentrale WebSocket-Implementierung in `SocketManager` (OkHttp).
- Auth beim Connect über Session-Daten (`authcode`, `userid`).
- Exponential Reconnect-Backoff.
- Event-Stream als `SharedFlow`.
- Repository mappt Transport-Events auf Domain-Events.
- ViewModels abonnieren nur Domain-Events (kein direkter Socket-Zugriff).

## Relevante Android-Dateien
- `android-app/app/src/main/java/de/trainingstagebuch/app/network/SocketManager.kt`
- `android-app/app/src/main/java/de/trainingstagebuch/app/network/SocketModels.kt`
- `android-app/app/src/main/java/de/trainingstagebuch/app/utils/SocketMessageUtils.kt`
- `android-app/app/src/main/java/de/trainingstagebuch/app/repository/TrainingstagebuchRepository.kt`
- `android-app/app/src/main/java/de/trainingstagebuch/app/services/DiaryService.kt`
- `android-app/app/src/main/java/de/trainingstagebuch/app/viewmodel/DiaryViewModel.kt`
- `android-app/app/src/main/java/de/trainingstagebuch/app/MainActivity.kt`

## Vue-Referenz
- Quelle: `frontend/src/services/socketService.js`
- Verbindungsaufbau über Socket.IO (`path: /socket.io/`), Events via `socket.on(...)`.
- Club-Room-Handling via `join-club` / `leave-club`.

## URL / Transport
- Android Basis: `http://10.0.2.2:3005`
- Daraus abgeleitet für OkHttp WebSocket:
  - `ws://10.0.2.2:3005/socket.io/?EIO=4&transport=websocket&authcode=<token>&userid=<username>`

## Auth beim Connect
Android sendet Auth auf mehreren kompatiblen Ebenen:
1. Query-Parameter im Handshake: `authcode`, `userid`
2. Direkt nach `onOpen`:
   - Socket.IO namespace connect payload: `40{"authcode":"...","userid":"..."}`
   - optionales Auth-Event: `42["auth",{"authcode":"...","userid":"..."}]`

Zusätzlich wird bei vorhandenem Club direkt `join-club` gesendet.

## Lifecycle / Connection-Strategie
- `MainActivity.onStart()` -> `SocketManager.setAppInForeground(true)`
- `MainActivity.onStop()` -> `SocketManager.setAppInForeground(false)`
- Connect nur wenn:
  - App im Vordergrund
  - und `requestConnect()` gesetzt (Login-Pfad)
  - und Session vollständig (`token`, `username`)
- Logout-Pfad ruft `requestDisconnect()` über Repository auf.

## Reconnect
- Exponential Backoff, initial `1s`, max `30s`.
- Reconnect nur solange Verbindung gewünscht ist (`shouldMaintainConnection=true`) und App im Vordergrund.

## Room-Verhalten (Club)
- Bei bestehender Verbindung und Club-Wechsel:
  - `leave-club` für alten Club
  - `join-club` für neuen Club
- Entspricht dem Vue-Verhalten beim Wechsel des aktiven Clubs.

## Eventtypen
Vue-Events (und Android-Mapping):
- `participant:added`
- `participant:removed`
- `participant:updated`
- `diary:note:added`
- `diary:note:updated`
- `diary:note:deleted`
- `diary:tag:added`
- `diary:tag:removed`
- `diary:date:updated`
- `activity:member:added`
- `activity:member:removed`
- `activity:changed`
- `member:changed`
- `group:changed`
- `tournament:changed`
- `schedule:match:updated`
- `schedule:match-report:submitted`

Kompatibilitätsaliase im Parser:
- `activity-member:added` -> `activity:member:added`
- `activity-member:removed` -> `activity:member:removed`

## Event-Pipeline in Android
1. `SocketManager.events: SharedFlow<SocketEvent>` (Transport-Ebene)
2. `TrainingstagebuchRepository.socketDomainEvents: SharedFlow<DomainSocketEvent>` (Domain-Ebene)
3. Services/ViewModels abonnieren Domain-Events (z. B. `DiaryService`/`DiaryViewModel`).

Damit sind Socket-Duplikate aus dem Diary-Port entfernt: Diary-ViewModel nutzt keine direkte `SocketManager`-Abhängigkeit mehr.
