# 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 <token>" \
  -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 <token>"
```

### Get Import Summary

```bash
curl http://localhost:5555/api/v1/card-import/summary \
  -H "Authorization: Bearer <token>"
```

### Delete Import

```bash
curl -X DELETE http://localhost:5555/api/v1/card-import/ \
  -H "Authorization: Bearer <token>"
```

## 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
