13 KiB
Executable File
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 anSocketClient.ktanlehnen (Reconnect, Timeout). - Kein Retrofit – native
URLSessionreicht für die überschaubare REST-Oberfläche. - Bilder: PhotosUI (
PhotosPicker/PHPicker) für die Bildauswahl; Upload alsmultipart/form-datawie Android.
3.3 Bundle-ID und Naming
- Vorschlag:
de.ypchat.iosoder konsistent mit Androidde.ypchat.android→ z. B.de.ypchat.app(einheitlich mit Marketing/Store). - Anzeigename: wie
R.string.app_nameauf Android.
4. Konfiguration und Build-Varianten
4.1 Base-URL
- Standard wie Android:
https://www.ypchat.net(siehedefaultBaseUrlinandroid/app/build.gradle.kts). - Pro Build-Konfiguration überschreibbar:
- Debug: lokale
Config/Debug.xcconfigmitBASE_URL = https://…(oder Staging). - Release: feste Produktions-URL.
- Debug: lokale
- Zur Laufzeit:
Bundle/ generierteInfo-Keys auslesen, trailing slash wieAppConfig.ktentfernen.
4.2 App Transport Security (ATS)
- Produktion: HTTPS wie Android Release (
usesCleartextTrafficfalse). - Debug: nur bei Bedarf
NSAppTransportSecurityfür HTTP-Testserver – dokumentieren und nicht in Release aktiv lassen.
4.3 Berechtigungen (Info.plist)
- Foto-Bibliothek (Lesen):
NSPhotoLibraryUsageDescriptionmit 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
baseUrlwie 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:
setSessionIdmit Payload{ "expressSessionId": "<id>" }– identisch zu Android. pendingExpressSessionIdbei 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 keinenURLSessionteilt, nach dem Connect sicherstellen, dassexpressSessionIdpersetSessionIdgesetzt 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,
loginemit. - logout:
POST api/logout, Socket trennen, Cookies löschen, State reset mit erhaltenemsavedProfileundcountries. - Timeout: 30 Minuten (
1800s) – Ticker jede Sekunde, bei 0 automatischlogout(wiestartTimeoutTicker/resetTimeout). - openConversation / closeConversation, sendMessage (inkl. Konsolen-Befehle mit
/), search, inbox/history, block/unblock. - Bild: Upload REST → bei Erfolg
sendImagemit absoluter URL (Basis-URL voranstellen wenn relativ).
Zustand als eine ChatState-Struktur (alle Properties aus ChatRepository.kt).
9. Präsentationsschicht (SwiftUI)
9.1 ViewModel
@MainActorViewModel (oder Repository auf MainActor publizieren), dasChatStatepublished und User-Aktionen an das Repository delegiert.task { await repository.restoreSession() }beim Erscheinen der Root-View.
9.2 Bildschirme (Parität zu YpChatRoot)
- Login: Landing-Karte, Profilfelder, Gender/Country-Picker, Validierung (Nickname ≥ 3 Zeichen), Socket-Status.
- Haupt-Shell: Top-Bar (App-Name, User, Online-Status, Timeout-Countdown, Logout).
- Tabs: Online | Suche | Posteingang | Verlauf | Konsole | Mehr – wie Android; Posteingang-Badge mit
unreadChatsCount. - Chat: Zurück, Blockieren/Entblocken, Nachrichtenliste, Eingabe, Smiley-Leiste (gleiche Tokens wie
SmileyItems), Bild wählen, Senden, Upload-Banner. - Suche / Inbox / Verlauf: Listen wie Android.
- Konsole: Eingabe, Senden, Ausgabezeilen + Tabelle (
CommandTableState). - Mehr: Unterseiten Feedback (inkl. Admin-Login), Partner (Safari öffnen), FAQ, Regeln, Sicherheit, Impressum – Texte aus lokalisierten Strings (siehe
res/values/strings.xmlauf Android als Quelle für DE/EN).
9.3 Design
- Farben und Abstände an die Android-Farbkonstanten in
YpChatRoot.ktanlehnen 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.xmlals 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.Errorund 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/versionCodeder 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
sessionwie „nicht eingeloggt“. - Bildgröße: 5 MB-Limit clientseitig wie Android (
MAX_IMAGE_BYTES).
16. Nächster konkreter Schritt
- Im Repo Ordner
ios/anlegen und Xcode-Projekt (SwiftUI App) hinzufügen. - SPM: Socket.IO-Client einbinden, minimales
SocketClient-Swift gegen Staging testen. GET api/sessionmit gemeinsamem Cookie-Storage verifizieren.- Danach schrittweise
ChatRepositoryportieren und UI anbinden.
Stand: Abgleich mit Android-Codebase (Compose-App, Mai 2026). Bei Backend-Änderungen diesen Plan und die Event-Liste aktualisieren.