# MTG Online Multiplayer Game Server — Handoff Document

**Project**: MTG Online Web (Modern Web-based MTG Platform)  
**Previous Thread**: Card Backend — Phase 1 & 2 (Deck Building, Card Import, User Data)  
**New Thread**: Phase 3 — Multiplayer Game Server  
**Location**: `/home/wall-o/projects/mtgonline`  
**Date**: 2026-07-25

---

## Context: What Was Built (Card Backend)

The previous thread delivered a complete card management and deckbuilding backend:

### Completed Features
- **FastAPI application** with JWT authentication, dual PostgreSQL databases (`mtgonline` + `mtgdata`), Redis caching
- **29 REST endpoints** across 10 routers (auth, users, decks, rooms, games, admin, cards, interactions, refresh, user-data, card-import)
- **16 user-data tables** with Alembic migrations, CASCADE deletes, JSONB flexibility
- **Card import feature** with fuzzy matching for XLSX/CSV/JSON/ODS files
- **Deck CRUD** with DRAFT/FINAL status transitions, precedents, suggestions
- **MTGJSON data pipeline** downloading and upserting card data into `mtgdata` database
- **Frontend** (React/TypeScript) with deck builder UI, card import, authentication, admin dashboard

### Current Architecture
```
mtgonline/
├── backend/                    # FastAPI card backend (Phase 1 & 2 complete)
│   ├── app/
│   │   ├── core/              # Settings, database engines, Redis client
│   │   ├── models/            # SQLAlchemy ORM models (user_data, user_deck, card_import)
│   │   ├── routers/           # API route modules (10 routers)
│   │   ├── schemas/           # Pydantic schemas
│   │   ├── services/          # MTGJSON manager, card DB, deck manager, fuzzy matcher
│   │   └── main.py            # FastAPI app entry point
│   ├── alembic/               # Database migrations
│   └── Dockerfile
├── frontend/                   # React/TypeScript deck builder (Phase 3 complete)
├── C++/                        # Cockatrice architecture analysis (reference)
├── state.json                  # Current state tracking
└── ROADMAP.md                  # Full project roadmap
```

### Key Integration Points Available
- **Card lookup**: `GET /api/cards/{card_id}` — returns full card data for game display
- **Card search**: `GET /api/cards/search?q=...` — search cards during gameplay
- **Set lists**: `GET /api/sets/` — list available sets for game formatting
- **User decks**: `GET /api/users/{user_id}/decks` — retrieve FINAL decks for player selection
- **Card import status**: `GET /api/v1/card-import/status` — check if user has imported their collection
- **Database access**: Direct SQLAlchemy async engines for `mtgonline` (app data) and `mtgdata` (card data)

---

## Phase 3: Multiplayer Game Server — Requirements

### Objective

Build a real-time multiplayer game server that enables live MTG gameplay between multiple players via WebSocket connections. This is the core gameplay engine — the replacement for Cockatrice's `servatrice` component.

### Success Criteria

- [ ] Players can create/join game rooms and play MTG in real-time
- [ ] Game state syncs correctly across all connected players (< 50ms latency)
- [ ] All 11 MTG turn phases are enforced server-side
- [ ] Stack resolution works correctly (layers, priority, targeting)
- [ ] Deck validation ensures legality before gameplay
- [ ] Game history is recorded as a serialized event log (for replays)
- [ ] Admin commands work (kick, ban, game control)
- [ ] Spectator mode is supported
- [ ] WebSocket reconnection handles gracefully with state sync

---

## Architecture Blueprint (Derived from Cockatrice Analysis)

### Authority Model

```
┌─────────────────┐         WebSocket (JSON)             ┌─────────────────┐
│   CLIENT        │◄────────────────────────────────────►│   SERVER        │
│  (React/TS)     │                                      │  (FastAPI/Py)   │
│                 │                                      │                 │
│ • Game Scene    │   GameCommands (play, attack, etc.)  │ • PostgreSQL    │
│ • Hand View     │◄────────────────────────────────────►│ • Game State    │
│ • Chat Panel    │   GameEvents (state changes)         │ • Room/Player   │
│ • Deck Panel    │                                      │   Management    │
│ • Phase Toolbar │   Chat, Admin, Spectator             │ • Replay Log    │
└─────────────────┘                                      └─────────────────┘
```

