Add comprehensive project documentation and Docker infrastructure for Paper Dynasty Real-Time Game Engine - a web-based multiplayer baseball simulation platform replacing the legacy Google Sheets system. Documentation Added: - Complete PRD (Product Requirements Document) - Project README with dual development workflows - Implementation guide with 5-phase roadmap - Architecture docs (backend, frontend, database, WebSocket) - CLAUDE.md context files for each major directory Infrastructure Added: - Root docker-compose.yml for full stack orchestration - Dockerfiles for backend and both frontends (multi-stage builds) - .dockerignore files for optimal build context - .env.example with all required configuration - Updated .gitignore for Python, Node, Nuxt, and Docker Project Structure: - backend/ - FastAPI + Socket.io game engine (Python 3.11+) - frontend-sba/ - SBA League Nuxt 3 frontend - frontend-pd/ - PD League Nuxt 3 frontend - .claude/implementation/ - Detailed implementation guides Supports two development workflows: 1. Local dev (recommended): Services run natively with hot-reload 2. Full Docker: One-command stack orchestration for testing/demos Next: Phase 1 implementation (backend/frontend foundations)
1436 lines
49 KiB
Markdown
1436 lines
49 KiB
Markdown
# 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. |