Umfangreiche Erweiterung der Skill-Bibliothek: Neue Skills für Humanisierung (Englisch/PT-BR), Design-Validierung, AI-SEO und Coolify-Deployment inkl. Regelwerke, Presets, Pattern-Referenzen, Testfälle und Automatisierungsskripte. Zusätzliche Skills für Revenue-Centric Design, Pier Cloud, OKF, Lebenslauf- und LinkedIn-Optimierung sowie zahlreiche Referenzdateien, Checklisten und YAML/JSON/Markdown-Templates. Einführung einer vollständigen OpenWiki-Dokumentation mit Architektur-, Domain- und Workflow-Beschreibungen, zentralem Index und automatisierten Updates. Modularer Aufbau, restriktive Lizenzen und umfassende Qualitäts- und Evaluationsmechanismen für alle neuen Inhalte.
7.6 KiB
type, title, description, tags
| type | title | description | tags | |||||
|---|---|---|---|---|---|---|---|---|
| Workflow | Slip & Challenge Workflows | Real-time game loops covering lobby creation, card dealing, phrase slipping, slip challenging, and challenge resolution. |
|
Slip & Challenge Workflows
This document outlines the core real-time game workflows in SlipItIn, detailing how SignalR events, backend service operations, database updates, and client state notifications interact.
These workflows execute state transitions on domain entities, invoke real-time methods in the ASP.NET Core GameHub, are implemented across backend services mapped in the source map, and are verified using tests described in the operations runbook.
1. Game Setup & Lobby Workflow
[Host] CreateLobby() ──> Generate 6-Char LobbyCode ──> Add to SignalR Group
│
[Player] JoinLobby() ──> Verify MaxPlayers & Status ───────────┤
│
[Player] PlayerReady() ──> Set IsReady = true ─────────────────┼──> Broadcast GameStateUpdated
│
[Host] StartGame() ──> Deal 5 Random Cards Per Player ─────────┴──> Unicast PlayerHandUpdated
- Lobby Creation: Host calls
GameHub.CreateLobby().GameService.CreateGameAsync()creates aGamerecord (Status = Lobby), generates a random 6-characterLobbyCode, adds the host as the firstPlayer, and registers the host's WebSocketConnectionId. Caller receivesLobbyCreated. - Joining Lobby: Opponents invoke
GameHub.JoinLobby(lobbyCode).GameService.JoinGameAsync()validates that the game exists, has space (Players.Count < MaxPlayers), and is inLobbystatus. The player is assigned aPlayerentry, added to the SignalR grouplobbyCode, andPlayerJoined(GameStateDto) is broadcast to all participants. - Player Ready: Players invoke
GameHub.PlayerReady(gameId, playerId).GameHubchecksValidatePlayerAccessAsyncand broadcastsGameStateUpdated. - Game Start & Card Dealing: The host invokes
GameHub.StartGame(gameId).GameHubverifies host authorization viaValidateHostAccessAsync(gameId, authUserId).GameService.StartGameAsync()transitionsGameStatustoInProgressand createsGameRound1 (RoundStatus.Active).GameService.DealCardsAsync()fetches active phrases, randomly selects 5 phrases per player, createsPlayerCardentries, and saves them to PostgreSQL.- SignalR broadcasts
GameStartedto the group. - SignalR sends private
PlayerHandUpdatednotifications (PlayerHandDto) individually to each player'sConnectionId.
2. Phrase Slipping Workflow
During real-life conversation or chat, a player speaks or types one of their secret phrases and marks it as used in the app:
- Submission: Player A calls
GameHub.SubmitSlip(gameId, playerId, cardId). - Access Control:
GameHubexecutesValidatePlayerAccessAsync(playerId, userId)to verify that Player A owns the specifiedPlayeraccount. - Engine Execution:
GameService.SubmitSlipAsync()loads thePlayerCard, validates card ownership (card.PlayerId == playerId), and setscard.IsUsed = true. - Notification:
GameHubbroadcastsSlipSubmitted({ PlayerId, CardId, Success }) to the SignalR lobby group.
3. Slip Challenge & Resolution Workflow
If another player suspects that a submitted phrase or recent conversation statement was an invalid slip, they can challenge the slipper.
Step 1: Challenge Initiation
- Player B (Challenger) calls
GameHub.ChallengeSlip(gameId, challengingPlayerId, targetCardId). GameHubverifies Player B's identity (ValidatePlayerAccessAsync).GameService.CreateChallengeAsync()creates aSlipChallengeentity withChallengeStatus.Pending.GameHubbroadcastsSlipChallenged(SlipChallengeDto) to the lobby group.GameHubsends a targetedChallengeReceivedmessage directly to Player A'sConnectionId.
Step 2: Challenge Resolution
Player A (the accused) responds by admitting or denying the false slip:
- Player A calls
GameHub.ResolveChallenge(challengeId, approved). GameHubexecutesValidateChallengeTargetAccessAsync(challengeId, authUserId)to guarantee that only the accused player can resolve the challenge.GameService.ResolveChallengeAsync()executes penalty logic:approved = true(Justified Accusation / Legitimate Catch): The accused admits the phrase was a fake slip.SlipChallenge.Statusis set toApproved. The card remains with the accused player.approved = false(False Accusation / Wrong Penalty): The accused denies the charge (the slip was valid).SlipChallenge.Statusis set toRejected. As a penalty for making a false accusation, the phrase card is reassigned to the challenger:targetCard.PlayerId = challenge.ChallengingPlayerId. The challenger now holds >5 cards in their hand.
GameHubbroadcastsChallengeResolvedto the lobby group.
Real-time Sequence Diagram
sequenceDiagram
autonumber
actor Slipper as Player A (Accused)
actor Challenger as Player B (Challenger)
participant Hub as GameHub
participant Service as GameService
participant DB as SlipItInDbContext
Note over Slipper, Challenger: Active Gameplay
Slipper->>Hub: SubmitSlip(gameId, playerAId, cardId)
Hub->>Service: SubmitSlipAsync(gameId, playerAId, cardId)
Service->>DB: Set PlayerCard.IsUsed = true
Hub-->>Challenger: Broadcast "SlipSubmitted"
Note over Challenger: Suspects invalid phrase
Challenger->>Hub: ChallengeSlip(gameId, playerBId, targetCardId)
Hub->>Service: CreateChallengeAsync()
Service->>DB: Insert SlipChallenge (Status = Pending)
Hub-->>Challenger: Broadcast "SlipChallenged" (SlipChallengeDto)
Hub-->>Slipper: Unicast "ChallengeReceived" to ConnectionId
Note over Slipper: Accused resolves accusation
Slipper->>Hub: ResolveChallenge(challengeId, approved)
Hub->>Hub: ValidateChallengeTargetAccessAsync()
Hub->>Service: ResolveChallengeAsync(challengeId, approved)
alt approved == false (False Accusation)
Service->>DB: Update targetCard.PlayerId = PlayerBId (Penalty)
Service->>DB: Set Challenge.Status = Rejected
else approved == true (Justified Catch)
Service->>DB: Set Challenge.Status = Approved
end
Hub-->>Challenger: Broadcast "ChallengeResolved"
4. SignalR Hub Event Reference
Summary of server-to-client events emitted by GameHub.cs:
| Event Name | Scope | Payload | Trigger |
|---|---|---|---|
LobbyCreated |
Caller | { GameId, LobbyCode } |
Host calls CreateLobby() |
PlayerJoined |
Group | GameStateDto |
Player calls JoinLobby() |
GameStateUpdated |
Group | GameStateDto |
Player calls PlayerReady() |
GameStarted |
Group | { GameId } |
Host calls StartGame() |
PlayerHandUpdated |
Unicast | PlayerHandDto |
Hand dealt or updated |
SlipSubmitted |
Group | { PlayerId, CardId, Success } |
Player calls SubmitSlip() |
SlipChallenged |
Group | SlipChallengeDto |
Opponent calls ChallengeSlip() |
ChallengeReceived |
Unicast | SlipChallengeDto |
Direct alert to target player |
ChallengeResolved |
Group | SlipChallengeDto |
Target calls ResolveChallenge() |
Error |
Caller | { Message } |
Any authorization or engine exception |