Files
singlechat/docs/ios-app-umsetzungsplan.md
Torsten Schulz (local) bfe28a25fa
All checks were successful
Deploy SingleChat / deploy (push) Successful in 40s
android app, extension of stats
2026-08-10 14:03:34 +02:00

13 KiB
Executable File
Raw Blame History

iOS-App für YpChat Umsetzungsplan

Dieses Dokument beschreibt die komplette Planung einer nativen iOS-App mit Feature-Parität zur bestehenden Android-App (android/app, Paket de.ypchat.android). Die Android-Implementierung dient als fachliche und API-Referenz.


1. Ziele und Abgrenzung

1.1 Produktziel

  • Nutzer können sich wie in der Android-App anmelden, chatten, suchen, Posteingang/Verlauf nutzen, Konsole-Befehle senden, Feedback und Partner-Links einsehen sowie Bilder hochladen und versenden.
  • Gleiche Backend-URLs, REST-Endpunkte und Socket.IO-Ereignisse wie auf Android.

1.2 Nicht-Ziele (optional später)

  • WatchOS, iPad-spezifisches Layout (erst iPhone-first).
  • Eigener Push-Benachrichtigungsdienst (nur falls das Backend später APNs unterstützt).

2. Referenz: Android-Architektur (zu spiegeln)

Schicht Android iOS-Empfehlung
Konfiguration BuildConfig.BASE_URL / local.properties Xcode Build-Konfiguration + xcconfig oder Info-Key BASE_URL
DI / Container AppContainer Eigene AppServices-Klasse oder schlankes Factory-Pattern beim App-Start
HTTP + Cookies OkHttp + SessionCookieJar URLSession mit HTTPCookieStorage (shared oder app-group bei Bedarf)
REST Retrofit + Gson URLSession + Codable (oder optional Alamofire)
Echtzeit io.socket (Socket.IO) socket.io-client-swift (oder vergleichbare aktive Library)
Zustand ChatRepository + StateFlow ObservableObject / @Observable + async oder Combine
UI Jetpack Compose SwiftUI (empfohlen)
Profil lokal ProfileStore (SharedPreferences) UserDefaults oder kleines Keychain-Wrapper nur wenn sensibel

Wichtige Dateien zum Abgleich: AppContainer.kt, RestApi.kt, SocketClient.kt, ChatRepository.kt, ChatViewModel.kt, YpChatRoot.kt, Models.kt, SocketEvent.kt.


3. Technologie- und Projektentscheidungen

3.1 Sprache und UI

  • Swift 5.10+, Deployment iOS 17+ (oder 16, wenn Gerätebindung es erfordert dann API prüfen).
  • SwiftUI für alle Screens; Navigation: TabView + eingebettete Unternavigation für „Mehr“.

3.2 Abhängigkeiten

  • Socket.IO-Client (Swift-Paket via SPM): muss dieselben Transporte unterstützen wie Android (websocket + polling); Verbindungsoptionen an SocketClient.kt anlehnen (Reconnect, Timeout).
  • Kein Retrofit native URLSession reicht für die überschaubare REST-Oberfläche.
  • Bilder: PhotosUI (PhotosPicker / PHPicker) für die Bildauswahl; Upload als multipart/form-data wie Android.

3.3 Bundle-ID und Naming

  • Vorschlag: de.ypchat.ios oder konsistent mit Android de.ypchat.android → z.B. de.ypchat.app (einheitlich mit Marketing/Store).
  • Anzeigename: wie R.string.app_name auf Android.

4. Konfiguration und Build-Varianten

4.1 Base-URL

  • Standard wie Android: https://www.ypchat.net (siehe defaultBaseUrl in android/app/build.gradle.kts).
  • Pro Build-Konfiguration überschreibbar:
    • Debug: lokale Config/Debug.xcconfig mit BASE_URL = https://… (oder Staging).
    • Release: feste Produktions-URL.
  • Zur Laufzeit: Bundle / generierte Info-Keys auslesen, trailing slash wie AppConfig.kt entfernen.

4.2 App Transport Security (ATS)

  • Produktion: HTTPS wie Android Release (usesCleartextTraffic false).
  • Debug: nur bei Bedarf NSAppTransportSecurity für HTTP-Testserver dokumentieren und nicht in Release aktiv lassen.

4.3 Berechtigungen (Info.plist)

  • Foto-Bibliothek (Lesen): NSPhotoLibraryUsageDescription mit klarer Begründung (Bild im Chat senden).
  • Keine Kamera zwingend nötig, wenn nur Galerie wie Android PickVisualMedia.

5. Datenmodell (Codable)

Alle DTOs aus Models.kt 1:1 als struct mit Codable abbilden, inkl. Sonderfall CountriesResponse: auf Android ein LinkedHashMap<String, String> auf iOS als [String: String] decodieren oder eigener Decodable-Wrapper.

