Files
singlechat/ANDROID-APP-KONZEPT.md
Torsten Schulz (notebook) 84f57facba android version
2026-05-12 10:21:24 +02:00

15 KiB

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

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:

https://www.ypchat.net

Development:

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:
{
  "expressSessionId": "<sessionId aus /api/session>"
}
  1. Server sendet connected.
  2. Wenn connected.loggedIn === true, App-State wiederherstellen.
  3. 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:

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:
{
  "success": true,
  "code": "<code>",
  "url": "/api/image/<code>"
}
  1. App sendet Socket-Event message mit isImage: true, message: code, imageUrl: url.
  2. 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.