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.
This commit is contained in:
275
docs/ios-app-umsetzungsplan.md
Normal file
275
docs/ios-app-umsetzungsplan.md
Normal file
@@ -0,0 +1,275 @@
|
||||
# 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](https://github.com/socketio/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:** 5 MB-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.*
|
||||
Reference in New Issue
Block a user