# Android-App-Konzept fuer SingleChat

## Zielbild

SingleChat soll als echte Android-App verfuegbar werden, nicht nur als WebView-Wrapper. Die Android-App nutzt die bestehenden Backend-Endpunkte und spricht mit dem vorhandenen Socket.IO-Server dasselbe Ereignisprotokoll wie das Vue-Web-Frontend.

Das Ziel fuer den ersten Release ist Funktionsgleichheit mit dem Kern-Chat:

- Login mit Benutzername, Geschlecht, Alter und Land
- Anzeige aktiver Benutzer
- Suche nach Benutzern
- Einzelchat mit Textnachrichten
- Bildversand ueber bestehenden Upload-Endpunkt
- Inbox mit ungelesenen Chats
- Verlauf geoeffneter Konversationen
- Blockieren und Entblockieren von Benutzern
- Session-Wiederherstellung, Logout und 30-Minuten-Inaktivitaetslogik
- Feedback- und Partnerseiten optional im MVP, aber technisch ueber vorhandene REST-Endpunkte moeglich

## Bestand Im Repo

Das aktuelle System besteht aus:

- Backend: Node.js/Express in `server/index.js`
- REST-Endpunkte in `server/routes.js`
- Socket.IO-Chat-Protokoll in `server/broadcast.js`
- Vue/Pinia-Webclient mit Socket.IO-Client in `client/src/stores/chat.js`
- Bild-Upload im Webclient ueber `client/src/components/ChatInput.vue`

Der Server erlaubt Socket.IO mit `websocket` und `polling`. Das Web-Frontend nutzt aktuell absichtlich nur `polling`, vermutlich wegen Proxy-/WebSocket-Problemen. Fuer Android sollte WebSocket als bevorzugter Transport genutzt werden, mit Polling als Fallback.

## Technische Empfehlung

### App-Technologie

Empfohlen: native Android-App mit Kotlin und Jetpack Compose.

Gruende:

- echte App-Erfahrung statt WebView
- robuste Hintergrund-/Reconnect-Logik
- gute Kontrolle ueber Cookies, Sessions und Uploads
- moderne UI mit Compose schneller wartbar
- bessere Basis fuer spaetere Push Notifications

Alternative: React Native oder Flutter waeren moeglich, bringen aber fuer diese App keinen klaren Vorteil, weil das Protokoll einfach ist und Android explizit das Ziel ist.

### Zielarchitektur

```text
Android App
  UI: Jetpack Compose
  State: ViewModel + StateFlow
  REST: Retrofit/OkHttp
  Socket: Socket.IO Android Client
  Session: OkHttp CookieJar + EncryptedSharedPreferences/DataStore
  Images: Android Photo Picker + Multipart Upload

Existing Backend
  Express REST API
  Socket.IO Chat Events
  express-session Cookie connect.sid
```

## Backend-Anbindung

### Basis-URL

Production:

```text
https://www.ypchat.net
```

Development:

```text
http://10.0.2.2:3300
```

`10.0.2.2` ist im Android Emulator der Host-Rechner. Auf echtem Geraet braucht es die lokale LAN-IP oder einen Dev-Tunnel.

### REST-Endpunkte

Die Android-App kann folgende vorhandene Endpunkte direkt verwenden:

| Zweck | Methode | Pfad | Android-Nutzung |
|---|---:|---|---|
| Health Check | GET | `/api/health` | Diagnose/Verbindungscheck |
| Session holen | GET | `/api/session` | Cookie initialisieren, Session wiederherstellen, Express-Session-ID erhalten |
| Logout | POST | `/api/logout` | serverseitige Session beenden und Socket trennen |
| Laenderliste | GET | `/api/countries` | Login-Land-Auswahl und Flag-Code |
| Bild hochladen | POST | `/api/upload-image` | Multipart-Upload mit Session-Cookie |
| Bild abrufen | GET | `/api/image/:code` | Anzeige empfangener Bilder |
| Partner | GET | `/api/partners` | optionaler App-Screen |
| Feedback laden | GET | `/api/feedback` | optionaler Feedback-Screen |
| Feedback senden | POST | `/api/feedback` | optionaler Feedback-Screen |
| Feedback Admin Login | POST | `/api/feedback/admin-login` | optional, eher nicht MVP |
| Feedback Admin Logout | POST | `/api/feedback/admin-logout` | optional, eher nicht MVP |
| Feedback loeschen | DELETE | `/api/feedback/:id` | optional, eher nicht MVP |

