# Slip It In – Architektur-Updates (Phase 2b & 3b) Dieses Dokument fasst die Sicherheits- und Stabilitäts-Erweiterungen zusammen, die dem ProjectPlan.md hinzugefügt wurden. ## 🔒 Backend-Sicherheit (Phase 2b) ### 1. JWT-Claims Validation im GameHub - **Problem**: Clients könnten falsche PlayerId-Claims senden (Spoofing) - **Lösung**: `GetAuthenticatedUserId()` extrahiert User-ID aus JWT-Claims - **Implementierung**: Jede Hub-Methode validiert `Context.User?.FindFirst(ClaimTypes.NameIdentifier)` ### 2. IDbContextFactory statt Scoped DbContext - **Problem**: Bei parallelen SignalR-Aufrufen kann es zu Race Conditions kommen - **Lösung**: `IDbContextFactory` erzeugt isolierte Sessions pro Aufruf - **Vorteil**: Phrase-Transfer ist thread-safe, keine Conflicts bei 2 gleichzeitigen Challenges ### 3. Serverseitige Validierung - **Regel**: Clients senden nur "Ich möchte X machen", Server prüft ALLES - **Beispiel**: `SubmitSlipAsync()` prüft auf dem Server: - ✅ Gehört die Phrase dem Spieler? - ✅ Ist die Runde aktiv? - ✅ Ist der Spieler noch im Spiel? ### 4. Daten-Isolation (GameStateDto vs. PlayerHandDto) - **GameStateDto**: Öffentliche Daten (Username, Score, CardCount) → für ALLE sichtbar - **PlayerHandDto**: Private Daten (Text der eigenen Karten) → nur für den Spieler selbst - **Ergebnis**: Gegner sehen nicht, welche Phrasen ich habe! --- ## 📱 Client-Stabilität (Phase 3b) ### 1. WeakReferenceMessenger für Event-Entkopplung - **Problem**: Services rufen ViewModels direkt auf → Memory Leaks wenn VM disposed - **Lösung**: Services senden Messages via `WeakReferenceMessenger.Default.Send()` - **Vorteil**: ViewModels können sich abmelden ohne zirkuläre Abhängigkeiten **Beispiel:** ```csharp // Service sendet Event WeakReferenceMessenger.Default.Send(new GameStateChangedMessage(newState)); // ViewModel empfängt (mit auto-cleanup beim Dispose) WeakReferenceMessenger.Default.Register(this, (r, m) => { CurrentGameState = m.Value; }); ``` ### 2. Automatischer Reconnect - **Strategie**: Exponential Backoff (0s → 2s → 10s → 30s) - **Pufferung**: Offline-Aktionen werden in lokale Queue geschrieben - **Resync**: Nach Reconnect wird `ResyncAsync()` aufgerufen **Flow:** 1. SignalR-Verbindung getrennt 2. Client speichert "Slip zu Phrase X" in lokale Queue 3. Nach 2s Automatischer Reconnect-Versuch 4. Nach erfolgreichem Reconnect: Queued Actions werden abgesendet ### 3. State Restoration - **App-Pause**: `GameStateService` speichert aktuellen State in `SecureStorage` - **App-Resume**: `ResyncAsync()` wird aufgerufen - ✅ Holt aktuellen GameState vom Server - ✅ Sendet gepufferte Offline-Aktionen erneut - ✅ UI zeigt "Syncing..." bis fertig ### 4. Dual-Layer Storage - **In-Memory Layer**: `GameStateService` halten aktuellen State - **Persistent Layer**: `SecureStorage`/`Preferences` speichern Backup - **Fehler-Handling**: Nach App-Crash kann State aus Persistent Layer wiederhergestellt werden --- ## 📊 Schnellreferenz: Neue Components ### Backend ``` GameHub ├─ GetAuthenticatedUserId() → JWT-Validierung ├─ ValidatePlayerAccessAsync() → Authorization Check └─ Alle Methoden nutzen IDbContextFactory Program.cs ├─ AddDbContextFactory() ├─ AddAuthentication(JwtBearerDefaults) └─ AddSignalR() mit JWT-Filter DTOs ├─ GameStateDto (öffentlich) ├─ PlayerHandDto (privat) └─ Keine CardText in GameStateDto! ``` ### Client ``` GameStateService ├─ CurrentGameState (in-memory) ├─ CurrentPlayerHand (in-memory) ├─ UpdateGameStateAsync() → speichert + sendet Message └─ ResyncAsync() → bei App-Resume SignalRService ├─ ConnectAsync(token) mit Auto-Reconnect ├─ RequestGameStateAsync() └─ On<> Handler senden Messages Messages (WeakReferenceMessenger) ├─ GameStateChangedMessage ├─ PlayerHandChangedMessage └─ ChallengeReceivedMessage ``` --- ## 🧪 Wichtigste Tests | Test | Ziel | |------|------| | **JWT-Auth** | Hub lehnt Requests ohne gültiges Token ab | | **Player-Access** | User A kann nicht auf Players von User B zugreifen | | **Race Condition** | Phrase-Transfer ist thread-safe bei 2 gleichzeitigen Challenges | | **Offline-Queue** | Aktionen während Netzwerk-Ausfall werden gepuffert und später gesendet | | **Memory Leaks** | Keine Leaks wenn ViewModels disposed werden (WeakReference) | | **State-Sync** | App-Resume synct korrekt mit Server-State | --- ## 🚀 Implementierungs-Reihenfolge 1. **Backend zuerst**: JWT-Auth + IDbContextFactory konfigurieren 2. **GameService erweitern**: Serverseitige Validierung in alle Methoden 3. **Client-Services**: GameStateService + SignalRService implementieren 4. **Messaging**: WeakReferenceMessenger in ViewModels integrieren 5. **Tests**: Integrationstest-Suite schreiben 6. **UI**: Views an neue Message-Events binden