# MTG Online Backend A Python FastAPI application that processes Magic: The Gathering card data from [MTGJSON](https://mtgjson.com/) and stores it in PostgreSQL, with Redis for caching. ## Overview This project provides a backend API for a Magic: The Gathering Online platform. It downloads and processes MTGJSON v5 dataset dumps, loads them into a PostgreSQL database, and exposes REST endpoints for card data, user authentication, deck management, and game state. ### Key Features - **MTGJSON Data Pipeline** — Downloads `AllPrintings.psql`, `AllIdentifiers.json`, `Keywords.json`, `CardTypes.json`, and `AllDeckFiles.zip` from MTGJSON v5 on startup or via a `POST /refresh` endpoint. - **Dual PostgreSQL** — Two databases: `mtgonline` for the application (users, decks, auth) and `mtgdata` for MTG card data. - **Redis Caching** — Used for card lookup caching and interaction pipeline state. - **Card Import Feature** — Users can import their card collection (fuzzy matching enabled) for deckbuilding constraints. - **Deck Management** — Full deck CRUD with precedents, suggestions, and status tracking (DRAFT/FINAL). - **MTG Rules Engine** — Integrated in `backend/mtg_rules_engine/` for multiplayer game server (rules enforcement, card validation, keyword processing). - **REST API** — `/docs` (Swagger) available at runtime. ## Architecture ``` mtgonline/ ├── backend/ # FastAPI application │ ├── mtg_rules_engine/ # MTG rules engine (rules enforcement for multiplayer) │ │ ├── engine.py # Core game engine │ │ ├── rules_engine.py # Rules engine core │ │ ├── keywords.py # Card keywords │ │ ├── keywords_db.py # Keywords database │ │ ├── keyword_validator.py # Keyword validation │ │ ├── validator.py # Card validation │ │ ├── updater.py # Engine updater │ │ ├── update_check.py # Update checker │ │ ├── test_engine.py # Engine tests │ │ └── README.md # Rules engine docs │ ├── app/ │ │ ├── core/ # Settings, database engines, Redis client │ │ ├── models/ # SQLAlchemy ORM models (app + MTG) │ │ ├── routers/ # API route modules │ │ ├── schemas/ # Pydantic request/response schemas │ │ ├── services/ # Business logic (MTGJSON manager, card DB, game server) │ │ └── main.py # FastAPI app entry point │ ├── scripts/ # Utility scripts (downloads, migrations, checks) │ ├── Dockerfile │ └── requirements.txt ├── docker-compose.dev.yml # Development stack (Postgres x2, Redis, Backend) ├── docker-compose.yml # Production stack ├── scripts/ # Shared utility scripts └── README.md ``` ### Data Flow 1. **On startup**, the backend connects to PostgreSQL (both instances) and Redis. 2. It checks `mtg_refresh_log` in the `mtgdata` database for existing data. 3. If no data exists, it downloads MTGJSON files from `https://mtgjson.com/api/v5/`, unzips if needed, and upserts them into `mtgdata` tables (`mtg_sets`, `mtg_cards`, etc.). 4. The data is then available via REST endpoints. ## API Endpoints ### Card Import (`/api/v1/card-import/`) | Method | Endpoint | Description | |--------|----------|-------------| | `GET` | `/api/v1/card-import/status` | Get current card import status | | `POST` | `/api/v1/card-import/` | Import/update card collection | | `DELETE` | `/api/v1/card-import/` | Delete card import | | `GET` | `/api/v1/card-import/summary` | Get import summary with match results | **Card Import Request Body:** ```json { "card_names": ["Lightning Bolt", "Shock", "Thoughtseize"] } ``` **Card Import Response:** ```json { "message": "Imported 3 cards successfully", "card_count": 3, "card_names": ["Lightning Bolt", "Shock", "Thoughtseize"], "imported_at": "2026-07-24T04:12:00" } ``` ### User Data Endpoints (`/api/v1/user-data/`) | Method | Endpoint | Description | |--------|----------|-------------| | `GET` | `/api/v1/user-data/profile` | Get user profile | | `PUT` | `/api/v1/user-data/profile` | Update user profile | | `GET` | `/api/v1/user-data/collection` | Get user card collection | | `GET` | `/api/v1/user-data/groups` | List user groups | | `GET` | `/api/v1/user-data/networks` | List user networks | | `GET` | `/api/v1/user-data/preferences` | Get user preferences | | `PUT` | `/api/v1/user-data/preferences` | Update user preferences | | `GET` | `/api/v1/user-data/activity` | Get user activity log | | `GET` | `/api/v1/user-data/replays` | List user replays | | `GET` | `/api/v1/user-data/replays/{replay_id}` | Get replay details | ### Deck Management Endpoints | Method | Endpoint | Description | |--------|----------|-------------| | `GET` | `/api/v1/decks/` | List user decks | | `POST` | `/api/v1/decks/` | Create new deck | | `GET` | `/api/v1/decks/{deck_id}` | Get deck details | | `PUT` | `/api/v1/decks/{deck_id}` | Update deck | | `DELETE` | `/api/v1/decks/{deck_id}` | Delete deck | | `POST` | `/api/v1/decks/{deck_id}/cards` | Add card to deck | | `PUT` | `/api/v1/decks/{deck_id}/cards/{card_id}` | Update deck card | | `DELETE` | `/api/v1/decks/{deck_id}/cards/{card_id}` | Remove card from deck | | `GET` | `/api/v1/decks/{deck_id}/cards` | List deck cards | | `POST` | `/api/v1/decks/{deck_id}/finalize` | Finalize deck (DRAFT → FINAL) | | `POST` | `/api/v1/decks/search/cards` | Search cards for deckbuilding | | `GET` | `/api/v1/decks/precedents/` | List deck precedents | | `POST` | `/api/v1/decks/precedents/` | Create precedent | | `GET` | `/api/v1/decks/precedents/{precedent_id}` | Get precedent details | | `POST` | `/api/v1/decks/precedents/{precedent_id}/use` | Use/clone precedent | | `GET` | `/api/v1/decks/suggestions/` | List card suggestions | | `POST` | `/api/v1/decks/suggestions/` | Add card suggestion | ## Quick Start ### Prerequisites - Docker and Docker Compose ### Run the Stack ```bash cd /home/wall-o/projects/mtgonline # Start all services (Postgres x2, Redis, Backend) docker compose -f docker-compose.dev.yml up -d # View logs docker compose -f docker-compose.dev.yml logs -f backend ``` The backend will automatically download MTGJSON data on first startup (this may take several minutes). ### Access | Service | Address | |---------------|---------------------| | Backend API | `http://localhost:5555` | | Swagger Docs | `http://localhost:5555/docs` | | Health Check | `http://localhost:5555/health` | | PostgreSQL (app) | `localhost:5432` | | PostgreSQL (MTG) | `localhost:5433` | | Redis | `localhost:6379` | ### Manual Data Refresh ```bash # Trigger a manual MTGJSON refresh curl -X POST http://localhost:5555/refresh ``` ## Card Import Feature Users can import their card collection to enable deckbuilding with owned cards. The feature includes fuzzy matching for typos. ### Import Cards ```bash curl -X POST http://localhost:5555/api/v1/card-import/ \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "card_names": ["Lightning Bolt", "Shock", "Thoughtseize"] }' ``` ### Check Import Status ```bash curl http://localhost:5555/api/v1/card-import/status \ -H "Authorization: Bearer " ``` ### Get Import Summary ```bash curl http://localhost:5555/api/v1/card-import/summary \ -H "Authorization: Bearer " ``` ### Delete Import ```bash curl -X DELETE http://localhost:5555/api/v1/card-import/ \ -H "Authorization: Bearer " ``` ## Environment Variables | Variable | Default | Description | |----------|---------|-------------| | `DATABASE_URL` | `postgresql+asyncpg://mtgonline_user:mtgonline_password@postgres:5432/mtgonline` | Primary database connection | | `MTG_DATABASE_URL` | `postgresql+asyncpg://mtgonline_user:mtgonline_password@mtgdata:5432/mtgdata` | MTG data database connection | | `REDIS_URL` | `redis://redis:6379` | Redis connection | | `DATA_DIR` | `/app/data` | Directory for MTGJSON files | | `DEBUG` | `False` | Enable debug logging | ## Docker Cleanup ```bash # Stop and remove all containers docker compose -f docker-compose.dev.yml down # Remove images and prune docker system prune -a --volumes ``` ## License MIT