paper-dynasty-gameplay-webapp/DEVELOPMENT_GUIDE_V2.md
Cal Corum c09f9d1302 CLAUDE: Initialize Paper Dynasty web app with Model/Service Architecture
Establishes foundation for migrating baseball simulation from Discord bot to web application using service-oriented architecture pattern.

Key components:
- FastAPI application structure with dependency injection
- Service layer foundation with base classes and container
- Comprehensive directory documentation with README files
- PostgreSQL containerization with Docker Compose
- Testing structure for unit/integration/e2e tests
- Migration planning documentation
- Rotating log configuration per user requirements

Architecture follows Model/Service/Controller pattern to improve testability, maintainability, and scalability over original monolithic Discord app.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-27 21:44:12 -05:00

574 lines
19 KiB
Markdown

# Paper Dynasty Web App Development Guide v2.0
## Model/Service Architecture Edition
## Overview
This guide provides instructions for AI agents working on the Paper Dynasty web app migration project using a **Model/Service Architecture**. This approach separates business logic into services, improving testability, maintainability, and scalability over the original monolithic approach.
## Quick Start for AI Agents
### Before Starting Any Session:
1. **Check Progress**: Read `./.claude/plans/web-migration-v2.md` to understand current status
2. **Review TODO List**: Use TodoWrite tool to track your progress throughout the session
3. **Understand Context**: This is a migration from `../discord-app/` to a web interface using **Model/Service Architecture**
4. **Follow Standards**: Use the code review methodology defined below
### Current Project Status
- **Migration Type**: Fork approach with **Model/Service Architecture**
- **Current Phase**: Check `./.claude/plans/web-migration-v2.md` for latest status
- **Architecture**: Clean separation between Models, Services, Controllers (FastAPI routes)
- **Next Tasks**: Always work from the current phase checklist in the migration plan
---
## Architecture Overview
### Model/Service Architecture Benefits
- **Separation of Concerns**: Clear boundaries between data, business logic, and web interface
- **Testability**: Services can be unit tested independently of database and web framework
- **Scalability**: Easy to add caching, background tasks, API versioning
- **Maintainability**: Business logic centralized in services, not scattered across routes
- **Future-Proofing**: Ready for mobile API, microservices, or different frontends
### Project Structure
```
gameplay-website/
├── .claude/
│ └── web-migration-v2.md
├── app/
│ ├── main.py # FastAPI application setup
│ ├── models/ # Pure data models (SQLModel)
│ │ ├── game.py # Game, Team, Player, Lineup, Play
│ │ ├── web_models.py # Session, Preferences, Notifications
│ │ └── exceptions.py # Custom exceptions
│ ├── services/ # Business logic layer ⭐ NEW
│ │ ├── __init__.py
│ │ ├── game_service.py # Game creation, management, queries
│ │ ├── gameplay_service.py # Core gameplay simulation & flow
│ │ ├── ai_service.py # AI decision making
│ │ ├── user_service.py # User sessions, preferences
│ │ ├── notification_service.py # Web notifications
│ │ └── auth_service.py # Discord OAuth, session management
│ ├── repositories/ # Data access layer ⭐ NEW (optional)
│ │ ├── __init__.py
│ │ ├── game_repository.py # Complex game queries
│ │ └── user_repository.py # User/session queries
│ ├── routers/ # FastAPI route handlers ⭐ ENHANCED
│ │ ├── __init__.py
│ │ ├── games.py # Game-related endpoints
│ │ ├── auth.py # Authentication routes
│ │ ├── api.py # JSON API for HTMX
│ │ └── pages.py # HTML page routes
│ ├── engine/ # Core simulation engine (stateless)
│ │ ├── dice.py # Dice rolling, fielding checks
│ │ ├── simulation.py # Pitcher vs batter mechanics
│ │ └── calculations.py # Statistics, WPA calculations
│ ├── config/
│ │ └── constants.py
│ ├── static/
│ └── templates/
├── tests/ # Comprehensive test structure
│ ├── unit/ # Unit tests for services
│ ├── integration/ # Integration tests
│ └── e2e/ # End-to-end tests
├── requirements.txt
└── DEVELOPMENT_GUIDE_V2.md # This file
```
---
## Code Review Methodology
### When Migrating Code from Discord App:
#### 1. Service Extraction First
```python
# ❌ Old approach: Business logic in routes
@app.post("/games/start")
async def start_game(request: Request):
# 50+ lines of game creation logic mixed with HTTP handling
# ✅ New approach: Clean service separation
@router.post("/games/start")
async def start_game(request: StartGameRequest):
game = await game_service.create_game(
away_team_id=request.away_team_id,
home_team_id=request.home_team_id,
game_type=request.game_type
)
return {"game_id": game.id, "status": "created"}
```
#### 2. Service Layer Design
```python
# ✅ Service pattern example
from sqlmodel import Session
from typing import Optional, List
from ..models.game import Game, Team
from ..repositories.game_repository import GameRepository
class GameService:
def __init__(self, session: Session):
self.session = session
self.game_repo = GameRepository(session)
async def create_game(
self,
away_team_id: int,
home_team_id: int,
game_type: str
) -> Game:
"""Create a new game with validation and business rules"""
# Validation
await self._validate_teams_available(away_team_id, home_team_id)
# Business logic
game = Game(
away_team_id=away_team_id,
home_team_id=home_team_id,
game_type=game_type,
season=self._get_current_season()
)
# Persistence
return await self.game_repo.create(game)
async def _validate_teams_available(self, away_id: int, home_id: int):
"""Private method for business rule validation"""
# Implementation here
pass
```
#### 3. Dependency Cleanup
```python
# ❌ Remove these Discord-specific imports
import discord
from discord.ext import commands
from discord import app_commands
# ✅ Replace with web-appropriate imports
from fastapi import FastAPI, Request, Response, Depends
from sqlmodel import Session
from typing import List, Optional
```
#### 4. Error Handling Review
```python
# ❌ Discord-specific error handling
await interaction.response.send_message("Error occurred", ephemeral=True)
# ✅ Service-layer error handling
from ..models.exceptions import GameNotFoundException
class GameService:
async def get_game(self, game_id: int) -> Game:
game = await self.game_repo.get_by_id(game_id)
if not game:
raise GameNotFoundException(f"Game {game_id} not found")
return game
# ✅ Route-layer error handling
@router.get("/games/{game_id}")
async def get_game(game_id: int, game_service: GameService = Depends()):
try:
game = await game_service.get_game(game_id)
return game
except GameNotFoundException as e:
raise HTTPException(status_code=404, detail=str(e))
```
#### 5. Logging Standards
Follow the user's CLAUDE.md requirements:
```python
import logging
logger = logging.getLogger(f'{__name__}.GameService')
class GameService:
async def create_game(self, away_team_id: int, home_team_id: int) -> Game:
logger.info(f'GameService.create_game - Creating game: {away_team_id} vs {home_team_id}')
try:
# Business logic
result = await self._create_game_logic(away_team_id, home_team_id)
logger.info(f'GameService.create_game - Game created successfully: {result.id}')
return result
except Exception as e:
logger.error(f'GameService.create_game - Failed to create game: {str(e)}')
raise
```
#### 6. Service Testing Pattern
```python
# ✅ Unit test services independently
import pytest
from unittest.mock import Mock
from app.services.game_service import GameService
from app.models.game import Game
@pytest.fixture
def mock_session():
return Mock()
@pytest.fixture
def game_service(mock_session):
return GameService(mock_session)
@pytest.mark.asyncio
async def test_create_game_success(game_service):
# Test business logic without database
result = await game_service.create_game(
away_team_id=1,
home_team_id=2,
game_type="ranked"
)
assert result.away_team_id == 1
assert result.home_team_id == 2
```
### Code Review Checklist Template
For each migrated file, check:
- [ ] Business logic extracted into appropriate service
- [ ] Service has clear, single responsibility
- [ ] All Discord imports removed
- [ ] Error handling appropriate for service layer
- [ ] Logging follows project standards
- [ ] Services have comprehensive unit tests
- [ ] Routes are thin, delegating to services
- [ ] Database access goes through repositories (if using repository pattern)
- [ ] Type hints on all service methods
- [ ] No obvious performance issues
---
## Service Layer Guidelines
### Service Responsibilities
#### GameService
- Game creation and validation
- Game state management
- Game queries and filtering
- Game lifecycle (start, pause, complete)
#### GameplayService
- Core gameplay simulation
- Play execution and validation
- Inning management
- Score calculation
#### AIService
- AI decision making
- Manager AI logic
- Automated gameplay
#### UserService
- User session management
- User preferences
- Authentication state
#### NotificationService
- Web notifications
- Game event notifications
- Real-time updates
### Service Design Principles
1. **Single Responsibility**: Each service has one clear purpose
2. **Dependency Injection**: Services receive dependencies via constructor
3. **Stateless**: Services don't maintain instance state between calls
4. **Testable**: Services can be unit tested with mocked dependencies
5. **Pure Business Logic**: No HTTP, database, or UI concerns in services
### Service Interaction Patterns
```python
# ✅ Service-to-service communication
class GameplayService:
def __init__(self, session: Session, ai_service: AIService):
self.session = session
self.ai_service = ai_service
async def execute_play(self, game_id: int, play_data: dict) -> PlayResult:
# Get current game state
game = await self.game_repo.get_by_id(game_id)
# Check if AI needs to make decisions
if game.ai_team:
ai_decision = await self.ai_service.get_defensive_decision(game)
play_data.update(ai_decision)
# Execute the play
return await self._execute_play_logic(game, play_data)
```
---
## Testing Architecture
### Test Structure
```
tests/
├── unit/ # Fast, isolated unit tests
│ ├── services/
│ │ ├── test_game_service.py
│ │ ├── test_gameplay_service.py
│ │ └── test_ai_service.py
│ ├── engine/
│ │ ├── test_dice.py
│ │ └── test_simulation.py
│ └── models/
│ └── test_game_models.py
├── integration/ # Database + service integration
│ ├── test_game_flow.py
│ └── test_auth_flow.py
└── e2e/ # Full application tests
├── test_game_creation.py
└── test_gameplay_flow.py
```
### Testing Patterns
#### Unit Testing Services
```python
# test_game_service.py
@pytest.fixture
def mock_game_repo():
return Mock(spec=GameRepository)
@pytest.fixture
def game_service(mock_game_repo):
return GameService(session=Mock(), game_repo=mock_game_repo)
@pytest.mark.asyncio
async def test_create_game_validates_teams(game_service, mock_game_repo):
# Test business logic without database
mock_game_repo.get_by_id.return_value = None # Team not found
with pytest.raises(TeamNotFoundException):
await game_service.create_game(999, 1000, "ranked")
```
#### Integration Testing
```python
# test_game_flow.py
@pytest.mark.asyncio
async def test_complete_game_creation_flow(db_session):
# Test with real database but isolated transaction
game_service = GameService(db_session)
# Create test data
team1 = await create_test_team(db_session)
team2 = await create_test_team(db_session)
# Test full flow
game = await game_service.create_game(team1.id, team2.id, "ranked")
assert game.id is not None
assert game.away_team_id == team1.id
```
### What to Test by Layer
#### Services (Unit Tests)
- **Critical**: Business logic validation, error handling, service interactions
- **Important**: Edge cases, complex calculations
- **Nice to have**: Performance characteristics
#### Engine (Unit Tests)
- **Critical**: Game simulation accuracy, dice probability, calculation correctness
- **Important**: Edge cases in game rules, random seed consistency
- **Nice to have**: Performance optimization
#### Integration Tests
- **Critical**: Database operations, service composition, authentication flow
- **Important**: Error propagation, transaction handling
- **Nice to have**: Caching behavior
---
## Migration Strategy
### Phase 1: Service Foundation
1. Create basic service interfaces
2. Extract simple business logic from Discord app
3. Set up dependency injection patterns
4. Create service unit tests
### Phase 2: Core Service Implementation
1. Implement GameService with full game management
2. Implement GameplayService with simulation logic
3. Implement AIService with decision making
4. Add comprehensive service tests
### Phase 3: Web Integration
1. Create FastAPI routes that use services
2. Add authentication and session services
3. Implement HTMX endpoints with service calls
4. Integration testing
### Phase 4: Advanced Features
1. Add repository layer if needed for complex queries
2. Implement notification service
3. Add caching and performance optimization
4. End-to-end testing
---
## Performance Considerations
### Service Layer Performance
- Use connection pooling for database sessions
- Implement caching at service level for expensive operations
- Consider async/await for I/O bound operations
- Monitor service call patterns for optimization opportunities
### Database Optimization
- Repositories handle complex queries and optimization
- Use eager loading for frequently accessed relationships
- Implement query result caching where appropriate
- Monitor N+1 query patterns
---
## Development Workflow
### Starting a New Session
1. Read current progress in `./.claude/web-migration-v2.md`
2. Update TodoWrite with current tasks focusing on service implementation
3. Work on the current phase tasks in order
4. Follow the service-first approach for any new business logic
5. Update progress in migration plan when completing major milestones
### Service Development Process
1. **Design**: Define service interface and responsibilities
2. **Test**: Write unit tests for expected behavior
3. **Implement**: Build service following single responsibility principle
4. **Integrate**: Connect service to routes and other services
5. **Validate**: Run full test suite and integration tests
### Virtual Environment Setup
Always check for virtual environment:
```bash
# Check for existing venv
ls -la | grep venv
# Create if doesn't exist (user works with discord.py, wants venv)
python -m venv venv
source venv/bin/activate # Linux/Mac
# or
venv\Scripts\activate # Windows
```
### Testing Requirements
User's CLAUDE.md specifies:
- "You do not need to ask for permission to run tests"
- Use pytest for all testing
- Include unit tests for services, integration tests for full flows
- Test critical game logic thoroughly
- Aim for 80%+ test coverage on services
### Git Commit Standards
User's CLAUDE.md specifies:
- Prefix commit messages with "CLAUDE: "
- Focus on the "why" rather than the "what"
- Example: "CLAUDE: Extract game creation logic into GameService for better testability"
---
## Migration-Specific Guidelines
### Files to Prioritize for Service Extraction
**High Priority (Extract to Services First)**:
- `../discord-app/command_logic/logic_gameplay.py``services/gameplay_service.py`
- `../discord-app/in_game/ai_manager.py``services/ai_service.py`
- Game creation/management logic → `services/game_service.py`
**Medium Priority (Core Engine - Keep Stateless)**:
- `../discord-app/in_game/simulations.py``engine/simulation.py`
- `../discord-app/dice.py``engine/dice.py`
**Lower Priority (Supporting Services)**:
- Authentication logic → `services/auth_service.py`
- User management → `services/user_service.py`
- Notifications → `services/notification_service.py`
### Service Extraction Patterns
#### Pattern 1: Discord Command → Service Method
```python
# ❌ Discord app pattern
@app_commands.command(name="start_game")
async def start_game(interaction: discord.Interaction):
# 50+ lines of business logic mixed with Discord API calls
# ✅ Web app pattern
class GameService:
async def create_game(self, away_team_id: int, home_team_id: int) -> Game:
# Pure business logic, no Discord dependencies
@router.post("/games/start")
async def start_game(request: StartGameRequest, game_service: GameService = Depends()):
return await game_service.create_game(request.away_team_id, request.home_team_id)
```
#### Pattern 2: Game Logic → Service + Engine
```python
# ❌ Mixed business logic and game engine
def process_at_bat(interaction, game_id, batter_decision):
# Mixed: Discord UI + game rules + database + simulation
# ✅ Separated concerns
class GameplayService:
async def process_at_bat(self, game_id: int, batter_decision: str) -> PlayResult:
# Business logic: validation, state management
def _simulate_at_bat(self, pitcher_stats, batter_stats) -> SimulationResult:
# Pure game engine logic
```
#### Pattern 3: AI Decision Making → AIService
```python
# ✅ Clean AI service
class AIService:
async def get_pitching_decision(self, game_state: GameState) -> PitchingDecision:
# AI logic without Discord dependencies
async def get_batting_decision(self, game_state: GameState) -> BattingDecision:
# AI logic without Discord dependencies
```
---
## Success Metrics
### Architecture Quality
- Clear separation between models, services, routes
- Services have single responsibilities
- Business logic not mixed with web framework code
- Comprehensive service unit tests
### Code Quality Standards
- All services have 90%+ test coverage
- Type hints required for all service methods
- Error handling appropriate for service layer
- Performance acceptable for multiple concurrent users
- No Discord-specific dependencies remaining
### Migration Success
- Working single-player baseball game with Discord OAuth
- Live scoreboard with news ticker
- Clean, service-oriented codebase ready for scaling
- Comprehensive test coverage across all layers
- Responsive web interface (mobile + desktop)
---
## Emergency Contacts & Resources
- **Project Owner**: Check project README for contact info
- **Discord App Source**: `../discord-app/` directory
- **Migration Plan**: `./.claude/web-migration-v2.md`
- **User Preferences**: `/home/cal/.claude/CLAUDE.md`
- **Architecture Reference**: This file (DEVELOPMENT_GUIDE_V2.md)
Remember: This is a migration project with the goal of creating a scalable, maintainable web application using Model/Service Architecture. Always prioritize clean architecture and comprehensive testing over speed of development.