# Paper Dynasty Real-Time Game Engine - Product Requirements Document

## Executive Summary

### Project Overview
The Paper Dynasty Real-Time Game Engine is a web-based multiplayer gaming platform that replaces the legacy Google Sheets macro system for playing Paper Dynasty baseball card games. The system consists of a shared game backend with WebSocket support and two separate Vue/Nuxt frontends (one per league) that enable real-time, turn-based baseball simulation games.

### Critical Business Driver
The legacy Google Sheets system is being deprecated, making this replacement system mission-critical for continued game operations.

### Objectives
- **Primary Goal**: Replace deprecated Google Sheets system with modern real-time web application
- **User Experience**: Provide fast, intuitive turn-based baseball gameplay on mobile and desktop
- **Architecture**: Build league-agnostic game engine supporting two leagues with minor rule variations
- **Flexibility**: Support synchronous multiplayer, asynchronous play, and single-player vs AI modes
- **Spectator Support**: Enable real-time game viewing for non-participants

### Success Metrics
- **Migration**: 100% of active games migrated from Google Sheets within 2 weeks of launch
- **Performance**: Game actions complete within 500ms average latency
- **Reliability**: 99.5% uptime with automatic game state recovery
- **User Adoption**: 90% of active players using web app within 1 month
- **Mobile Usage**: 60%+ of games played on mobile devices

---

## User Personas

### Primary Persona: The Competitive GM
**Demographics**: 25-35 year old male, baseball strategist, plays 5-10 games per week  
**Goals**: Win games through optimal strategic decisions and roster management  
**Pain Points**: Google Sheets is slow, crashes frequently, poor mobile experience  
**Usage Pattern**: 30-60 minute game sessions, primarily evening hours, often on mobile

### Secondary Persona: The Casual Manager
**Demographics**: 20-40 year old male, enjoys casual competition  
**Goals**: Play occasional games, experiment with different strategies  
**Pain Points**: Google Sheets learning curve, difficulty playing asynchronously  
**Usage Pattern**: 1-2 games per week, often plays turns asynchronously over multiple days

### Tertiary Persona: The Spectator
**Demographics**: League participant or baseball fan  
**Goals**: Watch competitive games, learn strategies from top players  
**Pain Points**: No current way to spectate games in progress  
**Usage Pattern**: Drops in to watch key matchups, checks multiple games

---

## System Architecture

### High-Level Architecture

```
┌─────────────────┐         ┌──────────────────┐
│  League 1 Vue   │────────▶│  League 1 REST   │
│    Frontend     │         │      API         │
│   (Nuxt 3)      │         │  (existing DB)   │
└────────┬────────┘         └──────────────────┘
         │
         │ WebSocket (Socket.io)
         │
         ▼
┌─────────────────────────────────────┐
│      Game Backend (FastAPI)         │
│                                     │
│  ┌──────────────────────────────┐  │
│  │   Game Engine (in-memory)    │  │
│  │  - Active game state         │  │
│  │  - Current play context      │  │
│  │  - Pending decisions         │  │
│  └──────────────────────────────┘  │
│                                     │
│  ┌──────────────────────────────┐  │
│  │   PostgreSQL (persistence)   │  │
│  │  - Completed plays           │  │
│  │  - Game metadata             │  │
│  │  - Lineups                   │  │
│  └──────────────────────────────┘  │
│                                     │
│  ┌──────────────────────────────┐  │
│  │   League Config System       │  │
│  │  - Rule variations           │  │
│  │  - d20 result charts         │  │
│  └──────────────────────────────┘  │
│                                     │
│  ┌──────────────────────────────┐  │
│  │   API Client Layer           │  │
│  │  - Fetch team/player data    │  │
│  │  - Submit final results      │  │
│  └──────────────────────────────┘  │
└─────────────────────────────────────┘
         │
         │ WebSocket (Socket.io)
         │
         ▼
┌─────────────────┐         ┌──────────────────┐
│  League 2 Vue   │────────▶│  League 2 REST   │
│    Frontend     │         │      API         │
│   (Nuxt 3)      │         └──────────────────┘
└─────────────────┘
```

### Data Flow

**Game Initialization:**
1. Frontend requests game start with team IDs
2. Backend fetches team/roster data from league REST API
3. Backend loads appropriate league config
4. Backend creates in-memory game session
5. Backend stores initial game metadata in PostgreSQL
6. WebSocket connections established for all participants

**During Gameplay:**
1. Player makes decision via frontend
2. WebSocket sends action to backend
3. Backend validates action against current state (in-memory)
4. Backend processes action, generates dice rolls if needed
5. Backend resolves play outcome using league config
6. Backend updates in-memory state
7. Backend asynchronously writes completed play to PostgreSQL
8. Backend broadcasts state update to all connected clients
9. Frontends update UI in real-time

**Game Recovery:**
1. Player reconnects after disconnect
2. Backend loads all plays from PostgreSQL
3. Backend rebuilds in-memory state by replaying plays
4. Backend sends current state to reconnected client
5. Game continues seamlessly

---

## Functional Requirements

### Authentication & User Management

#### Discord OAuth Integration
- **Requirement**: Users must authenticate via Discord OAuth
- **User Story**: As a Paper Dynasty player, I want to log in using my Discord account so I can access my teams and start games
- **Acceptance Criteria**:
  - Discord OAuth 2.0 implementation
  - User identification via Discord snowflake ID (gmid)
  - Session management with secure tokens
  - Automatic team data retrieval post-authentication
  - Support for users managing multiple teams

### Game Creation & Lobby

#### Create New Game
- **Requirement**: Players can create new games with flexible configuration
- **User Story**: As a GM, I want to create a new game against an opponent so we can compete
- **Acceptance Criteria**:
  - Select team from owned teams
  - Choose opponent team (or AI)
  - Select game mode (live multiplayer, async, vs AI)
  - Set game visibility (public spectators allowed, private)
  - Generate unique game link for sharing
  - Game appears in active games list

