313 lines
12 KiB
Markdown
313 lines
12 KiB
Markdown
# Week 6: Player Models & League Integration - Overview
|
|
|
|
**Created**: 2025-10-25
|
|
**Status**: Planning Complete, Ready for Implementation
|
|
**Prerequisites**: Week 5 Complete (Game engine working)
|
|
**Focus**: League-specific player models and API integration
|
|
|
|
---
|
|
|
|
## Quick Summary
|
|
|
|
Implement two-layer player model system:
|
|
1. **API Models** - Exact match to external league APIs (PD & SBA)
|
|
2. **Game Models** - Optimized for gameplay with only essential fields
|
|
|
|
This allows us to:
|
|
- Deserialize API responses with full type safety
|
|
- Work with clean, minimal data in game engine
|
|
- Support both leagues with different data structures
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ External League APIs │
|
|
│ ┌──────────────────────┐ ┌──────────────────────┐ │
|
|
│ │ PD API │ │ SBA API │ │
|
|
│ │ - Player │ │ - Player │ │
|
|
│ │ - Batting Ratings │ │ │ │
|
|
│ │ - Pitching Ratings │ │ │ │
|
|
│ └──────────────────────┘ └──────────────────────┘ │
|
|
└────────────────┬──────────────────────┬─────────────────────┘
|
|
│ │
|
|
↓ ↓
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ API Response Models (api_models.py) │
|
|
│ ┌──────────────────────┐ ┌──────────────────────┐ │
|
|
│ │ PdPlayerApi │ │ SbaPlayerApi │ │
|
|
│ │ PdBattingRatingsApi │ │ (with nested Team, │ │
|
|
│ │ PdPitchingRatingsApi│ │ Manager, Division) │ │
|
|
│ └──────────────────────┘ └──────────────────────┘ │
|
|
└────────────────┬──────────────────────┬─────────────────────┘
|
|
│ │
|
|
↓ ↓
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Mapper Layer (PlayerMapper class) │
|
|
│ Transforms: API → Game Models │
|
|
│ - Extracts essential fields │
|
|
│ - Flattens nested structures │
|
|
│ - Normalizes position data (pos_1-8 → List[str]) │
|
|
└────────────────┬──────────────────────┬─────────────────────┘
|
|
│ │
|
|
↓ ↓
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Game Models (player_models.py) │
|
|
│ ┌──────────────────────┐ ┌──────────────────────┐ │
|
|
│ │ PdPlayer │ │ SbaPlayer │ │
|
|
│ │ - Basic fields │ │ - Basic fields │ │
|
|
│ │ - Batting ratings │ │ - Simplified data │ │
|
|
│ │ - Pitching ratings │ │ │ │
|
|
│ └──────────────────────┘ └──────────────────────┘ │
|
|
└────────────────┬──────────────────────┬─────────────────────┘
|
|
│ │
|
|
↓ ↓
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Game Engine & Play Resolver │
|
|
│ - Uses game models during play resolution │
|
|
│ - PD: Uses outcome probabilities from ratings │
|
|
│ - SBA: Uses simplified result charts │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Why Two Layers?
|
|
|
|
### Problem
|
|
- External APIs return **massive** nested JSON (team, division, cardset, rarity, etc.)
|
|
- Game engine only needs **minimal** data (name, positions, ratings)
|
|
- PD needs 3 API calls per player (player + batting ratings + pitching ratings)
|
|
|
|
### Solution
|
|
**Layer 1: API Models** - Match external structure exactly
|
|
- Full type safety when deserializing
|
|
- All nested objects as Pydantic models
|
|
- Easy to maintain when API changes
|
|
|
|
**Layer 2: Game Models** - Only what's needed for gameplay
|
|
- Clean, minimal data
|
|
- Fast serialization for WebSocket
|
|
- Easy to work with in game logic
|
|
|
|
**Mapper Layer** - Transform between them
|
|
- Extract essential fields
|
|
- Combine multiple API calls (PD: player + ratings)
|
|
- Normalize differences between leagues
|
|
|
|
---
|
|
|
|
## Detailed Documentation
|
|
|
|
This plan is split across multiple focused files:
|
|
|
|
### Core Specifications
|
|
|
|
1. **[API Models - PD](./player-model-specs/api-models-pd.md)**
|
|
- All PD API response models
|
|
- JSON examples
|
|
- Nested structures (Cardset, Rarity, MlbPlayer)
|
|
- Batting & pitching ratings
|
|
|
|
2. **[API Models - SBA](./player-model-specs/api-models-sba.md)**
|
|
- SBA API response models
|
|
- JSON examples
|
|
- Nested structures (Team, Manager, Division)
|
|
|
|
3. **[Game Models](./player-model-specs/game-models.md)**
|
|
- BasePlayer abstract class
|
|
- SbaPlayer (game-optimized)
|
|
- PdPlayer (game-optimized with ratings)
|
|
- Field selection rationale
|
|
|
|
4. **[Mappers & Factories](./player-model-specs/mappers-and-factories.md)**
|
|
- PlayerMapper (API → Game)
|
|
- PlayerFactory (create by league)
|
|
- Transformation logic
|
|
- Position normalization
|
|
|
|
5. **[API Client](./player-model-specs/api-client.md)**
|
|
- LeagueApiClient HTTP client
|
|
- Methods for each endpoint
|
|
- Error handling
|
|
- Usage examples
|
|
|
|
6. **[Testing Strategy](./player-model-specs/testing-strategy.md)**
|
|
- Unit test specifications
|
|
- Integration test plans
|
|
- Mock data strategy
|
|
|
|
---
|
|
|
|
## Implementation Order
|
|
|
|
### Phase 1: API Models (Day 1)
|
|
1. Create `api_models.py`
|
|
2. Define all PD API models
|
|
3. Define all SBA API models
|
|
4. Unit tests with real JSON samples
|
|
|
|
### Phase 2: Game Models (Day 1-2)
|
|
1. Create `player_models.py`
|
|
2. Define BasePlayer abstract
|
|
3. Define SbaPlayer
|
|
4. Define PdPlayer with ratings
|
|
5. Unit tests
|
|
|
|
### Phase 3: Mappers (Day 2)
|
|
1. Create PlayerMapper class
|
|
2. Implement PD mapping (combine 3 API calls)
|
|
3. Implement SBA mapping
|
|
4. Unit tests with transformation examples
|
|
|
|
### Phase 4: API Client (Day 2-3)
|
|
1. Create `api_client.py`
|
|
2. Implement LeagueApiClient with httpx
|
|
3. Implement PD endpoints
|
|
4. Implement SBA endpoints
|
|
5. Integration tests with mocked responses
|
|
|
|
### Phase 5: Integration (Day 3)
|
|
1. Update `league_configs.py` with API base URLs
|
|
2. Update PlayResolver to use PD ratings
|
|
3. End-to-end integration tests
|
|
4. Performance testing
|
|
|
|
---
|
|
|
|
## Key Design Decisions
|
|
|
|
### Decision 1: Two-Layer Approach
|
|
**Chosen**: API models + Game models (with mapper)
|
|
|
|
**Alternatives Considered**:
|
|
- Single model matching API (❌ too much unnecessary data in game engine)
|
|
- Single game model with manual dict parsing (❌ no type safety on API responses)
|
|
|
|
**Rationale**: Separation of concerns, type safety, performance
|
|
|
|
### Decision 2: Nested Pydantic Models
|
|
**Chosen**: Full Pydantic models for all nested objects (Team, Cardset, etc.)
|
|
|
|
**Alternatives Considered**:
|
|
- Dict[str, Any] for nested data (❌ loses type safety)
|
|
- Flatten everything to top level (❌ complex mapping logic)
|
|
|
|
**Rationale**: Type safety, IDE autocomplete, validation
|
|
|
|
### Decision 3: Position Handling
|
|
**Chosen**: Extract `pos_1` through `pos_8` → `positions: List[str]`
|
|
|
|
**Rationale**: Cleaner interface, easier to work with in game logic
|
|
|
|
### Decision 4: PD Ratings Storage
|
|
**Chosen**: Store ratings as part of PdPlayer model (vs L and vs R)
|
|
|
|
**Rationale**: Always needed for play resolution, keep together
|
|
|
|
### Decision 5: API Base URLs
|
|
**Actual URLs** (from your data):
|
|
- PD: `https://pd.manticorum.com/`
|
|
- SBA: `https://api.sba.manticorum.com/`
|
|
|
|
---
|
|
|
|
## File Structure
|
|
|
|
After implementation, project structure will be:
|
|
|
|
```
|
|
backend/app/
|
|
├── models/
|
|
│ ├── api_models.py # NEW - External API response models
|
|
│ ├── player_models.py # NEW - Game-optimized player models
|
|
│ ├── game_models.py # Existing - Game state models
|
|
│ └── db_models.py # Existing - Database ORM models
|
|
│
|
|
├── data/
|
|
│ ├── __init__.py
|
|
│ └── api_client.py # NEW - HTTP client for league APIs
|
|
│
|
|
├── config/
|
|
│ ├── __init__.py
|
|
│ ├── base_config.py # To create
|
|
│ ├── league_configs.py # To create (with API URLs)
|
|
│ └── result_charts.py # To create
|
|
│
|
|
└── core/
|
|
├── play_resolver.py # UPDATE - Use PD ratings for resolution
|
|
└── ... # Existing files
|
|
|
|
tests/
|
|
├── unit/
|
|
│ ├── models/
|
|
│ │ ├── test_api_models.py # NEW
|
|
│ │ └── test_player_models.py # NEW
|
|
│ └── data/
|
|
│ └── test_mappers.py # NEW
|
|
│
|
|
└── integration/
|
|
└── data/
|
|
└── test_api_client.py # NEW
|
|
```
|
|
|
|
---
|
|
|
|
## Success Criteria
|
|
|
|
### Functional Requirements
|
|
- ✅ Can fetch PD player from API and deserialize to PdPlayerApi
|
|
- ✅ Can fetch PD batting ratings and deserialize
|
|
- ✅ Can fetch PD pitching ratings and deserialize
|
|
- ✅ Can fetch SBA player from API and deserialize to SbaPlayerApi
|
|
- ✅ Can map PD API models → PdPlayer game model
|
|
- ✅ Can map SBA API models → SbaPlayer game model
|
|
- ✅ PlayerFactory creates correct player type by league_id
|
|
- ✅ Positions correctly extracted from pos_1-8 fields
|
|
- ✅ PD ratings correctly attached to PdPlayer
|
|
|
|
### Non-Functional Requirements
|
|
- ✅ All API models pass Pydantic validation with real JSON
|
|
- ✅ Unit test coverage > 90%
|
|
- ✅ API client handles errors gracefully
|
|
- ✅ Serialization/deserialization < 10ms per player
|
|
- ✅ Type hints validated by mypy
|
|
|
|
---
|
|
|
|
## Timeline & Effort
|
|
|
|
**Estimated Total**: 2-3 days (16-24 hours)
|
|
|
|
**Breakdown**:
|
|
- API Models: 4-6 hours
|
|
- Game Models: 3-4 hours
|
|
- Mappers: 2-3 hours
|
|
- API Client: 4-6 hours
|
|
- Testing: 3-5 hours
|
|
|
|
**Dependencies**:
|
|
- httpx library (already in requirements.txt ✅)
|
|
- Access to PD and SBA APIs (have URLs ✅)
|
|
- Real JSON samples (provided by user ✅)
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
1. Read detailed specifications in `player-model-specs/` directory
|
|
2. Start with API models (PD first, then SBA)
|
|
3. Implement game models
|
|
4. Create mapper layer
|
|
5. Build API client
|
|
6. Write comprehensive tests
|
|
7. Update PlayResolver to use ratings
|
|
|
|
---
|
|
|
|
**Current Status**: 📝 Planning Complete - Ready to start implementation
|
|
**Last Updated**: 2025-10-25
|
|
**Week**: 6 of Phase 2
|