Tech-Debt-Cleanup: Doku, Security-Hardening, Server-Validierung, Client-Stabilitaet #2

Merged
tim merged 4 commits from feature/techdebt-cleanup into master 2026-09-01 19:00:25 +00:00
Owner

Doku/Repo:

  • README.md mit Setup, Run-Anleitung, Konfiguration und Sprachpolicy neu geschrieben
  • appsettings.json: committed JWT-Key und irreführende LocalDB-Connection-String entfernt
  • appsettings.Development.json: expliziter Dev-Only JWT-Key hinterlegt
  • build.yml: Build-CI für master/PRs hinzugefügt
  • slnx/aspire.config.json: Pfad-Casing korrigiert (Linux-kompatibel)
  • .gitignore: Kommentar zu den Legacy-SQLite-Einträgen

Server:

  • Jwt:Key ist in Production Pflicht (Fail-fast statt Fallback-Secret)
  • Passwort-Mindestlänge 8 Zeichen bei Registrierung
  • StartGame: nur aus Lobby, mindestens 2 Spieler
  • SetPlayerReady: gameId/Status geprüft
  • SubmitSlip: Game-/Round-Status, Round-Membership, IsUsed validiert
  • CreateChallenge: Round-Bindung, kein Self-Challenge, nur gespielte Karten, keine Doppel-Challenges
  • ResolveChallenge: Pending-Guard, Scoring (Score/SuccessfulSlips/FailedSlips), Approved-Transfer gefixt
  • GetPlayerHand: nur Karten der aktiven Runde
  • RoundTimeRemaining: StartedAt wird bei Round-Aktivierung gesetzt
  • Lobby-Code: crypto-random mit Kollisions-Retry
  • EF: explizite NpgsqlDataSource-Auflösung aus DI
  • Hub: Reconnect-Gruppenbeitritt, ConnectionId-Cleanup beim Disconnect, ChallengingPlayerName gesetzt, SlipChallenged/ChallengeResolved konsistent

Client:

  • Offline-Start löscht Session nicht mehr (NetworkError vs. Invalid unterschieden)
  • ResolveChallenge geht durch die Offline-Queue (kein Crash mehr bei Disconnect)
  • Queue: Poison-Entries werden nach 3 Retries verworfen statt die Queue ewig zu blockieren
  • SignalR: Verbindung wird sauber disposed/rebuildet, Token immer zur Laufzeit gelesen, Connect-Lock gegen parallele Starts
  • ViewModels: Thread-Marshaling in allen Receive-Handlern, kein async void mehr
  • LobbyViewModel: Logout deaktiviert den Singleton (kein stale-Navigation mehr), Reaktivierung via Activate()
  • GameBoard: lokaler 1s-Timer für RoundTimeRemaining
  • Overlay: x:DataType für kompilierte Bindings, Frame→Border
  • csproj: Preview-Logging-Package auf 10.0.10, Template-Cruft entfernt