#### Game Lobby/Pre-Game
- **Requirement**: Pre-game interface for lineup confirmation and game start
- **User Story**: As a GM, I want to review my lineup before the game starts so I can make any necessary adjustments
- **Acceptance Criteria**:
  - Display both team lineups (batting order, starting pitcher)
  - Ready/not ready status for each GM
  - Chat or communication method between GMs
  - Game starts when both GMs ready (or single player starts immediately)
  - Late-join capability for async games

### Real-Time Gameplay

#### Game State Display
- **Requirement**: Clear, real-time display of complete game state
- **User Story**: As a player, I want to see all relevant game information at a glance so I can make informed decisions
- **Acceptance Criteria**:
  - Current score by inning
  - Inning, outs, balls, strikes
  - Runners on base (visual diamond)
  - Current batter and pitcher with stats
  - Recent play history (last 3-5 plays)
  - Defensive positioning
  - Bullpen status
  - Bench availability
  - Real-time updates via WebSocket

#### Turn-Based Decision Flow
- **Requirement**: Structured decision-making workflow for offensive and defensive actions
- **User Story**: As a GM, I want clear prompts for decisions I need to make so the game flows smoothly
- **Acceptance Criteria**:
  - **Phase 1.0 - Set Defense**: Defensive positioning options
  - **Phase 1.X - Baserunner Decisions** (if applicable): Stolen base attempts per runner
  - **Phase 2.0 - Offensive Approach**: Swing away vs bunt options
  - Clear indication of whose turn it is
  - Decision timeout with default actions (for async play)
  - Visual feedback when waiting on opponent
  - Undo last decision (before play resolution)

#### Dice Rolling & Play Resolution
- **Requirement**: Fair, transparent dice rolling with immediate result display
- **User Story**: As a player, I want to see dice rolls happen in real-time so I trust the outcome
- **Acceptance Criteria**:
  - Backend generates cryptographically secure random rolls
  - Roll animation visible to all participants simultaneously
  - Roll result stored with play data
  - Play outcome determined by league-specific d20 charts
  - Play result selection by offensive player (when applicable)
  - Automatic game state advancement
  - Play-by-play commentary generation

#### Strategic Decisions
- **Requirement**: Support for all in-game strategic options
- **User Story**: As a GM, I want access to all strategic tools during the game so I can optimize my chances of winning
- **Acceptance Criteria**:
  - **Defensive positioning**: Standard, infield in, outfield shifted, etc.
  - **Stolen base attempts**: Per runner decision when applicable
  - **Offensive approach**: Swing away, bunt, hit-and-run
  - **Substitutions**: Pinch hitters, pinch runners, defensive replacements
  - **Pitching changes**: Relief pitcher selection from bullpen
  - Decision validation (prevent illegal moves)
  - Mobile-friendly decision interfaces

#### Game State Persistence
- **Requirement**: Games must persist indefinitely and support resumption
- **User Story**: As a player, I want to stop playing and resume later without losing progress
- **Acceptance Criteria**:
  - All completed plays written to PostgreSQL
  - Games persist when all players disconnect
  - Idle games consume minimal resources
  - Fast game state reconstruction on reconnection
  - Support for asynchronous play (players alternate turns over days)
  - No time limit on game completion

### Spectator Mode

#### Live Game Viewing
- **Requirement**: Non-participants can watch games in real-time
- **User Story**: As a league member, I want to spectate important games so I can learn strategies and enjoy the competition
- **Acceptance Criteria**:
  - Read-only game view with all state information
  - Real-time updates via WebSocket
  - Spectator count visible to players (optional)
  - Spectator chat/commentary (optional, post-MVP)
  - No impact on game performance
  - Mobile-friendly spectator interface

### Game Modes

#### Live Multiplayer
- **Requirement**: Both players online simultaneously, real-time gameplay
- **User Story**: As a GM, I want to play a full game in one sitting with immediate action
- **Acceptance Criteria**:
  - Both players connected and actively making decisions
  - Minimal latency between actions
  - Automatic forfeit if player inactive for extended period (configurable)
  - Quick reconnection if brief disconnect

#### Asynchronous Play
- **Requirement**: Players can make decisions at different times
- **User Story**: As a player with limited availability, I want to play games over multiple days by taking turns when convenient
- **Acceptance Criteria**:
  - Email/Discord notification when it's player's turn
  - Games can take days or weeks to complete
  - Clear indication of whose turn it is
  - Turn history visible to both players
  - No penalty for slow play

#### Single-Player vs AI
- **Requirement**: Play against existing AI opponent logic
- **User Story**: As a player, I want to practice against AI so I can test strategies
- **Acceptance Criteria**:
  - AI opponent logic integrated from existing system
  - AI makes decisions automatically (no delay)
  - Same game interface as multiplayer
  - AI difficulty level selection (if applicable)
  - Full game state tracking and stats recording

### Game History & Stats

#### Completed Games View
- **Requirement**: Access to all completed games and their results
- **User Story**: As a player, I want to review past games so I can analyze my performance
- **Acceptance Criteria**:
  - List of all completed games (personal and league-wide)
  - Filter by team, opponent, date range
  - Basic game summary (final score, winner, key stats)
  - Link to detailed play-by-play

#### Play-by-Play History
- **Requirement**: Complete record of every action in a game
- **User Story**: As a GM, I want to review every play from a game so I can learn from my decisions
- **Acceptance Criteria**:
  - Chronological list of all plays
  - Play details: batter, pitcher, count, runners, outcome, score change
  - Strategic decisions recorded
  - Dice rolls recorded
  - Export capability for external analysis
  - Data submitted to league REST API for stat compilation

---

## Technical Requirements

### Frontend Stack (Per League)

