Files
SlipItIn/openwiki/workflows/slip-and-challenge.md
Tim Krampitz 01046b01e4 Neue Skills, Referenzen & OpenWiki-Doku integriert
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.
2026-07-26 14:00:58 +02:00

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.
workflow
game-loop
signalr
slip-mechanic
real-time

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
  1. Lobby Creation: Host calls GameHub.CreateLobby(). GameService.CreateGameAsync() creates a Game record (Status = Lobby), generates a random 6-character LobbyCode, adds the host as the first Player, and registers the host's WebSocket ConnectionId. Caller receives LobbyCreated.
  2. Joining Lobby: Opponents invoke GameHub.JoinLobby(lobbyCode). GameService.JoinGameAsync() validates that the game exists, has space (Players.Count < MaxPlayers), and is in Lobby status. The player is assigned a Player entry, added to the SignalR group lobbyCode, and PlayerJoined (GameStateDto) is broadcast to all participants.
  3. Player Ready: Players invoke GameHub.PlayerReady(gameId, playerId). GameHub checks ValidatePlayerAccessAsync and broadcasts GameStateUpdated.
  4. Game Start & Card Dealing: The host invokes GameHub.StartGame(gameId). GameHub verifies host authorization via ValidateHostAccessAsync(gameId, authUserId).
    • GameService.StartGameAsync() transitions GameStatus to InProgress and creates GameRound 1 (RoundStatus.Active).
    • GameService.DealCardsAsync() fetches active phrases, randomly selects 5 phrases per player, creates PlayerCard entries, and saves them to PostgreSQL.
    • SignalR broadcasts GameStarted to the group.
    • SignalR sends private PlayerHandUpdated notifications (PlayerHandDto) individually to each player's ConnectionId.

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:

  1. Submission: Player A calls GameHub.SubmitSlip(gameId, playerId, cardId).
  2. Access Control: GameHub executes ValidatePlayerAccessAsync(playerId, userId) to verify that Player A owns the specified Player account.
  3. Engine Execution: GameService.SubmitSlipAsync() loads the PlayerCard, validates card ownership (card.PlayerId == playerId), and sets card.IsUsed = true.
  4. Notification: GameHub broadcasts SlipSubmitted ({ 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

  1. Player B (Challenger) calls GameHub.ChallengeSlip(gameId, challengingPlayerId, targetCardId).
  2. GameHub verifies Player B's identity (ValidatePlayerAccessAsync).
  3. GameService.CreateChallengeAsync() creates a SlipChallenge entity with ChallengeStatus.Pending.
  4. GameHub broadcasts SlipChallenged (SlipChallengeDto) to the lobby group.
  5. GameHub sends a targeted ChallengeReceived message directly to Player A's ConnectionId.

Step 2: Challenge Resolution

Player A (the accused) responds by admitting or denying the false slip:

  1. Player A calls GameHub.ResolveChallenge(challengeId, approved).
  2. GameHub executes ValidateChallengeTargetAccessAsync(challengeId, authUserId) to guarantee that only the accused player can resolve the challenge.
  3. GameService.ResolveChallengeAsync() executes penalty logic:
    • approved = true (Justified Accusation / Legitimate Catch): The accused admits the phrase was a fake slip. SlipChallenge.Status is set to Approved. The card remains with the accused player.
    • approved = false (False Accusation / Wrong Penalty): The accused denies the charge (the slip was valid). SlipChallenge.Status is set to Rejected. 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.
  4. GameHub broadcasts ChallengeResolved to 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