# MTG Online Backend Python FastAPI application for processing MTGJSON card data and managing the MTG Online platform backend. ## Architecture ### Core Components The backend consists of several key layers: **Core Layer** (`app/core/`) - `settings.py` — Application configuration using pydantic-settings with environment variable overrides - `database.py` — Dual PostgreSQL engine setup (mtgonline app DB + mtgdata MTG cards DB) - `redis_client.py` — Redis connection and caching utilities **Models** (`app/models/`) - `models.py` — SQLAlchemy ORM models for application data (users, decks, auth) - `mtg_models.py` — ORM models for MTG card data **Services** (`app/services/`) - `mtgjson_manager.py` — Primary MTGJSON data pipeline (download, unzip, upsert) - `mtgjson_downloader.py` — HTTP client for MTGJSON API - `mtgjson_loader.py` — Data loading and transformation - `mtgjson_uploader.py` — Database upsert operations - `card_database.py` — Card data access layer - `game_server.py` — Game state management - `deck_parser.py` — Deck list parsing and validation **Routers** (`app/routers/`) - `auth.py` — JWT authentication endpoints - `users.py` — User management - `decks.py` — Deck CRUD operations - `rooms.py` — Game room management - `games.py` — Game state endpoints - `admin.py` — Admin tools - `card_router.py` — MTG card data API - `interactions.py` — Card interaction engine - `refresh.py` — MTGJSON data refresh endpoint - `ws.py` — WebSocket support **Schemas** (`app/schemas/`) - `schemas.py` — Pydantic models for request/response validation - `proto_messages.py` — Protocol buffer message definitions - `protocol_constants.py` — MTG protocol constants ### Data Flow ``` MTGJSON API (https://mtgjson.com/api/v5/) ↓ download MTGJSON files (AllPrintings.psql, AllIdentifiers.json, etc.) ↓ load/transform PostgreSQL (mtgdata database) ↓ query REST API / Swagger Docs ``` ## Database Setup ### Primary Database (mtgonline) - **Purpose**: Application data (users, decks, auth tokens) - **Connection**: `postgresql+asyncpg://mtgonline_user:mtgonline_password@postgres:5432/mtgonline` - **Port**: 5432 (internal), 5432:5432 (host) ### MTG Data Database (mtgdata) - **Purpose**: MTG card data, sets, refresh logs - **Connection**: `postgresql+asyncpg://mtgonline_user:mtgonline_password@mtgdata:5432/mtgdata` - **Port**: 5432 (internal), 5433:5432 (host) - **Tables**: - `mtg_sets` — Card sets metadata - `mtg_cards` — Individual card data - `mtg_refresh_log` — Refresh history and status ### Redis - **Purpose**: Caching, session management - **Connection**: `redis://redis:6379` - **Port**: 6379 (internal), 6379:6379 (host) ## MTGJSON Data Pipeline ### Downloaded Files The backend downloads these files from MTGJSON v5: - `AllPrintings.psql` — Main card data (PostgreSQL format) - `AllIdentifiers.json` — Card identifiers (Multiverse, Scryfall, etc.) - `Keywords.json` — Card keywords - `CardTypes.json` — Card type definitions - `AllDeckFiles.zip` — Deck files (must be unzipped) ### Refresh Logic 1. **On Startup**: Checks `mtg_refresh_log` for existing data 2. **If No Data**: Downloads and loads all MTGJSON files (may take minutes) 3. **Manual Refresh**: `POST /refresh` endpoint triggers immediate reload 4. **Logging**: All refreshes logged to `mtg_refresh_log` with status, timing, and counts ## Environment Variables | Variable | Default | Description | |----------|---------|-------------| | `DATABASE_URL` | `postgresql+asyncpg://mtgonline_user:mtgonline_password@postgres:5432/mtgonline` | Primary database | | `MTG_DATABASE_URL` | `postgresql+asyncpg://mtgonline_user:mtgonline_password@mtgdata:5432/mtgdata` | MTG data database | | `REDIS_URL` | `redis://redis:6379` | Redis connection | | `DATA_DIR` | `/app/data` | MTGJSON files directory | | `UPLOAD_DIR` | `/app/uploads` | User uploads directory | | `DEBUG` | `False` | Enable debug logging | | `LOG_LEVEL` | `INFO` | Logging level | | `SECRET_KEY` | `change-me-in-production` | JWT secret | | `JWT_SECRET_KEY` | `change-me-in-production` | JWT signing key | ## Running the Backend ### Docker (Recommended) ```bash # Build image cd backend docker build -t mtgonline-backend:latest . # Run with dependencies docker compose -f ../docker-compose.dev.yml up -d backend ``` ### Local Development ```bash cd backend # Create venv python -m venv venv source venv/bin/activate # Install dependencies pip install -r requirements.txt # Set environment variables export DATABASE_URL="postgresql+asyncpg://mtgonline_user:mtgonline_password@localhost:5432/mtgonline" export MTG_DATABASE_URL="postgresql+asyncpg://mtgonline_user:mtgonline_password@localhost:5433/mtgdata" export REDIS_URL="redis://localhost:6379" # Run server python -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 ``` ## API Endpoints ### Health & Status - `GET /health` — Health check with MTGJSON status - `GET /` — API info ### Authentication - `POST /auth/login` — User login - `POST /auth/register` — User registration - `POST /auth/refresh` — Refresh JWT - `GET /auth/me` — Current user ### Users - `GET /users/{user_id}` — Get user - `PATCH /users/{user_id}` — Update user - `POST /users/{user_id}/ban` — Ban user (admin) ### Decks - `GET /decks/` — List decks - `POST /decks/` — Create deck - `GET /decks/{deck_id}` — Get deck - `PATCH /decks/{deck_id}` — Update deck - `DELETE /decks/{deck_id}` — Delete deck ### MTG Cards - `GET /api/cards/` — Search cards - `GET /api/cards/{card_id}` — Get card - `GET /api/sets/` — List sets ### Admin - `GET /admin/users` — List all users - `GET /admin/bans` — List bans - `POST /admin/bans` — Create ban ### Data Management - `POST /refresh` — Trigger MTGJSON refresh ### WebSocket - `WS /ws/{room_id}` — Real-time game communication ## Utility Scripts Located in `scripts/`: - `download_mtgjson.py` — Manual MTGJSON download - `check_mtgjson_status.py` — Verify data freshness - `verify_mtgjson_data.py` — Data validation - `inspect_db.py` — Database inspection - `load_mtgjson_data.py` — Data loading ## Testing ```bash cd backend # Run tests pytest # Run with coverage pytest --cov=app --cov-report=html ``` ## Project Structure ``` backend/ ├── app/ │ ├── __init__.py │ ├── main.py # FastAPI app entry │ ├── core/ │ │ ├── settings.py # Configuration │ │ ├── database.py # Database engines │ │ └── redis_client.py # Redis utilities │ ├── models/ │ │ ├── models.py # App models │ │ └── mtg_models.py # MTG models │ ├── routers/ │ │ ├── auth.py # Auth endpoints │ │ ├── users.py # User endpoints │ │ ├── decks.py # Deck endpoints │ │ ├── rooms.py # Room endpoints │ │ ├── games.py # Game endpoints │ │ ├── admin.py # Admin endpoints │ │ ├── card_router.py # Card API │ │ ├── interactions.py # Card interactions │ │ ├── refresh.py # Data refresh │ │ └── ws.py # WebSocket │ ├── schemas/ │ │ ├── schemas.py # Pydantic models │ │ ├── proto_messages.py # Protocol messages │ │ └── protocol_constants.py │ └── services/ │ ├── mtgjson_manager.py # MTGJSON pipeline │ ├── mtgjson_downloader.py │ ├── mtgjson_loader.py │ ├── mtgjson_uploader.py │ ├── card_database.py # Card data access │ ├── game_server.py # Game logic │ └── deck_parser.py # Deck parsing ├── scripts/ # Utility scripts ├── tests/ # Test suite ├── Dockerfile # Container build ├── requirements.txt # Python dependencies ├── pyproject.toml # Ruff config ├── .env.example # Environment template └── setup_db.py # Database setup script ``` ## Troubleshooting ### Backend can't connect to databases - Verify all services are running: `docker compose -f ../docker-compose.dev.yml ps` - Check logs: `docker compose -f ../docker-compose.dev.yml logs backend` - Ensure environment variables match docker-compose.dev.yml ### MTGJSON download fails - Check network connectivity to mtgjson.com - Verify DATA_DIR has write permissions - Check disk space: `df -h` - Manual download: `python scripts/download_mtgjson.py` ### Database tables missing - Run initialization: `docker exec -i mtgdata psql -U mtgonline_user mtgdata < /path/to/scripts/init-mtgdata.sql` - Check tables: `docker exec mtgdata psql -U mtgonline_user mtgdata -c "\dt"` ## License MIT