#### Technology Choices
- **Framework**: Vue 3 with Composition API
- **Meta Framework**: Nuxt 3 for SSR/SPA capabilities
- **Language**: TypeScript for type safety
- **UI Framework**: Tailwind CSS for responsive design
- **State Management**: Pinia for application state
- **WebSocket Client**: Socket.io-client for real-time communication
- **HTTP Client**: Axios for REST API calls
- **Authentication**: @nuxtjs/auth-next for Discord OAuth

#### Shared Component Library
- **Requirement**: Maximize code reuse between league frontends
- **Components to Share**:
  - Game board/field visualization
  - Play-by-play feed
  - Dice roll animations
  - Player card displays
  - Decision input forms
  - WebSocket connection manager
- **League-Specific**:
  - Branding/theming
  - Rule-specific UI elements
  - API endpoint configuration

### Backend Stack

#### Technology Choices
- **Framework**: FastAPI (Python 3.11+)
- **WebSocket**: Socket.io with Python adapter
- **Database**: PostgreSQL 14+ for game persistence
- **ORM**: SQLAlchemy 2.0 for database operations
- **Type Safety**: Pydantic models for data validation
- **Async**: asyncio and async/await patterns throughout
- **Testing**: pytest with async support

#### Game Backend Structure
```
game-backend/
├── app/
│   ├── main.py                    # FastAPI app initialization
│   ├── core/
│   │   ├── game_engine.py         # Core simulation logic
│   │   ├── dice.py                # Secure random roll generation
│   │   ├── state_manager.py      # In-memory game state
│   │   └── play_resolver.py      # Play outcome resolution
│   ├── config/
│   │   ├── base_config.py         # Shared configuration
│   │   ├── league_configs.py     # League-specific rules
│   │   └── result_charts.py      # d20 outcome tables per league
│   ├── data/
│   │   ├── api_client.py          # REST API wrapper
│   │   └── cache.py               # Optional caching layer
│   ├── websocket/
│   │   ├── connection_manager.py  # WebSocket lifecycle
│   │   ├── events.py              # Game event handlers
│   │   └── handlers.py            # Action handlers
│   ├── models/
│   │   ├── game_models.py         # Pydantic models
│   │   ├── db_models.py           # SQLAlchemy models
│   │   └── player_models.py       # Polymorphic player models
│   ├── database/
│   │   ├── session.py             # DB connection management
│   │   └── operations.py          # Async DB operations
│   └── api/
│       └── routes.py              # REST endpoints for game creation
├── tests/
│   ├── unit/
│   ├── integration/
│   └── e2e/
├── requirements.txt
└── docker-compose.yml             # Local development setup
```

#### Polymorphic Player Architecture

The game backend uses a polymorphic player model to handle league-specific differences in player data structure while maintaining type safety and clean separation of concerns.

**Player Model Hierarchy:**

```python
from abc import ABC, abstractmethod
from typing import Union, Optional
from pydantic import BaseModel

class BasePlayer(BaseModel, ABC):
    """Abstract base class for all player types"""
    id: int
    name: str
    
    @abstractmethod
    def get_image_url(self) -> str:
        """Returns the URL for the player's card image"""
        pass
    
    @abstractmethod
    def get_display_data(self) -> dict:
        """Returns data needed for UI display"""
        pass
    
    class Config:
        """Pydantic configuration"""
        from_attributes = True

class SbaPlayer(BasePlayer):
    """Simple player model for SBA League
    
    SBA League players have minimal data requirements:
    - Basic identification (id, name, image)
    - Optional metadata (team, manager) not used in gameplay
    """
    image: str
    team: Optional[str] = None
    manager: Optional[str] = None
    
    def get_image_url(self) -> str:
        return self.image
    
    def get_display_data(self) -> dict:
        return {
            "id": self.id,
            "name": self.name,
            "image": self.image,
            "team": self.team,
            "manager": self.manager
        }

class PdPlayer(BasePlayer):
    """Detailed player model for PD League with scouting data
    
    PD League players include comprehensive scouting information:
    - Card image for display
    - Nested scouting data with detailed statistics
    - Ratings and probability calculations
    - Additional analytical data for player evaluation
    """
    image: str
    scouting_data: dict  # Nested scouting information
    ratings: dict  # Player ratings across categories
    probabilities: dict  # Outcome probabilities
    
    def get_image_url(self) -> str:
        return self.image
    
    def get_display_data(self) -> dict:
        return {
            "id": self.id,
            "name": self.name,
            "image": self.image,
            "scouting_data": self.scouting_data,
            "ratings": self.ratings,
            "probabilities": self.probabilities
        }

class Lineup(BaseModel):
    """Lineup entry representing a card in a game lineup
    
    Uses Union type for player to support both league types while
    maintaining type safety. The factory method ensures the correct
    player type is instantiated based on league configuration.
    """
    id: int
    game_id: str
    card_id: int
    position: str
    batting_order: Optional[int] = None
    is_starter: bool = True
    is_active: bool = True
    
    # Union type allows either player type with full type safety
    player: Union[SbaPlayer, PdPlayer]
    
    @classmethod
    def from_api_data(cls, game_config, api_data: dict):
        """Factory method that creates lineup with correct player type
        
        Args:
            game_config: League configuration object
            api_data: Raw lineup data from league REST API
            
        Returns:
            Lineup instance with properly typed player
            
        Raises:
            ValueError: If league_id is not recognized
        """
        player_data = api_data.pop('player')
        
        if game_config.league_id == "sba":
            player = SbaPlayer(**player_data)
        elif game_config.league_id == "pd":
            player = PdPlayer(**player_data)
        else:
            raise ValueError(f"Unknown league: {game_config.league_id}")
        
        return cls(player=player, **api_data)
```

**Usage in Game Engine:**

