--- type: Domain Model title: Game Domain & State Models description: Detailed domain model and state lifecycles for SlipItIn games, rounds, phrase decks, players, and challenges. tags: [domain, models, state-machine, entity-framework, privacy] --- # Game Domain & State Models This page describes the core domain entities, relational schema, state machines, and data transfer objects (DTOs) that form the foundation of the SlipItIn game engine. The domain model [is secured by data privacy models defined in](/openwiki/architecture/overview.md) the system architecture, [defines state lifecycles executed by](/openwiki/workflows/slip-and-challenge.md) real-time game workflows, and [maps domain classes in C# project files indexed in](/openwiki/source-map.md) the source map (`SlipItIn.Shared/Models/` and `SlipItIn.Shared/DTOs/`). --- ## 1. Entity Relationship Diagram (ERD) The database schema is managed via Entity Framework Core (`SlipItInDbContext`) targeting PostgreSQL. ```mermaid erDiagram User { int Id PK string Username string Email string PasswordHash bool IsActive } Game { int Id PK string LobbyCode int HostId FK GameStatus Status int MaxPlayers int RoundDurationSeconds } Player { int Id PK int UserId FK int GameId FK int Score bool IsReady string ConnectionId } Phrase { int Id PK string Text int CreatorId FK bool IsActive } GameRound { int Id PK int GameId FK int RoundNumber RoundStatus Status } PlayerCard { int Id PK int PlayerId FK int PhraseId FK int GameRoundId FK bool IsUsed } SlipChallenge { int Id PK int GameRoundId FK int ChallengingPlayerId FK int TargetPlayerId FK int TargetCardId FK ChallengeStatus Status } User ||--o{ Game : "hosts" User ||--o{ Player : "participates as" User ||--o{ Phrase : "creates" Game ||--o{ Player : "contains" Game ||--o{ GameRound : "has" Player ||--o{ PlayerCard : "holds" Phrase ||--o{ PlayerCard : "used in" GameRound ||--o{ PlayerCard : "active in" GameRound ||--o{ SlipChallenge : "contains" Player ||--o{ SlipChallenge : "challenges" Player ||--o{ SlipChallenge : "target of" PlayerCard ||--o{ SlipChallenge : "targeted by" ``` --- ## 2. Core Domain Entities (`SlipItIn.Shared/Models`) ### `User` Represents an authenticated account. * **Properties**: `Id`, `Username`, `Email`, `PasswordHash` (BCrypt), `CreatedAt`, `IsActive`. * **Relations**: Navigation properties to created `Game` instances, player entries (`Players`), and created phrases (`Phrases`). ### `Game` Represents a multiplayer game session / lobby. * **Properties**: `Id`, `LobbyCode` (6-char alphanumeric), `HostId`, `Status` (`GameStatus`), `CreatedAt`, `StartedAt`, `EndedAt`, `MaxPlayers` (default 8), `RoundDurationSeconds` (30-60s). * **Relations**: `Host` (`User`), `Players` (`ICollection`), `Rounds` (`ICollection`). ### `Player` Represents a user's participation inside a specific `Game`. * **Properties**: `Id`, `UserId`, `GameId`, `Score`, `SuccessfulSlips`, `FailedSlips`, `JoinedAt`, `IsReady`, `ConnectionId` (active SignalR connection ID). * **Relations**: `User`, `Game`, `Cards` (`ICollection`). ### `Phrase` Represents a secret phrase or sentence created for the game deck. * **Properties**: `Id`, `Text`, `CreatorId`, `CreatedAt`, `IsActive`. * **Relations**: `Creator` (`User`), `PlayerCards` (`ICollection`). ### `GameRound` Tracks a distinct round within a game. * **Properties**: `Id`, `GameId`, `RoundNumber`, `Status` (`RoundStatus`), `StartedAt`, `EndedAt`. * **Relations**: `Game`, `ActiveCards` (`ICollection`), `Challenges` (`ICollection`). ### `PlayerCard` Represents a specific phrase card dealt to a player for a round. * **Properties**: `Id`, `PlayerId`, `PhraseId`, `GameRoundId`, `IsUsed` (boolean flag set when player submits slip), `AssignedAt`. * **Relations**: `Player`, `Phrase`, `GameRound`. ### `SlipChallenge` Represents an accusation made by one player against another player's submitted slip. * **Properties**: `Id`, `GameRoundId`, `ChallengingPlayerId`, `TargetPlayerId`, `TargetCardId`, `Status` (`ChallengeStatus`), `CreatedAt`, `ResolvedAt`. * **Relations**: `GameRound`, `ChallengingPlayer`, `TargetPlayer`, `TargetCard`. --- ## 3. Enumerations & State Lifecycles ### Game Status (`GameStatus`) ```mermaid stateDiagram-v2 [*] --> Lobby: CreateGameAsync() Lobby --> InProgress: StartGameAsync() (Host only) InProgress --> Completed: All rounds finished Lobby --> Cancelled: Host cancels InProgress --> Cancelled: Session abort ``` * **`Lobby`**: Waiting for players to join and set ready status. * **`InProgress`**: Active gameplay with dealt cards and active rounds. * **`Completed`**: Game finished, final scores tallied. * **`Cancelled`**: Lobby or game terminated early. ### Round Status (`RoundStatus`) ```mermaid stateDiagram-v2 [*] --> Waiting: StartGame / New Round Waiting --> Active: DealCardsAsync() Active --> Resolving: Challenge submitted Resolving --> Active: Challenge resolved Active --> Completed: Timer expires / All phrases used ``` ### Challenge Status (`ChallengeStatus`) * **`Pending`**: Accusation registered, awaiting response from the accused player. * **`Approved`**: Accusation confirmed (the phrase was indeed an invalid slip). The card remains with the accused player. * **`Rejected`**: Accusation rejected (the slip was legitimate). As a penalty, the card is transferred to the accuser's hand (`PlayerCard.PlayerId = ChallengingPlayerId`). --- ## 4. Data Transfer Objects (DTOs) & Data Privacy To enforce security and data privacy ([Architecture Overview](/openwiki/architecture/overview.md)), the backend exposes decoupled DTOs in `SlipItIn.Shared/DTOs`: | DTO | Visibility | Purpose & Content | |---|---|---| | `AuthResponseDto` | Direct REST | JWT Access Token, Expiration, Username, Email. | | `GameStateDto` | Broadcast (Group) | Public lobby/game status: `GameId`, `LobbyCode`, `Status`, `CurrentRound`, `RoundTimeRemaining`, `Players` (`PlayerInfoDto` array containing `PlayerId`, `Username`, `Score`, `IsReady`, and `CardCount`). **No card text.** | | `PlayerHandDto` | Unicast (Client) | Private hand data sent strictly to the card owner: `PlayerId`, `Cards` (`PlayerCardDto` array containing `CardId`, `PhraseId`, `Text`, `IsUsed`). | | `SlipChallengeDto` | Unicast / Group | Challenge notification: `ChallengeId`, `ChallengingPlayerId`, `TargetPlayerId`, `TargetCardId`, `Status`, `CreatedAt`. |