**Key Principle**: Server is authoritative. Clients send commands, server validates and broadcasts events. No client-side state manipulation.

### Game Engine Architecture

| Cockatrice Component | Modern Web Equivalent | Role |
|---|---|---|
| `AbstractGame` | `Game` (server-side) | Core game instance holding state, players, event handler |
| `GameMetaInfo` | `GameMetadata` | gameId, maxPlayers, description, started, spectators |
| `GameState` | `GameBoardState` | currentPhase, activePlayer, hostId, gameTimer |
| `GameEventHandler` | `GameEventDispatcher` | Central dispatch — processes events, prepares commands |
| `PlayerManager` | `PlayerRegistry` | Coordinates all players in a game |
| `PlayerLogic` | `Player` | Per-player game logic |
| `PlayerActions` | `PlayerCommands` | Concrete commands: play, attack, tap, draw |
| `CardZone` | `Zone` (base class) | Abstract zone — Hand/Stack/Table/Graveyard/Exile/Library |
| `HandZone` | `Hand` | Player's hand (secret/hidden zone) |
| `StackZone` | `Stack` | Spells/abilities on the stack |
| `TableZone` | `Battlefield` | Permanents on the battlefield |
| `PileZone` | `Pile` (Graveyard, Exile, Library) | Discard/exile/draw piles |
| `Replay` | `GameReplay` | Serialized event stream for replay |
| `Phase` | `TurnPhase` | 11-phase MTG turn structure |

### Turn Phase System (11 Phases with Sub-Phases)

```
Untap → Upkeep → Draw → Main 1 → Combat → Main 2 → End → Cleanup
                                        │
                                        └── Sub-phases:
                                            Beginning of Combat
                                            Declare Attackers
                                            Declare Blockers
                                            Combat Damage
                                            End of Combat
```

### Command/Event Flow

```
User Action (React component)
    │
    ▼
GameCommand (JSON message)
    │
    ▼
GameEventDispatcher.process()
    │
    ▼
Player.handleCommand()
    │
    ▼
ZoneLogic (state mutation)
    │
    ▼
GameEvent (broadcast to all clients via WebSocket)
    │
    ▼
Client receives & updates UI via Zustand/XState
```

### Network Protocol Design

Cockatrice uses Protocol Buffers over TCP. Modern web equivalent:

| Cockatrice Proto Message | JSON WebSocket Message |
|---|---|
| `ServerInfo_Game` | `{ "type": "game_info", "game_id": 1, "max_players": 2, ... }` |
| `ServerInfo_Player` | `{ "type": "player_info", "player_id": 1, "name": "...", ... }` |
| `Command_PlayCard` | `{ "type": "cmd_play_card", "card_id": 42, "zone": "hand", ... }` |
| `Command_Attack` | `{ "type": "cmd_attack", "attacker_id": 7, "targets": [3, 5], ... }` |
| `Event_Join` | `{ "type": "event_join", "player_id": 2, "properties": {...} }` |
| `Event_Leave` | `{ "type": "event_leave", "player_id": 1, "reason": "..." }` |
| `Event_SetActivePlayer` | `{ "type": "event_active_player", "player_id": 1 }` |
| `Event_SetActivePhase` | `{ "type": "event_active_phase", "phase": 5 }` |
| `Event_GameSay` | `{ "type": "event_chat", "player_id": 1, "message": "..." }` |
| `GameReplay` | `{ "type": "replay", "events": [...] }` |

### Architecture Patterns to Reuse

| Pattern | Cockatrice Usage | Modern Equivalent |
|---|---|---|
| **Event Bus** | Qt signals/slots | WebSocket broadcast + event system |
| **Command Pattern** | `Command_PlayCard`, `Command_Attack` | JSON command messages, validated server-side |
| **Observer** | `GameEventHandler` emits signals | WebSocket events trigger UI updates |
| **Strategy** | `CardZoneLogic` subclasses | Zone classes with strategy pattern |
| **Facade** | `AbstractGame` | Single `Game` object wrapping all subsystems |
| **Memento** | `DeckListMemento` for undo | Immutable state snapshots for undo/redo |
| **Repository** | `ServatriceDatabaseInterface` | SQLAlchemy repositories for game state |

---

## Implementation Plan

### Phase 3.1: Game Server Foundation