```python
class GameEngine:
    """Core game simulation engine with league-agnostic player handling"""
    
    def __init__(self, game_id: str, config: LeagueConfig):
        self.config = config
        self.lineups = self.load_lineups(game_id)
    
    def load_lineups(self, game_id: str) -> List[Lineup]:
        """Load and instantiate lineups with correct player types"""
        api_data = self.api_client.get_lineups(game_id, self.config)
        return [
            Lineup.from_api_data(self.config, lineup_data)
            for lineup_data in api_data
        ]
    
    def get_batter_display_data(self, lineup: Lineup) -> dict:
        """Get display data for current batter
        
        This method works for both leagues - the player object
        handles league-specific data formatting internally.
        """
        player = lineup.player
        
        # Common data available for all player types
        display_data = {
            "name": player.name,
            "image": player.get_image_url(),
            "position": lineup.position
        }
        
        # Type guard for league-specific data
        if isinstance(player, PdPlayer):
            # IDE autocomplete works here - knows player has scouting_data
            display_data["scouting"] = player.scouting_data
            display_data["ratings"] = player.ratings
        
        return display_data
```

**Benefits of Polymorphic Architecture:**

1. **Type Safety**: IDE provides accurate autocomplete and type checking for each player type
2. **Separation of Concerns**: League-specific logic contained within player classes
3. **Maintainability**: Easy to add new player types or modify existing ones
4. **Testability**: Can mock and test each player type independently
5. **Validation**: Pydantic validates structure of each player type automatically
6. **Explicit Design**: Factory method makes player type instantiation clear and predictable

### Database Schema

#### Games Table
```sql
CREATE TABLE games (
    id UUID PRIMARY KEY,
    league_id VARCHAR(50) NOT NULL,
    home_team_id INTEGER NOT NULL,
    away_team_id INTEGER NOT NULL,
    status VARCHAR(20) NOT NULL, -- 'pending', 'active', 'completed', 'abandoned'
    game_mode VARCHAR(20) NOT NULL, -- 'live', 'async', 'vs_ai'
    visibility VARCHAR(20) NOT NULL, -- 'public', 'private'
    current_inning INTEGER,
    current_half VARCHAR(10), -- 'top', 'bottom'
    home_score INTEGER DEFAULT 0,
    away_score INTEGER DEFAULT 0,
    created_at TIMESTAMP DEFAULT NOW(),
    started_at TIMESTAMP,
    completed_at TIMESTAMP,
    winner_team_id INTEGER,
    metadata JSONB -- flexible storage for league-specific data
);
```

#### Plays Table
```sql
CREATE TABLE plays (
    id SERIAL PRIMARY KEY,
    game_id UUID NOT NULL REFERENCES games(id),
    play_number INTEGER NOT NULL,
    inning INTEGER NOT NULL,
    half VARCHAR(10) NOT NULL,
    outs_before INTEGER NOT NULL,
    outs_recorded INTEGER NOT NULL,
    batter_id INTEGER NOT NULL,
    pitcher_id INTEGER NOT NULL,
    runners_before JSONB, -- {first: card_id, second: card_id, third: card_id}
    runners_after JSONB,
    balls INTEGER,
    strikes INTEGER,
    defensive_positioning VARCHAR(50),
    offensive_approach VARCHAR(50),
    dice_roll INTEGER,
    hit_type VARCHAR(50), -- 'single', 'double', 'out', etc.
    result_description TEXT,
    runs_scored INTEGER DEFAULT 0,
    created_at TIMESTAMP DEFAULT NOW(),
    metadata JSONB -- league-specific play data
);
```

#### Lineups Table
```sql
CREATE TABLE lineups (
    id SERIAL PRIMARY KEY,
    game_id UUID NOT NULL REFERENCES games(id),
    team_id INTEGER NOT NULL,
    card_id INTEGER NOT NULL,
    position VARCHAR(10) NOT NULL, -- 'P', 'C', '1B', etc.
    batting_order INTEGER,
    is_starter BOOLEAN DEFAULT true,
    is_active BOOLEAN DEFAULT true, -- false when substituted out
    entered_inning INTEGER DEFAULT 1,
    metadata JSONB
);
```

#### Game Sessions Table (In-Memory State Tracking)
```sql
CREATE TABLE game_sessions (
    game_id UUID PRIMARY KEY REFERENCES games(id),
    connected_users JSONB, -- {user_id: {role: 'home_gm', last_seen: timestamp}}
    last_action_at TIMESTAMP DEFAULT NOW(),
    state_snapshot JSONB -- full state snapshot for recovery
);
```

### Real-Time Communication

#### WebSocket Events (Server → Client)

**Connection Events:**
- `connected`: Confirmation of successful connection
- `game_joined`: Successfully joined game as player/spectator
- `user_connected`: Another user joined the game
- `user_disconnected`: Another user left the game

**Game State Events:**
- `game_state_update`: Complete game state (on join or major changes)
- `play_completed`: Play outcome and updated state
- `dice_rolled`: Dice roll result with animation trigger
- `decision_required`: Prompt for player action
- `decision_timeout_warning`: Countdown before auto-decision
- `inning_change`: New inning started
- `game_ended`: Game completion with final results

**Error Events:**
- `invalid_action`: Action rejected with reason
- `connection_error`: Connection issue details
- `game_error`: Game logic error

#### WebSocket Events (Client → Server)

**Connection Management:**
- `join_game`: Join as player or spectator
- `leave_game`: Disconnect from game
- `heartbeat`: Keep-alive ping

**Game Actions:**
- `set_defense`: Submit defensive positioning
- `set_stolen_base`: Submit stolen base attempt
- `set_offensive_approach`: Submit swing/bunt decision
- `select_play_result`: Choose outcome when applicable
- `substitute_player`: Make substitution
- `change_pitcher`: Bring in relief pitcher
- `ready_to_start`: Indicate readiness in pre-game lobby

### Performance Requirements

