Complete integration of position ratings system enabling X-Check defensive plays to use actual player ratings from PD API with intelligent fallbacks for SBA. **Live API Testing Verified**: ✅ - Endpoint: GET https://pd.manticorum.com/api/v2/cardpositions?player_id=8807 - Response: 200 OK, 7 positions retrieved successfully - Cache performance: 16,601x faster (API: 0.214s, Cache: 0.000s) - Data quality: Real defensive ratings (range 1-5, error 0-88) **Architecture Overview**: - League-aware: PD league fetches ratings from API, SBA uses defaults - StateManager integration: Defenders retrieved from lineup cache - Self-contained GameState: All data needed for X-Check in memory - Graceful degradation: Falls back to league averages if ratings unavailable **Files Created**: 1. app/services/pd_api_client.py (NEW) - PdApiClient class for PD API integration - Endpoint: GET /api/v2/cardpositions?player_id={id}&position={pos} - Async HTTP client using httpx (already in requirements.txt) - Optional position filtering: get_position_ratings(8807, ['SS', '2B']) - Returns List[PositionRating] for all positions player can play - Handles both list and dict response formats - Comprehensive error handling with logging 2. app/services/position_rating_service.py (NEW) - PositionRatingService with in-memory caching - get_ratings_for_card(card_id, league_id) - All positions - get_rating_for_position(card_id, position, league_id) - Specific position - Cache performance: >16,000x faster on hits - Singleton pattern: position_rating_service instance - TODO Phase 3E-Final: Upgrade to Redis 3. app/services/__init__.py (NEW) - Package exports for clean imports 4. test_pd_api_live.py (NEW) - Live API integration test script - Tests with real PD player 8807 (7 positions) - Verifies caching, filtering, GameState integration - Run: `python test_pd_api_live.py` 5. test_pd_api_mock.py (NEW) - Mock integration test for CI/CD - Demonstrates flow without API dependency 6. tests/integration/test_position_ratings_api.py (NEW) - Pytest integration test suite - Real API tests with player 8807 - Cache verification, SBA skip logic - Full end-to-end GameState flow **Files Modified**: 1. app/models/game_models.py - LineupPlayerState: Added position_rating field (Optional[PositionRating]) - GameState: Added get_defender_for_position(position, state_manager) - Uses StateManager's lineup cache to find active defender by position - Iterates through lineup.players to match position + is_active 2. app/config/league_configs.py - SbaConfig: Added supports_position_ratings() → False - PdConfig: Added supports_position_ratings() → True - Enables league-specific behavior without hardcoded conditionals 3. app/core/play_resolver.py - __init__: Added state_manager parameter for X-Check defender lookup - _resolve_x_check(): Replaced placeholder defender ratings with actual lookup - Uses league config to check if ratings supported - Fetches defender via state.get_defender_for_position() - Falls back to defaults (range=3, error=15) if ratings unavailable - Detailed logging for debugging rating lookups 4. app/core/game_engine.py - Added _load_position_ratings_for_lineup() method - Loads all position ratings at game start for PD league - Skips loading for SBA (league config check) - start_game(): Calls rating loader for both teams before marking active - PlayResolver instantiation: Now passes state_manager parameter - Logs: "Loaded X/9 position ratings for team Y" **X-Check Resolution Flow**: 1. League check: config.supports_position_ratings()? 2. Get defender: state.get_defender_for_position(pos, state_manager) 3. If PD + defender.position_rating exists: Use actual range/error 4. Else if defender found: Use defaults (range=3, error=15) 5. Else: Log warning, use defaults **Position Rating Loading (Game Start)**: 1. Check if league supports ratings (PD only) 2. Get lineup from StateManager cache 3. For each player: - Fetch rating from position_rating_service (with caching) - Set player.position_rating field 4. Cache API responses (16,000x faster on subsequent access) 5. Log success: "Loaded X/9 position ratings for team Y" **Live Test Results (Player 8807)**: ``` Position Range Error Innings CF 3 2 372 2B 3 8 212 SS 4 12 159 RF 2 2 74 LF 3 2 62 1B 4 0 46 3B 3 65 34 ``` **Testing**: - ✅ Live API: Player 8807 → 7 positions retrieved successfully - ✅ Caching: 16,601x performance improvement - ✅ League config: SBA=False, PD=True - ✅ GameState integration: Defender lookup working - ✅ Existing tests: 27/28 config tests passing (1 pre-existing URL failure) - ✅ Syntax validation: All files compile successfully **Benefits**: - ✅ X-Check now uses real defensive ratings in PD league - ✅ SBA league continues working with manual entry (uses defaults) - ✅ No breaking changes to existing functionality - ✅ Graceful degradation if API unavailable - ✅ In-memory caching reduces API calls by >99% - ✅ League-agnostic design via config system - ✅ Production-ready with live API verification **Phase 3E Status**: Main complete (85% → 90%) **Next**: Phase 3E-Final (WebSocket events, Redis upgrade, full defensive lineup) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|---|---|---|
| .claude | ||
| backend | ||
| frontend-pd | ||
| frontend-sba | ||
| .dockerignore | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| CLAUDE.md | ||
| docker-compose.yml | ||
| prd-web-scorecard-1.1.md | ||
| QUICKSTART.md | ||
| README.md | ||
Paper Dynasty Real-Time Game Engine
Web-based real-time multiplayer baseball simulation platform replacing the legacy Google Sheets system.
Project Structure
strat-gameplay-webapp/
├── backend/ # FastAPI game engine
├── frontend-sba/ # SBA League Nuxt frontend
├── frontend-pd/ # PD League Nuxt frontend
├── .claude/ # Claude AI implementation guides
├── docker-compose.yml # Full stack orchestration
└── README.md # This file
Two Development Workflows
Option 1: Local Development (Recommended for Daily Work)
Best for: Fast hot-reload, quick iteration, debugging
Services:
- ✅ Backend runs locally (Python hot-reload)
- ✅ Frontends run locally (Nuxt hot-reload)
- ✅ Redis in Docker (lightweight)
- ✅ PostgreSQL on your existing server
Setup:
-
Environment Setup
# Copy environment template cp .env.example .env # Edit .env with your database credentials and API keys -
Start Redis (in one terminal)
cd backend docker-compose up -
Start Backend (in another terminal)
cd backend source venv/bin/activate # or 'venv\Scripts\activate' on Windows python -m app.mainBackend will be available at http://localhost:8000
-
Start SBA Frontend (in another terminal)
cd frontend-sba npm run devSBA frontend will be available at http://localhost:3000
-
Start PD Frontend (in another terminal)
cd frontend-pd npm run devPD frontend will be available at http://localhost:3001
Advantages:
- ⚡ Instant hot-reload on code changes
- 🐛 Easy debugging (native debuggers work)
- 💨 Fast startup times
- 🔧 Simple to restart individual services
Option 2: Full Docker Orchestration
Best for: Integration testing, demos, production-like environment
Services:
- ✅ Everything runs in containers
- ✅ Consistent environment
- ✅ One command to start everything
Setup:
-
Environment Setup
# Copy environment template cp .env.example .env # Edit .env with your database credentials and API keys -
Start Everything
# From project root docker-compose upOr run in background:
docker-compose up -d -
View Logs
# All services docker-compose logs -f # Specific service docker-compose logs -f backend docker-compose logs -f frontend-sba -
Stop Everything
docker-compose down
Advantages:
- 🎯 Production-like environment
- 🚀 One-command startup
- 🔄 Easy to share with team
- ✅ CI/CD ready
Development Commands
Backend
cd backend
# Activate virtual environment
source venv/bin/activate
# Install dependencies
pip install -r requirements-dev.txt
# Run server
python -m app.main
# Run tests
pytest tests/ -v
# Code formatting
black app/ tests/
# Linting
flake8 app/ tests/
# Type checking
mypy app/
Frontend
cd frontend-sba # or frontend-pd
# Install dependencies
npm install
# Run dev server
npm run dev
# Build for production
npm run build
# Preview production build
npm run preview
# Lint
npm run lint
# Type check
npm run type-check
Database Setup
This project uses an existing PostgreSQL server. You need to manually create the database:
-- On your PostgreSQL server
CREATE DATABASE paperdynasty_dev;
CREATE USER paperdynasty WITH PASSWORD 'your-secure-password';
GRANT ALL PRIVILEGES ON DATABASE paperdynasty_dev TO paperdynasty;
Then update DATABASE_URL in .env:
DATABASE_URL=postgresql+asyncpg://paperdynasty:your-password@your-db-server:5432/paperdynasty_dev
Environment Variables
Copy .env.example to .env and configure:
Required
DATABASE_URL- PostgreSQL connection stringSECRET_KEY- Application secret key (at least 32 characters)DISCORD_CLIENT_ID- Discord OAuth client IDDISCORD_CLIENT_SECRET- Discord OAuth secretSBA_API_URL/SBA_API_KEY- SBA League API credentialsPD_API_URL/PD_API_KEY- PD League API credentials
Optional
REDIS_URL- Redis connection (auto-configured in Docker)CORS_ORIGINS- Allowed origins (defaults to localhost:3000,3001)
Available Services
When running, the following services are available:
| Service | URL | Description |
|---|---|---|
| Backend API | http://localhost:8000 | FastAPI REST API |
| Backend Docs | http://localhost:8000/docs | Interactive API documentation |
| SBA Frontend | http://localhost:3000 | SBA League web app |
| PD Frontend | http://localhost:3001 | PD League web app |
| Redis | localhost:6379 | Cache (not exposed via HTTP) |
Health Checks
# Backend health
curl http://localhost:8000/api/health
# Or visit in browser
open http://localhost:8000/api/health
Troubleshooting
Backend won't start
- Check
DATABASE_URLis correct in.env - Verify PostgreSQL database exists
- Ensure Redis is running (
docker-compose upin backend/) - Check logs for specific errors
Frontend won't connect to backend
- Verify backend is running at http://localhost:8000
- Check CORS settings in backend
.env - Clear browser cache and cookies
- Check browser console for errors
Docker containers won't start
- Ensure
.envfile exists with all required variables - Run
docker-compose downthendocker-compose upagain - Check
docker-compose logsfor specific errors - Verify no port conflicts (8000, 3000, 3001, 6379)
Database connection fails
- Verify PostgreSQL server is accessible
- Check firewall rules allow connection
- Confirm database and user exist
- Test connection with
psqldirectly
Documentation
- Full PRD: See
/prd-web-scorecard-1.1.md - Implementation Guide: See
.claude/implementation/00-index.md - Architecture Docs: See
.claude/implementation/directory
Tech Stack
Backend
- Framework: FastAPI (Python 3.11+)
- WebSocket: Socket.io
- Database: PostgreSQL 14+ with SQLAlchemy
- Cache: Redis 7
- Auth: Discord OAuth with JWT
Frontend
- Framework: Vue 3 + Nuxt 3
- Language: TypeScript
- Styling: Tailwind CSS
- State: Pinia
- WebSocket: Socket.io-client
Contributing
See .claude/implementation/ for detailed implementation guides and architecture documentation.
License
Proprietary - Paper Dynasty League System