Doku/Repo: - README.md mit Setup, Run-Anleitung, Konfiguration und Sprachpolicy neu geschrieben - appsettings.json: committed JWT-Key und irreführende LocalDB-Connection-String entfernt - appsettings.Development.json: expliziter Dev-Only JWT-Key hinterlegt - build.yml: Build-CI für master/PRs hinzugefügt - slnx/aspire.config.json: Pfad-Casing korrigiert (Linux-kompatibel) - .gitignore: Kommentar zu den Legacy-SQLite-Einträgen Server: - Jwt:Key ist in Production Pflicht (Fail-fast statt Fallback-Secret) - Passwort-Mindestlänge 8 Zeichen bei Registrierung - StartGame: nur aus Lobby, mindestens 2 Spieler - SetPlayerReady: gameId/Status geprüft - SubmitSlip: Game-/Round-Status, Round-Membership, IsUsed validiert - CreateChallenge: Round-Bindung, kein Self-Challenge, nur gespielte Karten, keine Doppel-Challenges - ResolveChallenge: Pending-Guard, Scoring (Score/SuccessfulSlips/FailedSlips), Approved-Transfer gefixt - GetPlayerHand: nur Karten der aktiven Runde - RoundTimeRemaining: StartedAt wird bei Round-Aktivierung gesetzt - Lobby-Code: crypto-random mit Kollisions-Retry - EF: explizite NpgsqlDataSource-Auflösung aus DI - Hub: Reconnect-Gruppenbeitritt, ConnectionId-Cleanup beim Disconnect, ChallengingPlayerName gesetzt, SlipChallenged/ChallengeResolved konsistent Client: - Offline-Start löscht Session nicht mehr (NetworkError vs. Invalid unterschieden) - ResolveChallenge geht durch die Offline-Queue (kein Crash mehr bei Disconnect) - Queue: Poison-Entries werden nach 3 Retries verworfen statt die Queue ewig zu blockieren - SignalR: Verbindung wird sauber disposed/rebuildet, Token immer zur Laufzeit gelesen, Connect-Lock gegen parallele Starts - ViewModels: Thread-Marshaling in allen Receive-Handlern, kein async void mehr - LobbyViewModel: Logout deaktiviert den Singleton (kein stale-Navigation mehr), Reaktivierung via Activate() - GameBoard: lokaler 1s-Timer für RoundTimeRemaining - Overlay: x:DataType für kompilierte Bindings, Frame→Border - csproj: Preview-Logging-Package auf 10.0.10, Template-Cruft entfernt
tim added 1 commit 2026-08-22 17:48:09 +00:00
Tech-Debt-Cleanup: Doku, Security-Hardening, Server-Validierung, Client-Stabilitaet
Some checks failed
Build / build (pull_request) Has been cancelled
af6528ee68
Doku/Repo:
- README.md mit Setup, Run-Anleitung, Konfiguration und Sprachpolicy neu geschrieben
- appsettings.json: committed JWT-Key und irreführende LocalDB-Connection-String entfernt
- appsettings.Development.json: expliziter Dev-Only JWT-Key hinterlegt
- build.yml: Build-CI für master/PRs hinzugefügt
- slnx/aspire.config.json: Pfad-Casing korrigiert (Linux-kompatibel)
- .gitignore: Kommentar zu den Legacy-SQLite-Einträgen

Server:
- Jwt:Key ist in Production Pflicht (Fail-fast statt Fallback-Secret)
- Passwort-Mindestlänge 8 Zeichen bei Registrierung
- StartGame: nur aus Lobby, mindestens 2 Spieler
- SetPlayerReady: gameId/Status geprüft
- SubmitSlip: Game-/Round-Status, Round-Membership, IsUsed validiert
- CreateChallenge: Round-Bindung, kein Self-Challenge, nur gespielte Karten, keine Doppel-Challenges
- ResolveChallenge: Pending-Guard, Scoring (Score/SuccessfulSlips/FailedSlips), Approved-Transfer gefixt
- GetPlayerHand: nur Karten der aktiven Runde
- RoundTimeRemaining: StartedAt wird bei Round-Aktivierung gesetzt
- Lobby-Code: crypto-random mit Kollisions-Retry
- EF: explizite NpgsqlDataSource-Auflösung aus DI
- Hub: Reconnect-Gruppenbeitritt, ConnectionId-Cleanup beim Disconnect, ChallengingPlayerName gesetzt, SlipChallenged/ChallengeResolved konsistent

Client:
- Offline-Start löscht Session nicht mehr (NetworkError vs. Invalid unterschieden)
- ResolveChallenge geht durch die Offline-Queue (kein Crash mehr bei Disconnect)
- Queue: Poison-Entries werden nach 3 Retries verworfen statt die Queue ewig zu blockieren
- SignalR: Verbindung wird sauber disposed/rebuildet, Token immer zur Laufzeit gelesen, Connect-Lock gegen parallele Starts
- ViewModels: Thread-Marshaling in allen Receive-Handlern, kein async void mehr
- LobbyViewModel: Logout deaktiviert den Singleton (kein stale-Navigation mehr), Reaktivierung via Activate()
- GameBoard: lokaler 1s-Timer für RoundTimeRemaining
- Overlay: x:DataType für kompilierte Bindings, Frame→Border
- csproj: Preview-Logging-Package auf 10.0.10, Template-Cruft entfernt
tim added 1 commit 2026-08-22 18:14:56 +00:00
Signed-off-by: Tim Krampitz <Tim.Krampitz@live.com>
tim added 1 commit 2026-08-23 12:47:41 +00:00
Fix CI build workflow, index casing, and test assertions
All checks were successful
Build / build (pull_request) Successful in 2m16s
660fc4d311
Author
Owner