#### Latency Targets
- **Action Response**: < 500ms from user action to state update
- **WebSocket Message Delivery**: < 200ms
- **Database Write**: < 100ms (async, non-blocking)
- **Game State Recovery**: < 2 seconds
- **Page Load Time**: < 3 seconds on 3G mobile

#### Scalability Requirements
- **Concurrent Games**: Support 10+ simultaneous games
- **Concurrent Users**: 50+ connected users across all games
- **Database**: Handle 100,000+ play records
- **WebSocket Connections**: 100+ persistent connections
- **Memory Usage**: < 1GB for game backend with 10 active games

### Security Requirements

#### Authentication & Authorization
- **Discord OAuth**: Secure token exchange and validation
- **Session Management**: JWT tokens with appropriate expiration
- **WebSocket Auth**: Token validation on connection
- **Action Authorization**: Verify user can perform actions (is GM of team)
- **Spectator Restrictions**: Enforce read-only access

#### Data Security
- **HTTPS/WSS**: All communications encrypted
- **Input Validation**: Pydantic models validate all inputs
- **SQL Injection Prevention**: ORM with parameterized queries
- **Rate Limiting**: Prevent abuse of API endpoints
- **Game State Integrity**: Cryptographic hashing of critical state (optional)

#### Fair Play
- **Dice Roll Security**: Cryptographically secure random generation
- **Action Validation**: Server-side enforcement of all rules
- **No Client Trust**: All game logic executes server-side
- **Audit Trail**: Complete play history for dispute resolution

### Infrastructure & Deployment

#### Hosting
- **Frontend**: Cloud VPS with nginx
- **Backend**: Cloud VPS with uvicorn + gunicorn
- **Database**: PostgreSQL on same or separate VPS
- **SSL/TLS**: Let's Encrypt certificates
- **Domain**: Separate subdomain per league (optional)

#### Monitoring & Logging
- **Application Logs**: Structured JSON logging
- **Error Tracking**: Exception logging with stack traces
- **Performance Monitoring**: Response time tracking
- **WebSocket Health**: Connection status monitoring
- **Database Monitoring**: Query performance and connection pool

#### Backup & Recovery
- **Database Backups**: Daily automated backups
- **Game State Snapshots**: Periodic state dumps
- **Recovery Procedures**: Documented recovery process
- **Data Retention**: Completed games archived after 1 year (configurable)

---

## User Experience Requirements

### Mobile-First Design

#### Layout & Navigation
- **Single Column Layout**: Optimized for portrait mobile screens
- **Bottom Navigation**: Primary actions easily thumb-accessible
- **Collapsible Sections**: Game details, history, stats can collapse
- **Swipe Gestures**: Swipe between game views, history
- **Touch Targets**: Minimum 44x44px for all interactive elements

#### Game Interface
- **Field Visualization**: Clear diamond with runners, scalable
- **Decision Cards**: Full-width decision buttons with clear labels
- **Score Display**: Persistent header with key info
- **Quick Actions**: Common actions (substitutions, pitching changes) accessible
- **Minimal Scrolling**: Key information visible without scrolling

### Desktop Experience
- **Two-Column Layout**: Game state left, play-by-play/decisions right
- **Keyboard Shortcuts**: Quick access to common actions
- **Hover States**: Additional info on hover
- **Multiple Games**: Support for tabbed multi-game viewing (stretch goal)

### Loading States & Feedback

#### Real-Time Feedback
- **WebSocket Status**: Connection indicator in UI
- **Waiting States**: Clear "Waiting for opponent" messaging
- **Action Feedback**: Immediate visual confirmation of actions
- **Dice Roll Animation**: Exciting, brief animation for rolls
- **Play Resolution**: Smooth transition to play outcome

#### Error Handling
- **Connection Loss**: Automatic reconnection with status updates
- **Action Errors**: Clear error messages with recovery options
- **Game Errors**: Graceful degradation, never break game state
- **Network Issues**: Offline indicator with queued actions

### Accessibility
- **WCAG 2.1 AA Compliance**: Meet accessibility standards
- **Screen Reader Support**: Proper ARIA labels throughout
- **Keyboard Navigation**: Full game playable via keyboard
- **Color Contrast**: Sufficient contrast for all text
- **Focus Indicators**: Clear focus states for interactive elements

---

## League Configuration System

### Config Structure

#### Base Configuration (Shared)
```python
class BaseGameConfig:
    """Shared configuration across all leagues"""
    innings: int = 9
    outs_per_inning: int = 3
    strikes_for_out: int = 3
    balls_for_walk: int = 4
    roster_size: int = 26
    min_pitchers: int = 5
    positions: List[str] = ['C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF']
```

#### League-Specific Configuration
```python
class League1Config(BaseGameConfig):
    """League 1 specific rules"""
    league_id: str = "league_1"
    result_charts: Dict = {...}  # d20 outcome tables
    special_rules: Dict = {
        "extra_innings_runner": True,
        "designated_hitter": False,
        ...
    }

class League2Config(BaseGameConfig):
    """League 2 specific rules"""
    league_id: str = "league_2"
    result_charts: Dict = {...}  # Different d20 tables
    special_rules: Dict = {
        "extra_innings_runner": False,
        "designated_hitter": True,
        ...
    }
```

#### Result Charts
```python
# Example d20 chart structure
result_charts = {
    "batting": {
        # Column variations per league
        "power_hitter_vs_pitcher": {
            1: "strikeout",
            2: "strikeout",
            3: "groundout",
            ...
            18: "double",
            19: "triple",
            20: "homerun"
        },
        ...
    },
    "baserunning": {...},
    "defense": {...}
}
```

### Config Loading
- Game session initialized with league_id
- Appropriate config loaded at game start
- Config immutable during game (stored with game metadata)
- Config versioning for rule changes over time

---

## Implementation Roadmap

### Phase 1: Core Infrastructure (Weeks 1-3)