#### Deliverables
1. **Game Server Module** — Separate FastAPI WebSocket endpoint for game rooms
2. **Game Room Management** — Room creation, player join/leave, spectator support
3. **Game State Management** — Server-authoritative game state with full phase tracking
4. **Player System** — Player registration, connection management, disconnection handling
5. **WebSocket Protocol** — JSON message protocol for commands and events
6. **Database Models** — Game rooms, player connections, game state persistence

#### Files to Create
```
backend/app/
├── models/
│   ├── game_room.py              # Game room model (room_id, game_type, host_id, status)
│   ├── game_player.py            # Player connection (player_id, room_id, connection_id, hand, life)
│   ├── game_state.py             # Game board state (phase, turn, cards, zones)
│   ├── game_event.py             # Game events log (for replay)
│   └── game_log.py               # Game history (serialized event log)
├── routers/
│   └── game_server.py            # WebSocket endpoint for game rooms
├── services/
│   ├── game_engine.py            # Core game engine (turn phases, combat, stack)
│   ├── game_state_manager.py     # Game state management and synchronization
│   ├── player_manager.py         # Player management (join, leave, disconnect)
│   ├── card_zone.py              # Card zone logic (hand, stack, battlefield, pile)
│   ├── game_rule_engine.py       # Game rule enforcement (mana, timing, targeting)
│   └── game_replay.py            # Game replay recording and playback
├── schemas/
│   └── game_schemas.py           # Pydantic schemas for game messages
└── ws/
    ├── connection.py             # WebSocket connection management
    └── message_handler.py        # Message parsing and dispatch
```

#### Detailed Implementation Steps

**Step 1: Game Room Model & Router**
- Create `GameRoom` model with room_id, game_type, host_id, status (WAITING/PLAYING/FINISHED)
- Create `GamePlayer` model with player_id, room_id, connection_id, hand (JSONB), life_total
- Create `GameServer` router with WebSocket endpoint `/ws/game/{room_id}`
- Implement room creation (host creates room), player join/leave, spectator join/leave
- Handle WebSocket disconnection gracefully (player_timeout for reconnect)

**Step 2: Game State Management**
- Create `GameBoardState` model tracking: current_phase, active_player, turn_number, host_id
- Track all zone contents: hands, stack, battlefield, graveyards, exiles, libraries
- Implement phase transitions (Untap → Upkeep → Draw → Main1 → Combat → Main2 → End → Cleanup)
- Handle sub-phases within Combat (Beginning, Declare Attackers, Declare Blockers, Combat Damage, End)

**Step 3: Card Zone Logic**
- Implement `CardZone` base class with common operations (add, remove, search, sort)
- Implement `HandZone` (secret zone, only visible to owner)
- Implement `StackZone` (priority-based, spell/ability resolution)
- Implement `BattlefieldZone` (permanent zone, battlefield effects)
- Implement `PileZone` (Graveyard, Exile, Library — shuffle, draw, discard)
- Implement zone-specific behaviors (hand: count/mulligan, stack: layer resolution)

**Step 4: Game Rule Engine**
- Implement mana payment tracking and validation
- Implement timing rules (sorcery speed, instant speed, flash)
- Implement targeting validation (legal targets, priority chain)
- Implement combat rules (attackers, blockers, damage assignment, trample, first strike)
- Implement stack resolution (last in, first out, layer system)
- Implement life total tracking and loss conditions (0 life, poison, concession)

**Step 5: Game Replay System**
- Serialize all game events as a JSONB log
- Support replay recording (on game start) and playback (on request)
- Implement deterministic replay (same commands → same state)
- Store replays in `game_logs` table with compressed JSONB

**Step 6: Admin Commands**
- Implement kick player command
- Implement ban player command (from mtgonline DB)
- Implement game pause/resume
- Implement spectator mode toggle
- Implement admin override for game state

### Phase 3.2: Integration with Card Backend

#### Deliverables
1. **Deck Validation Service** — Validate decks before game start
2. **Card Lookup Service** — Fetch card data for game display
3. **User Authentication** — JWT validation for game server
4. **Database Integration** — Access to `mtgdata` and `mtgonline` databases

#### Integration Points
- **Card Backend API** (`http://backend:8000`):
  - `GET /api/cards/{card_id}` — Get card details for game board display
  - `GET /api/cards/search?q=...` — Search cards during gameplay
  - `GET /api/sets/` — List available sets for game formatting
  - `GET /api/users/{user_id}/decks` — Get user's FINAL decks for selection