Wichtig: REST und Socket muessen dieselbe Cookie-Session verwenden. Android braucht daher einen gemeinsamen `OkHttpClient` mit persistenter Cookie-Verwaltung.

## Socket.IO-Protokoll

### Verbindungsaufbau

Ablauf analog zum Web-Frontend:

1. `GET /api/session` aufrufen, damit das Backend ein `connect.sid`-Cookie setzt und die `sessionId` zurueckgibt.
2. Socket.IO zu derselben Basis-URL verbinden.
3. Nach `connect` das Event `setSessionId` senden:

```json
{
  "expressSessionId": "<sessionId aus /api/session>"
}
```

4. Server sendet `connected`.
5. Wenn `connected.loggedIn === true`, App-State wiederherstellen.
6. Sonst Login-Screen anzeigen.

### Client sendet

| Event | Payload | Zweck |
|---|---|---|
| `setSessionId` | `{ "expressSessionId": string }` | Socket mit Express-Session verknuepfen |
| `login` | `{ "userName": string, "gender": string, "age": number, "country": string, "expressSessionId": string }` | Chat-Login |
| `message` | `{ "toUserName": string, "message": string, "messageId": string }` | Textnachricht |
| `message` | `{ "toUserName": string, "message": imageCode, "messageId": string, "isImage": true, "imageUrl": string }` | Bildnachricht nach REST-Upload |
| `requestConversation` | `{ "withUserName": string }` | Konversation laden und als gelesen markieren |
| `userSearch` | `{ "nameIncludes"?, "minAge"?, "maxAge"?, "countries"?, "genders"? }` | Benutzer suchen |
| `requestHistory` | kein Payload | Chatverlauf-Liste laden |
| `requestOpenConversations` | kein Payload | Inbox/ungelesene Chats laden |
| `blockUser` | `{ "userName": string }` | Benutzer blockieren |
| `unblockUser` | `{ "userName": string }` | Benutzer entblockieren |

### Server sendet

| Event | Payload | Android-State |
|---|---|---|
| `connected` | `{ "sessionId": string, "loggedIn"?: boolean, "user"?: User }` | Session setzen, ggf. Login wiederherstellen |
| `loginSuccess` | `{ "sessionId": string, "user": User }` | Login-State setzen |
| `userList` | `{ "users": User[] }` | Online-Liste aktualisieren |
| `message` | `{ "from": string, "message": string, "messageId": string, "timestamp": string, "isImage"?, "imageUrl"?, "imageCode"? }` | Nachricht empfangen |
| `messageSent` | `{ "messageId": string, "to": string }` | lokale Nachricht bestaetigen |
| `conversation` | `{ "with": string, "messages": Message[] }` | Konversation anzeigen |
| `searchResults` | `{ "results": User[] }` | Suchergebnisse anzeigen |
| `historyResults` | `{ "results": HistoryItem[] }` | Verlauf anzeigen |
| `inboxResults` | `{ "results": InboxItem[] }` | Inbox anzeigen |
| `unreadChats` | `{ "count": number }` | Badge aktualisieren |
| `commandResult` | `{ "lines": string[], "kind": string }` | Admin-/Slash-Command-Hinweise anzeigen |
| `commandTable` | `{ "title": string, "columns": string[], "rows": unknown[][] }` | Admin-/Statistik-Tabelle anzeigen |
| `userBlocked` | `{ "userName": string }` | Blockierstatus setzen |
| `userUnblocked` | `{ "userName": string }` | Blockierstatus entfernen |
| `error` | `{ "message": string }` | Snackbar/Dialog anzeigen |

## Android-Modulstruktur

Vorschlag fuer ein neues Modul oder separates Repo:

```text
android/
  app/
    src/main/
      java/net/ypchat/app/
        MainActivity.kt
        YpChatApp.kt
        core/
          Config.kt
          SessionCookieJar.kt
          NetworkModule.kt
        data/
          api/
            RestApi.kt
            SocketClient.kt
          model/
            UserDto.kt
            MessageDto.kt
            ConversationDto.kt
          repository/
            ChatRepository.kt
            FeedbackRepository.kt
        ui/
          login/
          chat/
          users/
          search/
          inbox/
          history/
          feedback/
          common/
```

### Verantwortlichkeiten