Code-Review-Findings

P1 – Challenge kann spielübergreifend angelegt werden

SlipItIn.Server/Services/GameService.cs:197 übernimmt challengingPlayerId ohne Prüfung, ob der Spieler zum gameId gehört. Der Hub prüft in SlipItIn.Server/Hubs/GameHub.cs:258 nur, ob die Spieler-ID dem authentifizierten Benutzer gehört. Dadurch kann ein Benutzer als Spieler aus Spiel A eine Karte in Spiel B challengen; die Challenge wird dann in Spiel B gespeichert und kann dort Spielstand/Kartenbesitz verändern.

Bitte im Service zusätzlich sicherstellen, dass challengingPlayerId zu gameId gehört, z. B. über eine Abfrage mit p.Id == challengingPlayerId && p.GameId == gameId. Die Prüfung sollte im Service bleiben und durch einen Test für diesen Cross-Game-Fall abgesichert werden.

P2 – CI baut MAUI ohne explizite Workload-Installation

.github/workflows/build.yml:34 baut das MAUI-Projekt direkt nach actions/setup-dotnet, ohne den erforderlichen MAUI-Workload zu installieren. Auf einem frischen Runner kann der Build deshalb mit NETSDK1147 fehlschlagen.

Bitte vor dem Client-Build explizit dotnet workload install maui ausführen oder den benötigten Plattform-Workload gezielt installieren und den Workflow auf einem frischen Runner verifizieren.

Die lokalen 78 Server-Tests sowie der lokale MAUI-Build waren erfolgreich; der MAUI-Build meldet jedoch bestehende Warnungen.

## Code-Review-Findings ### P1 – Challenge kann spielübergreifend angelegt werden `SlipItIn.Server/Services/GameService.cs:197` übernimmt `challengingPlayerId` ohne Prüfung, ob der Spieler zum `gameId` gehört. Der Hub prüft in `SlipItIn.Server/Hubs/GameHub.cs:258` nur, ob die Spieler-ID dem authentifizierten Benutzer gehört. Dadurch kann ein Benutzer als Spieler aus Spiel A eine Karte in Spiel B challengen; die Challenge wird dann in Spiel B gespeichert und kann dort Spielstand/Kartenbesitz verändern. Bitte im Service zusätzlich sicherstellen, dass `challengingPlayerId` zu `gameId` gehört, z. B. über eine Abfrage mit `p.Id == challengingPlayerId && p.GameId == gameId`. Die Prüfung sollte im Service bleiben und durch einen Test für diesen Cross-Game-Fall abgesichert werden. ### P2 – CI baut MAUI ohne explizite Workload-Installation `.github/workflows/build.yml:34` baut das MAUI-Projekt direkt nach `actions/setup-dotnet`, ohne den erforderlichen MAUI-Workload zu installieren. Auf einem frischen Runner kann der Build deshalb mit `NETSDK1147` fehlschlagen. Bitte vor dem Client-Build explizit `dotnet workload install maui` ausführen oder den benötigten Plattform-Workload gezielt installieren und den Workflow auf einem frischen Runner verifizieren. Die lokalen 78 Server-Tests sowie der lokale MAUI-Build waren erfolgreich; der MAUI-Build meldet jedoch bestehende Warnungen.
tim added 1 commit 2026-09-01 18:51:36 +00:00
P1: Challenger-Zugehörigkeit zum Spiel validieren; P2: MAUI-Workload im CI installieren
All checks were successful
Build / build (pull_request) Successful in 6m10s
7953b8ddd0
- GameService.CreateChallengeAsync prüft jetzt, dass challengingPlayerId zum gameId gehört
- Zwei neue Tests für Cross-Game-/Fremdspieler-Challenges
- CI: dotnet workload install maui vor dem Restore, damit MAUI auf frischen Runnern baut
tim merged commit 118660a207 into master 2026-09-01 19:00:25 +00:00
tim deleted branch feature/techdebt-cleanup 2026-09-01 19:00:26 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: tim/SlipItIn#2