- **Direct PSQL Access** (via shared connection string):
  - `mtgdata` database — Read card data (cards, sets, etc.)
  - `mtgonline` database — Read user decks (for deck validation, game setup)

#### Deck Validation Flow
```
Player selects deck → Server fetches deck from mtgonline DB
    │
    ▼
Validate deck against rules:
    │
    ├── Check card count (60+ for Standard/Modern, 100+ for Commander)
    │   ├── Card validity (must exist in mtgdata)
    │   ├── Color identity (Commander format)
    │   └── Basic land count (max 4 of each non-basic)
    │
    ├── Check banned cards (format-specific ban list)
    │
    └── Return validation result (pass/fail with reasons)
```

### Phase 3.3: WebSocket Client Integration

#### Deliverables
1. **WebSocket Client** — React component for game client
2. **State Management** — Zustand store for game state
3. **Message Handlers** — Parse and handle game events
4. **Reconnection Logic** — Exponential backoff with state sync

#### Integration with Frontend
- **WebSocket Connection**: Connect to `/ws/game/{room_id}` on game start
- **State Store**: Use Zustand to manage game state, sync with server events
- **Message Handlers**: Handle join, leave, play_card, attack, etc.
- **Reconnection**: On disconnect, attempt reconnect with exponential backoff, sync state on reconnect

---

## Database Schema for Game Server

### Tables to Create

| Table | Purpose | Key Columns |
|-------|---------|-------------|
| `game_rooms` | Game room management | room_id (PK), game_type, host_id, status, created_at |
| `game_players` | Player connections | player_id (PK), room_id (FK), connection_id, hand (JSONB), life_total, is_spectator |
| `game_states` | Game board state | state_id (PK), room_id (FK), current_phase, turn_number, active_player, cards (JSONB), created_at |
| `game_events` | Event log for replay | event_id (PK), room_id (FK), event_type, event_data (JSONB), timestamp |
| `game_replays` | Recorded games | replay_id (PK), room_id (FK), events (JSONB), duration, started_at, finished_at |

### JSONB Structures

**Hand**: `{"cards": [{"card_id": 1, "name": "Lightning Bolt", "zone": "hand"}]}`  
**Stack**: `{"items": [{"card_id": 5, "name": "Counterspell", "controller": 1}]}`  
**Battlefield**: `{"cards": [{"card_id": 10, "name": "Craterhoof", "zone": "battlefield", "tapped": false}]}`  
**Graveyard**: `{"cards": [{"card_id": 1, "name": "Lightning Bolt", "zone": "graveyard"}]}`

---

## Game Engine Implementation Details

### Core Game Class

```python
class Game:
    """Core game instance holding state, players, event handler."""
    
    def __init__(self, room_id: str, game_type: str, host_id: int):
        self.room_id = room_id
        self.game_type = game_type  # Standard, Modern, Commander
        self.host_id = host_id
        self.players: Dict[int, Player] = {}
        self.state: GameBoardState = GameBoardState()
        self.event_dispatcher: GameEventDispatcher = GameEventDispatcher(self)
        self.replay: GameReplay = GameReplay()
    
    def add_player(self, player: Player) -> bool:
        """Add player to game. Returns True if successful."""
    
    def remove_player(self, player_id: int) -> bool:
        """Remove player from game. Broadcasts event."""
    
    def transition_phase(self) -> None:
        """Advance to next phase. Validates phase transitions."""
    
    def handle_command(self, command: GameCommand) -> List[GameEvent]:
        """Process player command. Returns events to broadcast."""
    
    def broadcast_event(self, event: GameEvent) -> None:
        """Broadcast event to all connected clients."""
```

### Player Class