**Backend Foundation:**
- FastAPI project setup with Python 3.11+
- PostgreSQL database setup with initial schema
- WebSocket server with Socket.io
- Discord OAuth integration
- Basic game session management
- Dice roll generation and testing

**Frontend Foundation (per league):**
- Nuxt 3 project setup with TypeScript
- Tailwind CSS configuration
- Discord OAuth integration
- WebSocket client setup
- Basic routing and navigation

**Deliverable**: Players can authenticate and establish WebSocket connections

### Phase 2: Game Engine Core (Weeks 4-6)

**Backend Game Logic:**
- In-memory game state management
- Play resolution engine with base rules
- League config system (initial implementation)
- Database operations for plays and lineups
- Game state persistence and recovery

**Frontend Game View:**
- Game board visualization
- Score and state display
- Basic decision input forms
- Real-time state updates via WebSocket

**Deliverable**: Can play a simplified game from start to finish

### Phase 3: Complete Game Features (Weeks 7-9)

**Backend Enhancements:**
- All strategic decisions implemented
- Substitution and pitching change logic
- Complete result charts for both leagues
- AI opponent integration
- Async game mode support

**Frontend Enhancements:**
- Complete decision workflow UI
- Substitution interfaces
- Play-by-play history display
- Mobile-optimized layouts
- Desktop responsive layouts

**Deliverable**: Full-featured game matching legacy system capabilities

### Phase 4: Spectator & Polish (Weeks 10-11)

**Spectator Mode:**
- Spectator WebSocket events
- Read-only game view
- Spectator list display

**UI/UX Polish:**
- Dice roll animations
- Smooth transitions
- Loading states and error handling
- Mobile touch optimization
- Accessibility improvements

**Deliverable**: Production-ready system with spectator support

### Phase 5: Testing & Launch (Weeks 12-13)

**Testing:**
- End-to-end game testing
- Load testing (10 concurrent games)
- Mobile device testing (iOS/Android)
- Browser compatibility testing
- Security audit

**Documentation:**
- User guide for players
- Technical documentation
- Deployment procedures
- Troubleshooting guide

**Launch:**
- Soft launch with beta testers
- Collect feedback and iterate
- Full launch and migration from Google Sheets
- Monitor performance and stability

**Deliverable**: Stable production system, legacy system deprecated

---

## Post-MVP Features (Future Phases)

### Phase 6: Roster Management (Weeks 14-16)
- My Team page with team selection
- Roster viewing and editing
- Lineup builder for pre-game setup
- Roster validation and constraints
- Integration with game creation flow

### Phase 7: Marketplace (League-Specific) (Weeks 17-19)
- Card browsing and search
- Buy/sell functionality
- Price tracking and history
- Inventory management
- League-specific marketplace rules

### Phase 8: Team Transactions (League-Specific) (Weeks 20-21)
- Team-to-team trade interface
- Trade proposals and acceptance
- Trade validation and league rules
- Trade history and tracking

### Phase 9: Advanced Features (Future)
- Tournament bracket system
- League standings and statistics
- Advanced analytics and reports
- Mobile native apps (iOS/Android)
- Discord bot integration for game notifications
- Replay system for completed games
- Custom game modes and events

---

## Risk Assessment & Mitigation

### Technical Risks

**WebSocket Reliability**
- **Risk**: Connection drops, message loss, state desynchronization
- **Mitigation**: Automatic reconnection, state recovery from database, heartbeat monitoring, message acknowledgment system

**Database Performance**
- **Risk**: Slow writes impact game responsiveness
- **Mitigation**: Async database operations, connection pooling, database indexing, query optimization

**State Management Complexity**
- **Risk**: In-memory state gets out of sync with database
- **Mitigation**: Comprehensive testing, state validation, recovery procedures, logging

**League Config Bugs**
- **Risk**: Rule variation bugs affect gameplay fairness
- **Mitigation**: Extensive config testing, versioning system, rollback capability

### User Adoption Risks

**Migration Friction**
- **Risk**: Users resist switching from familiar Google Sheets
- **Mitigation**: Feature parity first, clear migration guide, beta testing period, user training

**Mobile UX Challenges**
- **Risk**: Complex gameplay difficult on mobile
- **Mitigation**: Mobile-first design, user testing on real devices, iterative UX improvements

**Learning Curve**
- **Risk**: New system confusing for existing players
- **Mitigation**: Intuitive UI, onboarding flow, help documentation, video tutorials

### Business Risks

**Timeline Pressure**
- **Risk**: Legacy system deprecation deadline missed
- **Mitigation**: Phased rollout, MVP focus, parallel operation period, buffer time

**Single Developer Risk**
- **Risk**: Development bottlenecks, knowledge silos
- **Mitigation**: AI copilot usage, comprehensive documentation, code comments, automated testing

**Scope Creep**
- **Risk**: Feature additions delay MVP launch
- **Mitigation**: Strict MVP definition, post-MVP roadmap, change request process

---

## Success Metrics & KPIs

### Launch Success (First Month)
- 90% of active players migrated from Google Sheets
- Zero critical bugs requiring rollback
- Average game completion time < 60 minutes
- < 5% of games abandoned due to technical issues

### User Engagement (Ongoing)
- Average 5+ games per active player per week
- 60%+ of games played on mobile devices
- Average session duration 30-60 minutes
- Spectator views per game > 2 (indicates community interest)

### Performance Metrics
- 95th percentile action latency < 1 second
- WebSocket connection success rate > 99%
- Game state recovery success rate 100%
- Database write latency < 100ms average

### Reliability Metrics
- System uptime > 99.5%
- Zero data corruption incidents
- Successful game recovery rate 100%
- Average time to recover from server restart < 30 seconds

### User Satisfaction
- Net Promoter Score (NPS) > 50
- System usability scale (SUS) score > 75
- Support ticket volume < 5 per week
- Positive feedback ratio > 80%

---

## Testing Strategy