- `RestApi`: Retrofit-Definitionen fuer `/api/*`
- `SocketClient`: kapselt Socket.IO-Verbindung, Event-Handler und Emits
- `ChatRepository`: verbindet REST, Socket und lokalen App-State
- `ChatViewModel`: bietet `StateFlow<ChatUiState>` fuer Compose
- `SessionCookieJar`: persistiert `connect.sid`, damit REST und Socket dieselbe Session nutzen
- `ImageUploader`: Photo Picker, Komprimierung falls noetig, Multipart Upload

## UI-Konzept

### Navigation

MVP-Screens:

- Login
- Online-Benutzer
- Suche
- Chat
- Inbox
- Verlauf
- Profil/Logout

Optional:

- Feedback
- Partner
- Regeln/Sicherheit/FAQ als native Info-Screens oder WebContent aus statischen Texten

### Mobile UX

Der Webclient ist desktop-/browsernah. Die App sollte mobiler denken:

- Startet in Login oder zuletzt aktiver Chat-Ansicht
- Bottom Navigation fuer `Online`, `Suche`, `Inbox`, `Verlauf`
- Chat-Screen mit fester Eingabezeile unten
- Online-Status und Flagge direkt in User-Zeilen
- Unread-Badge auf Inbox-Tab
- Bildauswahl ueber Android Photo Picker
- Fehlermeldungen als Snackbar, kritische Session-Fehler als Dialog

## Session- und Reconnect-Konzept

### Persistenz

Gespeichert werden lokal:

- `connect.sid` Cookie
- letzter bekannter Login-State fuer UI-Skeleton
- Logout-Marker, analog `singlechat_logged_out` im Web
- keine Chatnachrichten dauerhaft im MVP, weil Backend diese aktuell nur im Arbeitsspeicher haelt

### Reconnect

Empfohlener Ablauf:

1. App startet.
2. Wenn kein Logout-Marker vorhanden: `GET /api/session`.
3. Wenn Session `loggedIn`: Socket verbinden und `setSessionId` senden.
4. Wenn Socket reconnectet: erneut `GET /api/session`, dann `setSessionId`.
5. Bei `connect_error`: exponentielles Retry mit sichtbarem Offline-Banner.
6. Bei Logout: `POST /api/logout`, Socket disconnect, Cookie loeschen, Logout-Marker setzen.

### Inaktivitaet

Backend und Webclient verwenden 30 Minuten. Android sollte dieselbe Regel im UI spiegeln:

- Timer startet nach `loginSuccess` oder Session-Restore.
- Timer wird bei Senden, Empfangen, Suche und Conversation Requests zurueckgesetzt.
- Bei Ablauf: lokaler Logout und optional `POST /api/logout`.

## Bildversand

Ablauf:

1. Benutzer waehlt Bild per Photo Picker.
2. App prueft MIME-Type und Groesse.
3. Optional: Bild auf sinnvolle Chat-Groesse komprimieren, z.B. max. 1600 px Kantenlaenge.
4. `POST /api/upload-image` als Multipart `image`.
5. Backend antwortet mit:

```json
{
  "success": true,
  "code": "<code>",
  "url": "/api/image/<code>"
}
```

6. App sendet Socket-Event `message` mit `isImage: true`, `message: code`, `imageUrl: url`.
7. Anzeige erfolgt ueber volle URL `https://www.ypchat.net/api/image/<code>`.

Hinweis: Der Backend-Endpunkt erlaubt 5 MB Upload und haelt Bilder temporaer fuer 6 Stunden.

## Backend-Anpassungen Vor Android-Release

Die App kann grundsaetzlich mit dem aktuellen Backend starten. Sinnvolle kleine Anpassungen wuerden die Mobile-Integration aber robuster machen:

- CORS ist fuer mobile Apps weniger kritisch, aber Socket.IO-Origin-Handling sollte getestet werden, weil native Clients oft keinen Browser-Origin senden.
- Session-Handling sollte fuer Android explizit dokumentiert werden: `GET /api/session` vor Socket-Verbindung.
- WebSocket ueber Apache sollte sauber funktionieren. Android kann Polling fallbacken, aber echte WebSocket-Verbindung ist fuer Akku und Latenz besser.
- `/api/upload-image` hat aktuell einen Fallback auf den zuletzt aktiven Client. Fuer Mobile waere sauberer: eindeutig ueber `req.sessionID` validieren und keine Aktivitaets-Heuristik verwenden.
- Nachrichten und Konversationen liegen aktuell im Arbeitsspeicher. Fuer eine App mit Reconnect/Background-Nutzung sollte mittelfristig Persistenz ergaenzt werden.
- Optional: API-Versionierung einfuehren, z.B. `/api/v1/session`, bevor App-Versionen langfristig im Umlauf sind.