```python
class Player:
    """Per-player game logic."""
    
    def __init__(self, player_id: int, name: str, deck: Deck):
        self.player_id = player_id
        self.name = name
        self.deck = deck
        self.hand: HandZone = HandZone()
        self.battlefield: BattlefieldZone = BattlefieldZone()
        self.graveyard: PileZone = PileZone()
        self.exile: PileZone = PileZone()
        self.library: LibraryZone = LibraryZone()
        self.life_total: int = 20
        self.poison_counters: int = 0
    
    def handle_command(self, command: GameCommand) -> List[GameEvent]:
        """Process command. Returns events to broadcast."""
    
    def play_card(self, card_id: int, zone: str) -> GameEvent:
        """Play card from hand to battlefield."""
    
    def attack(self, attacker_id: int, targets: List[int]) -> GameEvent:
        """Declare attackers and assign damage."""
    
    def tap_card(self, card_id: int) -> GameEvent:
        """Tap card for mana or attack."""
    
    def draw_card(self) -> GameEvent:
        """Draw card from library."""
```

### Zone Classes

```python
class CardZone:
    """Abstract zone base class."""
    
    def add_card(self, card: Card) -> None:
        """Add card to zone."""
    
    def remove_card(self, card_id: int) -> Card:
        """Remove card from zone."""
    
    def search(self, filter: SearchFilter) -> List[Card]:
        """Search zone with filter."""
    
    def shuffle(self) -> None:
        """Shuffle zone."""
    
    def sort(self) -> None:
        """Sort zone."""

class HandZone(CardZone):
    """Player's hand (secret zone)."""
    # Only visible to owner
    
class StackZone(CardZone):
    """Spells/abilities on the stack."""
    # Priority-based resolution

class BattlefieldZone(CardZone):
    """Permanent zone."""
    # Has tap/untap, counters, attachments

class PileZone(CardZone):
    """Graveyard, exile, library."""
    # Shuffleable (library) or non-shuffleable (graveyard)
```

---

## Testing Strategy

### Unit Tests

- **Game State Transitions**: Test all 11 phases and sub-phases
- **Combat Rules**: Test attack, block, damage assignment, trample, first strike
- **Stack Resolution**: Test priority, layer system, LIFO resolution
- **Mana Payment**: Test mana pool, timing, costs
- **Zone Operations**: Test add/remove/search/shuffle/sort for each zone
- **Deck Validation**: Test format rules (Standard, Modern, Commander)
- **Replay Determinism**: Test same commands → same state

### Integration Tests

- **WebSocket Connection**: Test connect/disconnect/join/leave
- **Game Room Management**: Test room creation, player count, spectator
- **Real-time Sync**: Test state sync across multiple clients
- **Reconnection**: Test reconnect with state sync
- **Admin Commands**: Test kick, ban, pause, resume

### Load Tests

- **Concurrent Players**: Test 2-8 players per game
- **Multiple Games**: Test 100+ concurrent games
- **Message Throughput**: Test 1000+ messages/sec per game
- **Latency**: Test < 50ms message latency

---

## Acceptance Criteria

### Functional Requirements

- [ ] Players can create game rooms with custom settings
- [ ] Players can join existing game rooms
- [ ] Game starts with all players ready
- [ ] 11-phase turn structure works correctly
- [ ] Combat rules enforce attack/block/damage correctly
- [ ] Stack resolves spells/abilities in correct order
- [ ] Mana payment validates costs and timing
- [ ] Deck validation ensures format legality
- [ ] Game history recorded as serialized event log
- [ ] Admin can kick/ban players
- [ ] Spectators can watch games
- [ ] WebSocket disconnect triggers graceful player timeout

### Performance Requirements

- [ ] WebSocket latency < 50ms for game state updates
- [ ] Support 1000+ concurrent users across multiple games
- [ ] Game state syncs within 100ms across all connected players
- [ ] Replay recording doesn't impact gameplay performance
- [ ] Database queries for card lookup < 10ms

### Security Requirements

- [ ] JWT authentication for all WebSocket connections
- [ ] Input validation for all game commands
- [ ] Rate limiting for message spam protection
- [ ] Admin-only commands require admin role
- [ ] Game state never exposed to spectators (unless enabled)

---

## Files to Create/Modify

### New Files
```
backend/app/
├── models/
│   ├── game_room.py
│   ├── game_player.py
│   ├── game_state.py
│   ├── game_event.py
│   └── game_log.py
├── routers/
│   └── game_server.py
├── services/
│   ├── game_engine.py
│   ├── game_state_manager.py
│   ├── player_manager.py
│   ├── card_zone.py
│   ├── game_rule_engine.py
│   └── game_replay.py
├── schemas/
│   └── game_schemas.py
└── ws/
    ├── connection.py
    └── message_handler.py
```