### Unit Testing
- **Game Engine Logic**: Test all play resolution scenarios
- **Dice Generation**: Verify randomness and security
- **State Management**: Test state transitions and validation
- **Config System**: Verify league-specific rules load correctly
- **Database Operations**: Test CRUD operations and recovery
- **Target Coverage**: > 80% code coverage

### Integration Testing
- **WebSocket Communication**: Test all event types
- **Database Persistence**: Test async write operations
- **API Integration**: Test REST API client interactions
- **Game Flow**: Test complete game workflows
- **Multi-user Scenarios**: Test concurrent player actions

### End-to-End Testing
- **Complete Games**: Play full games in all modes (live, async, vs AI)
- **Reconnection**: Test disconnect/reconnect scenarios
- **Spectator Experience**: Verify spectator can view games correctly
- **Mobile Devices**: Test on iOS and Android devices
- **Browser Compatibility**: Test on Chrome, Safari, Firefox, Edge

### Load Testing
- **Concurrent Games**: Simulate 10 simultaneous games
- **WebSocket Connections**: Test 100+ concurrent connections
- **Database Load**: Test with 100,000+ play records
- **Recovery Speed**: Test state recovery under load
- **Memory Usage**: Monitor memory over extended periods

### User Acceptance Testing
- **Beta Testing**: 10-20 players test for 2 weeks
- **Feedback Collection**: Structured feedback forms
- **Bug Reporting**: Clear bug reporting process
- **Comparison Testing**: Side-by-side with Google Sheets
- **Mobile Testing**: Real device testing by users

---

## Appendix

### API Endpoint Reference

#### Game Backend REST Endpoints
```
POST   /api/games              # Create new game
GET    /api/games/:id          # Get game details
GET    /api/games/active       # List active games
GET    /api/games/completed    # List completed games
POST   /api/games/:id/join     # Join game as player
GET    /api/games/:id/history  # Get play-by-play history
DELETE /api/games/:id          # Abandon/delete game (admin)
```

#### League REST API Endpoints (Existing)
```
GET    /api/teams/:id          # Get team details
GET    /api/teams/:id/roster   # Get team roster
GET    /api/players/:id        # Get player details
GET    /api/cards/:id          # Get card details
POST   /api/games/submit       # Submit completed game results
```

### Database Indexes

#### Performance Optimization
```sql
-- Games table indexes
CREATE INDEX idx_games_status ON games(status);
CREATE INDEX idx_games_league ON games(league_id);
CREATE INDEX idx_games_teams ON games(home_team_id, away_team_id);
CREATE INDEX idx_games_created ON games(created_at DESC);

-- Plays table indexes
CREATE INDEX idx_plays_game ON plays(game_id);
CREATE INDEX idx_plays_game_number ON plays(game_id, play_number);
CREATE INDEX idx_plays_created ON plays(created_at);

-- Lineups table indexes
CREATE INDEX idx_lineups_game ON lineups(game_id);
CREATE INDEX idx_lineups_team ON lineups(team_id);
CREATE INDEX idx_lineups_active ON lineups(game_id, is_active);

-- Game sessions table indexes
CREATE INDEX idx_sessions_last_action ON game_sessions(last_action_at);
```

### WebSocket Event Payload Examples

#### game_state_update
```json
{
  "event": "game_state_update",
  "data": {
    "game_id": "uuid",
    "inning": 3,
    "half": "top",
    "outs": 2,
    "balls": 2,
    "strikes": 1,
    "home_score": 2,
    "away_score": 1,
    "runners": {
      "first": null,
      "second": 12345,
      "third": null
    },
    "current_batter": {
      "card_id": 67890,
      "player_name": "Mike Trout",
      "batting_avg": 0.305
    },
    "current_pitcher": {
      "card_id": 11111,
      "player_name": "Sandy Alcantara",
      "era": 2.45
    },
    "decision_required": {
      "role": "home_defense",
      "type": "set_defense",
      "timeout": 30
    }
  }
}
```

#### play_completed
```json
{
  "event": "play_completed",
  "data": {
    "play_number": 45,
    "dice_roll": 14,
    "result_type": "single",
    "description": "Mike Trout singles to left field. Runner advances to third.",
    "runs_scored": 0,
    "outs_recorded": 0,
    "new_state": {
      "outs": 2,
      "runners": {
        "first": 67890,
        "second": null,
        "third": 12345
      }
    }
  }
}
```

#### dice_rolled
```json
{
  "event": "dice_rolled",
  "data": {
    "roll": 14,
    "animation_duration": 2000,
    "timestamp": "2025-10-16T19:45:23Z"
  }
}
```

### Environment Configuration

#### Backend Environment Variables
```bash
# Application
APP_ENV=production
DEBUG=false
SECRET_KEY=your-secret-key

# Database
DATABASE_URL=postgresql://user:pass@localhost:5432/paperdynasty
DB_POOL_SIZE=20
DB_MAX_OVERFLOW=10

# Discord OAuth
DISCORD_CLIENT_ID=your-client-id
DISCORD_CLIENT_SECRET=your-client-secret
DISCORD_REDIRECT_URI=https://yourdomain.com/auth/callback

# League APIs
LEAGUE1_API_URL=https://league1-api.com
LEAGUE1_API_KEY=your-api-key
LEAGUE2_API_URL=https://league2-api.com
LEAGUE2_API_KEY=your-api-key

# WebSocket
WS_HEARTBEAT_INTERVAL=30
WS_CONNECTION_TIMEOUT=60

# Game Settings
MAX_CONCURRENT_GAMES=20
GAME_IDLE_TIMEOUT=86400  # 24 hours
AUTO_SAVE_INTERVAL=10  # plays
```

