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 overridesdatabase.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 APImtgjson_loader.py— Data loading and transformationmtgjson_uploader.py— Database upsert operationscard_database.py— Card data access layergame_server.py— Game state managementdeck_parser.py— Deck list parsing and validation
Routers (app/routers/)
auth.py— JWT authentication endpointsusers.py— User managementdecks.py— Deck CRUD operationsrooms.py— Game room managementgames.py— Game state endpointsadmin.py— Admin toolscard_router.py— MTG card data APIinteractions.py— Card interaction enginerefresh.py— MTGJSON data refresh endpointws.py— WebSocket support
Schemas (app/schemas/)
schemas.py— Pydantic models for request/response validationproto_messages.py— Protocol buffer message definitionsprotocol_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 metadatamtg_cards— Individual card datamtg_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 keywordsCardTypes.json— Card type definitionsAllDeckFiles.zip— Deck files (must be unzipped)
Refresh Logic
- On Startup: Checks
mtg_refresh_logfor existing data - If No Data: Downloads and loads all MTGJSON files (may take minutes)
- Manual Refresh:
POST /refreshendpoint triggers immediate reload - Logging: All refreshes logged to
mtg_refresh_logwith 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)
# 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
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 statusGET /— API info
Authentication
POST /auth/login— User loginPOST /auth/register— User registrationPOST /auth/refresh— Refresh JWTGET /auth/me— Current user
Users
GET /users/{user_id}— Get userPATCH /users/{user_id}— Update userPOST /users/{user_id}/ban— Ban user (admin)
Decks
GET /decks/— List decksPOST /decks/— Create deckGET /decks/{deck_id}— Get deckPATCH /decks/{deck_id}— Update deckDELETE /decks/{deck_id}— Delete deck
MTG Cards
GET /api/cards/— Search cardsGET /api/cards/{card_id}— Get cardGET /api/sets/— List sets
Admin
GET /admin/users— List all usersGET /admin/bans— List bansPOST /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 downloadcheck_mtgjson_status.py— Verify data freshnessverify_mtgjson_data.py— Data validationinspect_db.py— Database inspectionload_mtgjson_data.py— Data loading
Testing
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