## Datenschutz Und Store-Themen

Vor Veroeffentlichung im Play Store beachten:

- Datenschutzerklaerung direkt in App verlinken
- klare Alters-/Community-Regeln im Onboarding
- Hinweis, dass Chatnachrichten temporaer serverseitig verarbeitet werden
- Bild-Upload transparent erklaeren
- Melde-/Blockierfunktion prominent erreichbar machen
- Android `INTERNET` Permission erforderlich
- Keine Speicherpermission noetig, wenn Android Photo Picker genutzt wird

Wenn die App spaeter Push Notifications bekommt, braucht es FCM, Datenschutz-Ergaenzung und serverseitige Device-Token-Verwaltung.

## MVP-Backlog

### Phase 1: Android-Projekt

- Gradle/Kotlin/Compose-Projekt anlegen
- App-Theme und Basisnavigation erstellen
- `Config` fuer Dev/Prod-Basis-URL
- OkHttp, Retrofit und Socket.IO-Client einrichten
- Persistente CookieJar implementieren

### Phase 2: Session Und Login

- `GET /api/session`
- Socket-Verbindung mit `setSessionId`
- Login-Screen
- `login` Event
- `connected`, `loginSuccess`, `error`
- Logout mit `/api/logout`

### Phase 3: Chat-Kern

- Online-Userliste via `userList`
- Chat-Screen
- `requestConversation`
- Textnachrichten senden/empfangen
- `messageSent`, `unreadChats`
- Reconnect und Offline-Banner

### Phase 4: Suche, Inbox, Verlauf

- Suchformular und `userSearch`
- Suchergebnisse
- Inbox mit `requestOpenConversations`
- Verlauf mit `requestHistory`
- Blockieren/Entblockieren

### Phase 5: Bilder

- Android Photo Picker
- Multipart Upload zu `/api/upload-image`
- Bildnachricht via Socket senden
- Bildanzeige ueber `/api/image/:code`
- Fehlerbehandlung fuer abgelaufene Bilder

### Phase 6: Release-Haertung

- ProGuard/R8-Regeln fuer Socket.IO/OkHttp testen
- Crash-/Error-Logging entscheiden
- Play Store Icons, Screenshots, App Name
- Datenschutz-/Impressum-/Regeln-Screens
- Test auf Emulator, echtem Android-Geraet, schlechtem Netz und App-Background

## Risiken

| Risiko | Auswirkung | Gegenmassnahme |
|---|---|---|
| Socket.IO Android Client Version passt nicht zum Server | Verbindungsfehler | Version gegen Socket.IO Server 4.x testen, `allowEIO3` ist serverseitig aktiv |
| Session-Cookie wird nicht zwischen REST und Socket geteilt | Login/Upload funktionieren inkonsistent | gemeinsame OkHttp CookieJar und expliziter `setSessionId` Flow |
| Apache WebSocket-Proxy ist instabil | Reconnects/Latenz | WebSocket-Regeln pruefen, Polling als Fallback |
| Backend speichert Chat nur im RAM | Nachrichten nach Server-Restart weg | fuer MVP akzeptieren, spaeter DB-Persistenz |
| App im Hintergrund verliert Socket | Nachrichten kommen nur bei geoeffneter App | fuer MVP akzeptieren, spaeter Push Notifications |
| Bild-Upload-Session-Fallback ist unscharf | falsche Zuordnung theoretisch moeglich | Backend vor Release eindeutiger machen |

## Offene Entscheidungen

- Soll Android zuerst als separates Repo oder als `android/` Ordner in diesem Repo entstehen?
- Soll der MVP nur Chat enthalten oder auch Feedback/Partner/FAQ?
- Soll das bestehende Design exakt nachgebaut oder fuer Mobile bewusst neu interpretiert werden?
- Soll die erste Version ohne Push Notifications starten?

## Empfehlung Fuer Den Naechsten Schritt

Ich wuerde als naechstes ein Android-Projekt im Ordner `android/` scaffolden und zuerst nur den technischen Durchstich bauen:

1. `GET /api/session`
2. Socket.IO connect
3. `setSessionId`
4. Login
5. Empfang von `userList`
6. Senden und Empfangen einer Textnachricht

Wenn dieser Durchstich steht, ist der groesste technische Unsicherheitsblock geloest. Danach ist der Rest vor allem UI- und Zustandsarbeit.