PartnerLinkDto: JSON-Feld "Page Name"CodingKeys mit case pageName = "Page Name".


6. REST-API

Basis-URL + Pfad wie RestApi.kt:

Methode Pfad Zweck
GET api/session Session / eingeloggter User
POST api/logout Logout
GET api/countries Länderliste
GET api/feedback Feedback-Liste
GET api/feedback/admin-status Admin-Session-Status
POST api/feedback Feedback senden
POST api/feedback/admin-login Admin-Login
POST api/feedback/admin-logout Admin-Logout
DELETE api/feedback/{id} Eintrag löschen (Admin)
GET api/partners Partner-Links
POST api/upload-image Multipart-Feld image

Cookie-Handling: Nach session-Call und weiteren Requests müssen Cookies wie im Browser/OkHttp mitgeführt werden URLSessionConfiguration.default mit httpCookieStorage und httpShouldSetCookies / httpCookieAcceptPolicy prüfen; bei Problemen explizit Cookie-Header aus Storage für die Domain setzen.

Fehlerbehandlung: HTTP-Status und Body auswerten; Fehlermeldungen in den UI-State wie ChatState.errorMessage / feedbackMessage.


7. Socket.IO-Client

7.1 Verbindung

  • URL: gleiche baseUrl wie REST (ohne zusätzlichen Pfad, sofern Server Root nutzt mit Android-Verhalten abgleichen).
  • Optionen analog SocketClient.kt: Reconnect, reconnectionAttempts, Delays, Timeout; Transports WebSocket + Polling falls die Swift-Library das abbildet.

7.2 Authentifizierung / Session

  • Beim Connect bzw. nach Connect: setSessionId mit Payload { "expressSessionId": "<id>" } identisch zu Android.
  • pendingExpressSessionId bei erneutem Connect erneut senden.

7.3 Client → Server (emit)

Event Payload-Felder (Kern)
login userName, gender, age, country, expressSessionId
message message, messageId, optional toUserName; für Bild: toUserName, isImage, imageUrl
requestConversation withUserName
userSearch nameIncludes, minAge, maxAge, countries[], genders[]
requestHistory (leer)
requestOpenConversations (leer)
blockUser / unblockUser userName

7.4 Server → Client (on)

Alle Events aus SocketClient.kt abbilden und in ein internes enum / sealed Äquivalent übersetzen: connected, loginSuccess, userList, message, messageSent, conversation, searchResults, historyResults, inboxResults, unreadChats, userBlocked, userUnblocked, commandResult, commandTable, error, sowie Verbindungsmetadaten (connect, disconnect, connect_error).

JSON-Parsing: Foundation JSONSerialization oder JSONDecoder mit [String: Any]-Hilfstypen Feldnamen und Typen strikt an Android-Mapper (toUserDto, toMessageDto, …) halten.

7.5 HTTP-Stack und Socket

  • Android nutzt dieselbe OkHttpClient-Instanz für Socket und REST. Auf iOS: wo möglich eine gemeinsame Cookie-Quelle; falls die Socket-Library keinen URLSession teilt, nach dem Connect sicherstellen, dass expressSessionId per setSessionId gesetzt ist (wie Android bei getrenntem Transport).

8. Repository- und App-Logik (ChatRepository)

Die Reducer-Logik aus ChatRepository.reduce und die Methoden funktional kopieren:

  • restoreSession: Profil laden, Länder laden, feedbackAdminStatus, GET api/session, dann Socket connect + setSessionId.
  • login: Profil speichern, Session-ID beschaffen, Socket ggf. verbinden, login emit.
  • logout: POST api/logout, Socket trennen, Cookies löschen, State reset mit erhaltenem savedProfile und countries.
  • Timeout: 30 Minuten (1800 s) Ticker jede Sekunde, bei 0 automatisch logout (wie startTimeoutTicker / resetTimeout).
  • openConversation / closeConversation, sendMessage (inkl. Konsolen-Befehle mit /), search, inbox/history, block/unblock.
  • Bild: Upload REST → bei Erfolg sendImage mit absoluter URL (Basis-URL voranstellen wenn relativ).

Zustand als eine ChatState-Struktur (alle Properties aus ChatRepository.kt).


9. Präsentationsschicht (SwiftUI)

9.1 ViewModel

  • @MainActor ViewModel (oder Repository auf MainActor publizieren), das ChatState published und User-Aktionen an das Repository delegiert.
  • task { await repository.restoreSession() } beim Erscheinen der Root-View.

