Files
singlechat/docs/ios-app-umsetzungsplan.md
Torsten Schulz (local) 810b084e10 Refactor application structure and configuration
- Updated the application namespace and ID from "net.ypchat.app" to "de.ypchat.android" for better alignment with branding.
- Increased Gradle heap size settings to optimize build performance.
- Disabled dependency constraints to simplify dependency management.
- Removed obsolete files related to the previous application structure, including MainActivity, YpChatApp, and various core components, streamlining the codebase.

These changes collectively enhance the application's configuration and structure, improving maintainability and performance.
2026-05-12 14:25:55 +02:00

13 KiB
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.