- Create tests/conftest.py with testcontainers for Postgres and Redis
- Auto-detect Docker Desktop socket and disable Ryuk for compatibility
- Update tests/db/conftest.py and tests/services/conftest.py to use shared fixtures
- Fix test_resolve_effect_logs_exceptions: logger was disabled by pytest
- Fix test_save_and_load_with_real_redis: use redis_url fixture
- Minor lint fix in engine_validation.py
Tests now auto-start containers on run - no need for `docker compose up`
All 1199 tests passing.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
UNSET sentinel pattern:
- Add UNSET sentinel in protocols.py for nullable field updates
- Fix inability to clear deck description (UNSET=keep, None=clear)
- Fix repository inability to clear validation_errors
Starter deck improvements:
- Remove unused has_starter_deck from CollectionService
- Add deprecation notes to old starter deck methods
Validation improvements:
- Add energy type validation in deck_validator.py
- Add energy type validation in deck schemas
- Add VALID_ENERGY_TYPES constant
Game loading fix:
- Fix get_deck_for_game silently skipping invalid cards
- Now raises ValueError with clear error message
Tests:
- Add TestEnergyTypeValidation test class
- Add TestGetDeckForGame test class
- Add tests for validate_energy_types utility function
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Critical fixes:
- Add admin API key authentication for admin endpoints
- Add race condition protection via unique partial index for starter decks
- Make starter deck selection atomic with combined method
Moderate fixes:
- Fix DI pattern violation in validate_deck_endpoint
- Add card ID format validation (regex pattern)
- Add card quantity validation (1-99 range)
- Fix exception chaining with from None (B904)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Complete OAuth-based authentication with JWT session management:
Core Services:
- JWT service for access/refresh token creation and verification
- Token store with Redis-backed refresh token revocation
- User service for CRUD operations and OAuth-based creation
- Google and Discord OAuth services with full flow support
API Endpoints:
- GET /api/auth/{google,discord} - Start OAuth flows
- GET /api/auth/{google,discord}/callback - Handle OAuth callbacks
- POST /api/auth/refresh - Exchange refresh token for new access token
- POST /api/auth/logout - Revoke single refresh token
- POST /api/auth/logout-all - Revoke all user sessions
- GET/PATCH /api/users/me - User profile management
- GET /api/users/me/linked-accounts - List OAuth providers
- GET /api/users/me/sessions - Count active sessions
Infrastructure:
- Pydantic schemas for auth/user request/response models
- FastAPI dependencies (get_current_user, get_current_premium_user)
- OAuthLinkedAccount model for multi-provider support
- Alembic migration for oauth_linked_accounts table
Dependencies added: email-validator, fakeredis (dev), respx (dev)
84 new tests, 1058 total passing
- Rename data/cards/ to data/raw/ for scraped data
- Add data/definitions/ as authoritative card data source
- Add convert_cards.py script to transform raw -> definitions
- Generate 378 card definitions (344 Pokemon, 24 Trainers, 10 Energy)
- Add CardService for loading and querying card definitions
- In-memory indexes for fast lookups by type, set, pokemon_type
- search() with multiple filter criteria
- get_all_cards() for GameEngine integration
- Add SetInfo model for set metadata
- Update Attack model with damage_display field for variable damage
- Update CardDefinition with image_path, illustrator, flavor_text
- Add 45 tests (21 converter + 24 CardService)
- Update scraper output path to data/raw/
Card data is JSON-authoritative (no database) to support offline fork goal.