9.2 Bildschirme (Parität zu YpChatRoot)

  1. Login: Landing-Karte, Profilfelder, Gender/Country-Picker, Validierung (Nickname ≥ 3 Zeichen), Socket-Status.
  2. Haupt-Shell: Top-Bar (App-Name, User, Online-Status, Timeout-Countdown, Logout).
  3. Tabs: Online | Suche | Posteingang | Verlauf | Konsole | Mehr wie Android; Posteingang-Badge mit unreadChatsCount.
  4. Chat: Zurück, Blockieren/Entblocken, Nachrichtenliste, Eingabe, Smiley-Leiste (gleiche Tokens wie SmileyItems), Bild wählen, Senden, Upload-Banner.
  5. Suche / Inbox / Verlauf: Listen wie Android.
  6. Konsole: Eingabe, Senden, Ausgabezeilen + Tabelle (CommandTableState).
  7. Mehr: Unterseiten Feedback (inkl. Admin-Login), Partner (Safari öffnen), FAQ, Regeln, Sicherheit, Impressum Texte aus lokalisierten Strings (siehe res/values/strings.xml auf Android als Quelle für DE/EN).

9.3 Design

  • Farben und Abstände an die Android-Farbkonstanten in YpChatRoot.kt anlehnen für ein konsistentes Erscheinungsbild.
  • Bilder in Chat: AsyncImage / Kingfisher nur falls nötig; Caching beachten.

9.4 Lokalisierung

  • Localizable.xcstrings (oder .strings) mindestens Deutsch; Android-strings.xml als Master-Liste.

10. Sicherheit und Datenschutz

  • Passwörter (Feedback-Admin) nur im Speicher, nicht loggen.
  • TLS in Release erzwingen.
  • Keychain nur nötig, wenn sensible Tokens dauerhaft ohne Cookies gespeichert werden sollen (aktuell: Session eher cookie-basiert wie Web).

11. Qualitätssicherung

11.1 Tests

  • Unit-Tests: JSON-Decodierung der REST- und Socket-Payloads (Fixtures aus echten Server-Responses erfassen).
  • Integration: Manuell gegen Staging/Produktion: Login, Nachricht, Suche, Feedback, Bild-Upload, Logout, Timeout.

11.2 Edge Cases

  • App in den Hintergrund: Socket-Verhalten (Disconnect/Reconnect) und Timeout-Reset gemäß Produktregel klären (Android tickt weiter iOS analog umsetzen).
  • Schlechte Netzwerke: Fehlermeldungen aus SocketEvent.Error und REST anzeigen.

12. App Store / Vertrieb

  • Apple Developer Program, App-ID, Provisioning Profiles.
  • Datenschutzerklärung und App-Privacy-Labels (Netzwerk, Fotos, ggf. Nutzerinhalt).
  • TestFlight für interne Tester vor Release.
  • Versionierung: an versionName / versionCode der Android-App angleichen oder eigenes Schema dokumentieren.

13. Repository-Struktur (Vorschlag)

ios/
  YpChat.xcodeproj oder YpChat.xcworkspace
  YpChat/
    App/
    Core/           # AppConfig, Cookie/Session storage, ProfileStore
    Data/           # APIClient, SocketClient, DTOs
    Features/       # Login, Chat, Tabs, More, …
    Resources/      # Assets, Localizable
  Config/
    Debug.xcconfig
    Release.xcconfig

Root-README oder dieses Dokument verlinken, wie man BASE_URL setzt.


14. Phasenplan (Meilensteine)

Phase Inhalt Ergebnis
P0 Xcode-Projekt, Konfiguration, leere SwiftUI-App, BASE_URL Laufende Shell-App
P1 REST-Client + Cookie-Speicher, session / countries / logout Session funktioniert
P2 Socket-Client, setSessionId, login, userList, message Minimaler Chat
P3 Vollständiger ChatRepository-State, alle Socket-Events, Timeout Parität Kernlogik
P4 SwiftUI: Login + Tabs + Chat + Suche/Inbox/Verlauf UI-Hauptteil
P5 Bild-Upload + Anzeige, Smileys Medien-Parität
P6 Mehr: Feedback, Partner, statische Seiten Rest-UI
P7 Lokalisierung, Feinschliff, Dark Mode optional Polish
P8 TestFlight, Store-Metadaten, Screenshots Release

15. Risiken und Abhängigkeiten

  • Socket.IO-Swift-Version muss zum Server-Socket.IO passen; bei Protokoll-Mismatch Verbindungsfehler mit Server-Version abgleichen.
  • Cookie-Domain / Pfad: muss mit dem Backend identisch sein, sonst wirkt session wie „nicht eingeloggt“.
  • Bildgröße: 5MB-Limit clientseitig wie Android (MAX_IMAGE_BYTES).

16. Nächster konkreter Schritt

  1. Im Repo Ordner ios/ anlegen und Xcode-Projekt (SwiftUI App) hinzufügen.
  2. SPM: Socket.IO-Client einbinden, minimales SocketClient-Swift gegen Staging testen.
  3. GET api/session mit gemeinsamem Cookie-Storage verifizieren.
  4. Danach schrittweise ChatRepository portieren und UI anbinden.

Stand: Abgleich mit Android-Codebase (Compose-App, Mai 2026). Bei Backend-Änderungen diesen Plan und die Event-Liste aktualisieren.