# Backend - Paper Dynasty Game Engine ## Overview FastAPI-based real-time game backend handling WebSocket communication, game state management, and database persistence for both SBA and PD leagues. **Tech Stack**: FastAPI (Python 3.13), Socket.io, PostgreSQL 14+, SQLAlchemy 2.0, Pydantic v2, pytest ## Project Structure ``` backend/ ├── app/ │ ├── main.py # FastAPI + Socket.io init │ ├── config.py # pydantic-settings │ ├── core/ # Game engine - see core/CLAUDE.md │ ├── config/ # League configs - see config/CLAUDE.md │ ├── models/ # Pydantic + SQLAlchemy - see models/CLAUDE.md │ ├── websocket/ # Socket.io handlers - see websocket/CLAUDE.md │ ├── api/ # REST endpoints - see api/CLAUDE.md │ ├── database/ # Async persistence - see database/CLAUDE.md │ ├── services/ # Business logic (LineupService, PD API client) │ └── utils/ # Logging, auth - see utils/CLAUDE.md ├── tests/ # See tests/CLAUDE.md ├── terminal_client/ # Interactive testing - see terminal_client/CLAUDE.md └── logs/ # Daily rotating logs (gitignored) ``` ## Development ### Quick Start ```bash cd backend uv sync # Install dependencies docker compose up -d # Start Redis uv run python -m app.main # Start server at localhost:8000 ``` ### Testing ```bash uv run pytest tests/unit/ -v # All unit tests (739 passing) uv run python -m terminal_client # Interactive REPL ``` ### Code Quality ```bash uv run mypy app/ # Type checking uv run ruff check app/ # Linting uv run ruff format app/ # Formatting ``` ## Key Patterns ### Hybrid State Management - **In-memory**: Active game states for <500ms response - **PostgreSQL**: Persistent storage for recovery - **Pattern**: Write-through cache (update memory + async DB write) ### League-Agnostic Core - Game engine works for any league - Config-driven behavior (SbaConfig, PdConfig) - Polymorphic player models (BasePlayer → SbaPlayer, PdPlayer) ### DateTime **Always use Pendulum** (never Python's datetime): ```python import pendulum now = pendulum.now('UTC') ``` ## Environment ### Database - **Server**: PostgreSQL at 10.10.0.42:5432 - **Database**: paperdynasty_dev - **Connection**: `postgresql+asyncpg://...` ### Required .env Variables ```bash DATABASE_URL=postgresql+asyncpg://... SECRET_KEY=your-secret-key DISCORD_CLIENT_ID=... DISCORD_CLIENT_SECRET=... ``` ### Python Environment - **Version**: Python 3.13.3 - **Package Manager**: UV (fast, reliable) - **Virtual Environment**: `backend/.venv/` ## Testing Policy **REQUIRED**: 100% unit tests passing before any commit ```bash uv run pytest tests/unit/ -q # Must show all passing ``` ## Coding Standards - **Formatting**: Ruff (88 chars, black-compatible) - **Linting**: Ruff (replaces flake8, includes isort, pyupgrade) - **Type Hints**: Required for public functions - **Logging**: `logger = logging.getLogger(f'{__name__}.ClassName')` - **Error Handling**: "Raise or Return" - no silent failures ## Performance Targets | Metric | Target | |--------|--------| | Action response | < 500ms | | WebSocket delivery | < 200ms | | DB writes | < 100ms (async) | | State recovery | < 2 seconds | ## References - **WebSocket Protocol Spec**: `../.claude/WEBSOCKET_PROTOCOL_SPEC.md` - Complete event catalog and workflow - **Type Checking Guide**: `.claude/type-checking-guide.md` - **Code Review**: `.claude/CODE_REVIEW_GAME_ENGINE.md` - **Implementation Plans**: `../.claude/implementation/` - **Full PRD**: `../prd-web-scorecard-1.1.md` --- **Tests**: 739/739 passing | **Phase**: 3E-Final Complete | **Updated**: 2025-01-19