### Modified Files
```
backend/app/
├── main.py                    # Mount game server router
├── core/
│   ├── database.py            # Add game database engine if needed
│   └── settings.py            # Add game server settings
├── alembic/
│   └── versions/
│       └── 005_game_server_tables.py
```

### Dependencies to Add
```
# backend/requirements.txt
websockets>=12.0
pydantic>=2.9.2
```

---

## Integration with Card Backend

### API Endpoints Used by Game Server

| Endpoint | Purpose | Method |
|----------|---------|--------|
| `/api/cards/{card_id}` | Get card details | GET |
| `/api/cards/search?q=...` | Search cards | GET |
| `/api/sets/` | List sets | GET |
| `/api/users/{user_id}/decks` | Get user decks | GET |
| `/api/v1/card-import/status` | Check import status | GET |

### Database Access

**mtgdata database** (read-only):
- `mtg_cards` — Card data for game display
- `mtg_sets` — Set data for format rules
- `mtg_card_types` — Card type definitions

**mtgonline database** (read-write):
- `users` — User authentication
- `decks` — User decks for validation
- `ban` — Ban list for admin commands
- `game_logs` — Game history storage

---

## Cockatrice Analysis Reference

The complete architecture analysis is at `/home/wall-o/projects/mtgonline/C++/ARCHITECTURE_ANALYSIS.md`.

Key takeaways:
- **Server authoritative**: Never trust client state
- **Deterministic replay**: Same commands → same state
- **Zone abstraction**: Each zone independently implementable
- **Phase system**: 11-phase MTG turn with sub-phases
- **Command/Event separation**: What player wants vs. what happens

The modern web adaptation replaces:
- TCP with WebSocket (JSON)
- Protocol Buffers with JSON messages
- Qt Widgets with React/Next.js
- C++/MySQL with Python/FastAPI + PostgreSQL
- Monolithic handler with modular service architecture

---

## Next Steps

1. **Start with Phase 3.1**: Game server foundation (models, router, WebSocket)
2. **Implement core game engine**: Turn phases, combat, stack resolution
3. **Add zone logic**: Hand, stack, battlefield, pile zones
4. **Integrate with card backend**: Deck validation, card lookup
5. **Add replay system**: Serialize events for replay
6. **Test thoroughly**: Unit, integration, load tests
7. **Update documentation**: API docs, architecture docs
8. **Push to Gitea**: Commit and push all changes

---

## Quick Reference

### Game Room WebSocket Endpoint
```
WS /ws/game/{room_id}
```

### Command Messages
```json
{
  "type": "cmd_play_card",
  "card_id": 42,
  "zone": "hand",
  "targets": [3, 5],
  "mana_cost": [1, "R", "G"]
}
```

### Event Messages
```json
{
  "type": "event_play_card",
  "card_id": 42,
  "controller": 1,
  "zone": "battlefield",
  "timestamp": 1784948189
}
```

### State Sync Message
```json
{
  "type": "state_sync",
  "game_state": {
    "current_phase": "main1",
    "turn_number": 5,
    "active_player": 1,
    "hands": {"1": [...], "2": [...]},
    "battlefield": [...],
    "stack": [...],
    "graveyards": {"1": [...], "2": [...]}
  }
}
```

---

## Environment Variables

Add to `.env` or docker-compose:

```bash
# Game Server
GAME_SERVER_HOST=0.0.0.0
GAME_SERVER_PORT=8765
GAME_WS_PATH=/ws/game
GAME_TOKEN_EXPIRY=3600
GAME_PLAYER_TIMEOUT=30
GAME_MAX_PLAYERS=8
```

---

## Docker Configuration

Add to `docker-compose.dev.yml`:

```yaml
  game-server:
    build:
      context: ./backend
      dockerfile: Dockerfile
    ports:
      - "8765:8765"
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - MTG_DATABASE_URL=${MTG_DATABASE_URL}
      - REDIS_URL=${REDIS_URL}
      - GAME_SERVER_PORT=8765
      - GAME_WS_PATH=/ws/game
    depends_on:
      - postgres
      - mtgdata
      - redis
    networks:
      - mtgonline
```

---

**Last Updated**: 2026-07-25  
**Status**: Handoff complete. Ready for Phase 3 implementation.  
**Next Action**: Begin Phase 3.1 — Game server foundation (models, router, WebSocket).