#### Frontend Environment Variables
```bash
# Application
NUXT_PUBLIC_API_URL=https://api.yourdomain.com
NUXT_PUBLIC_WS_URL=wss://api.yourdomain.com

# Discord OAuth
NUXT_PUBLIC_DISCORD_CLIENT_ID=your-client-id
NUXT_PUBLIC_DISCORD_REDIRECT_URI=https://yourdomain.com/auth/callback

# League Config
NUXT_PUBLIC_LEAGUE_ID=league_1
NUXT_PUBLIC_LEAGUE_NAME=Paper Dynasty League 1
NUXT_PUBLIC_LEAGUE_API_URL=https://league1-api.com

# Features
NUXT_PUBLIC_ENABLE_SPECTATORS=true
NUXT_PUBLIC_ENABLE_AI_GAMES=true
NUXT_PUBLIC_ENABLE_ASYNC_GAMES=true
```

### Deployment Checklist

#### Pre-Deployment
- [ ] All tests passing (unit, integration, e2e)
- [ ] Load testing completed successfully
- [ ] Security audit completed
- [ ] Database migrations tested
- [ ] Backup procedures verified
- [ ] Monitoring and logging configured
- [ ] SSL certificates installed
- [ ] Environment variables configured
- [ ] Documentation updated

#### Deployment Steps
1. **Database Setup**
   - Create production database
   - Run migrations
   - Create indexes
   - Configure backups

2. **Backend Deployment**
   - Deploy FastAPI application
   - Configure uvicorn/gunicorn
   - Set up process manager (systemd/supervisor)
   - Configure nginx reverse proxy
   - Test WebSocket connections

3. **Frontend Deployment (per league)**
   - Build production bundles
   - Deploy static assets
   - Configure nginx for SPA routing
   - Set up CDN (optional)
   - Test Discord OAuth flow

4. **Post-Deployment**
   - Verify all endpoints responding
   - Test WebSocket connectivity
   - Create test game and verify functionality
   - Monitor logs for errors
   - Set up alerting

#### Rollback Plan
- Database snapshot before deployment
- Previous application version tagged in git
- Documented rollback procedures
- Database migration rollback scripts
- DNS/routing quick revert capability

### Monitoring & Alerting

#### Key Metrics to Monitor
- **Application Health**
  - HTTP response times
  - WebSocket connection count
  - Active game sessions
  - Memory usage
  - CPU usage

- **Database Health**
  - Connection pool utilization
  - Query execution times
  - Slow query log
  - Database size growth

- **Game Metrics**
  - Games created per hour
  - Games completed per hour
  - Average game duration
  - Games abandoned rate
  - Reconnection frequency

#### Alert Thresholds
- HTTP 5xx errors > 5 per minute
- WebSocket connection failures > 10%
- Database connection pool > 90% utilized
- Memory usage > 85%
- Game state recovery failures > 0
- System uptime < 99.5%

### Support & Maintenance

#### User Support Channels
- Discord server for real-time support
- GitHub issues for bug reports
- Email support for account issues
- In-app feedback form

#### Maintenance Windows
- Weekly maintenance window: Sunday 3-5 AM (lowest usage)
- Emergency maintenance: As needed with advance notice
- Database backups: Daily at 2 AM
- Log rotation: Weekly

#### Incident Response
1. **Detection**: Automated alerts or user reports
2. **Assessment**: Determine severity and impact
3. **Communication**: Update status page, notify users
4. **Resolution**: Fix issue, test thoroughly
5. **Post-Mortem**: Document incident and prevention steps

---

## Glossary

**GM (General Manager)**: A player who manages a team in Paper Dynasty

**Team**: An entity in the game that owns cards and competes in games. A team can have 1-2 GMs with permissions to play.

**Card**: An individual player card instance owned by a team. Multiple cards can reference the same player.

**Player**: The core record containing baseball statistics and probabilities for a real MLB player.

**Roster**: The collection of 26 cards that a team can use in games. Teams can have multiple rosters.

**Lineup**: The specific arrangement of cards for a game, including batting order and defensive positions.

**Main Team**: A GM's primary team used for regular league play.

**Gauntlet Team**: A secondary team used for special event-based games with temporary rosters.

**Play**: A single at-bat or baserunning event in a game, recorded with complete details.

**Inning**: A period of play in baseball consisting of a top half (away team bats) and bottom half (home team bats).

**d20**: A 20-sided die; Paper Dynasty uses d20 rolls to determine play outcomes via result charts.

**Result Chart**: Tables that map dice roll results to play outcomes based on game situation and card attributes.

**League Config**: Configuration system that defines league-specific rules and result charts.

**WebSocket**: Protocol for persistent, bidirectional communication between client and server enabling real-time updates.

**Async Play**: Game mode where players make decisions at different times, allowing games to span multiple days.

**Spectator**: A user watching a game in real-time without participating as a player.

**Discord Snowflake ID (gmid)**: Unique identifier for a Discord user, used to link game accounts to Discord.

---

## Conclusion

This PRD defines a comprehensive real-time game engine for Paper Dynasty that replaces the legacy Google Sheets system with a modern, scalable web application. The system prioritizes:

1. **Reliability**: Persistent game state with automatic recovery
2. **Flexibility**: Support for multiple play modes (live, async, vs AI)
3. **Performance**: Fast, responsive gameplay on mobile and desktop
4. **Scalability**: League-agnostic architecture supporting multiple leagues
5. **User Experience**: Mobile-first design with intuitive interfaces

The phased implementation approach allows for incremental delivery while maintaining focus on the critical MVP: a fully functional real-time game engine. Post-MVP phases will expand functionality to include roster management, marketplace, and league-specific features.

Success depends on meeting the aggressive timeline for replacing the deprecated Google Sheets system while maintaining feature parity and improving the user experience. The hybrid architecture (in-memory state + database persistence) provides the optimal balance of performance and reliability for Paper Dynasty's turn-based gameplay and modest concurrent user load.

With proper execution of this PRD, Paper Dynasty will have a modern, maintainable platform that can evolve with the game's needs for years to come.