Files
mtgonline/backend/API_DOCUMENTATION.md
akadmin c42d7ca0e1 feat: implement user data schema and API endpoints
- Add Alembic migration setup with async configuration
- Create 16 user data models (users, decks, cards, replays, etc.)
- Implement comprehensive API endpoints with JWT auth
- Add replay, card collection, group, network, preferences, and activity log routers
- Include API documentation and migration test plan
- Update Dockerfile to run migrations on startup
2026-07-23 03:23:54 +00:00

15 KiB

User Data API Endpoints - Complete Documentation

Overview

The User Data API provides comprehensive CRUD operations for:

  • Session Management - User authentication sessions
  • Deck Versions - Deck version history and rollback
  • Game Replays - Game recording and playback
  • Game Outcomes - Win/loss tracking with ratings
  • User Statistics - Denormalized stats (games, wins, streaks)
  • Card Collection - User-owned cards with condition/language
  • Wishlist - Cards users want to acquire
  • Groups - User groups with roles and chat
  • Networks - Extended social connections
  • Preferences - User settings and preferences
  • Activity Log - Audit trail with JSONB metadata

Base URL

/api/v1/user-data

Authentication

All endpoints require a valid JWT token in the Authorization header:

Authorization: Bearer <your-jwt-token>

1. Session Management

Get Active Sessions

GET /sessions/me

Response:

[
  {
    "cleaned_count": 2,
    "message": "Found 2 active sessions"
  }
]

Cleanup Expired Sessions

DELETE /sessions/cleanup

Response:

{
  "message": "Cleaned 5 expired sessions"
}

Logout Current Session

POST /sessions/logout

Response:

{
  "message": "Logged out successfully"
}

2. Deck Versions

Create Deck Version

POST /decks/{deck_id}/versions
Content-Type: application/json

{
  "content": "4x Thoughtseize, 4x Lightning Bolt, ...",
  "status": "DRAFT",
  "comment": "Updated for meta change"
}

Response:

{
  "id": 1,
  "deck_id": 42,
  "version_number": 3,
  "content": "4x Thoughtseize, ...",
  "status": "DRAFT",
  "comment": "Updated for meta change",
  "created_at": "2026-01-01T12:00:00Z"
}

Get Deck Versions

GET /decks/{deck_id}/versions?page=1&page_size=50

Response:

{
  "versions": [...],
  "total": 10,
  "page": 1,
  "page_size": 50,
  "total_pages": 1
}

Update Deck Version

PATCH /decks/{deck_id}/versions/{version_id}
Content-Type: application/json

{
  "status": "FINAL",
  "comment": "Ready for tournament"
}

Delete Deck Version

DELETE /decks/{deck_id}/versions/{version_id}

3. Game Replays

Create Game Replay

POST /replays
Content-Type: application/json

{
  "game_uuid": "550e8400-e29b-41d4-a716-446655440000",
  "room_id": 1,
  "game_type": "Draft",
  "format": "Standard",
  "duration_seconds": 1800,
  "start_time": "2026-01-01T12:00:00Z",
  "end_time": "2026-01-01T12:30:00Z",
  "status": "COMPLETED",
  "replay_data": {
    "turns": [...],
    "deck": {...}
  }
}

Response:

{
  "id": 1,
  "game_uuid": "550e8400-...",
  "room_id": 1,
  "game_type": "Draft",
  "format": "Standard",
  "duration_seconds": 1800,
  "start_time": "2026-01-01T12:00:00Z",
  "end_time": "2026-01-01T12:30:00Z",
  "status": "COMPLETED",
  "replay_data": {...},
  "created_at": "2026-01-01T12:30:00Z",
  "updated_at": "2026-01-01T12:30:00Z",
  "players": [...]
}

Get Game Replays

GET /replays?page=1&page_size=50&user_id=42&status_filter=COMPLETED

Response:

{
  "replays": [...],
  "total": 100,
  "page": 1,
  "page_size": 50,
  "total_pages": 2
}

Get Replay Players

GET /replays/{replay_id}/players

Response:

[
  {
    "id": 1,
    "user_id": 42,
    "deck_id": 10,
    "position": 1,
    "won": true,
    "lost": false,
    "concession": false,
    "turn_one": false
  }
]

4. Game Outcomes

Create Game Outcome

POST /outcomes
Content-Type: application/json

{
  "game_uuid": "550e8400-e29b-41d4-a716-446655440000",
  "outcome": "WIN",
  "opponent_id": 99,
  "format": "Standard",
  "rating_before": 1500,
  "rating_after": 1525,
  "rating_change": 25
}

Response:

{
  "id": 1,
  "user_id": 42,
  "game_uuid": "550e8400-...",
  "outcome": "WIN",
  "opponent_id": 99,
  "format": "Standard",
  "rating_before": 1500,
  "rating_after": 1525,
  "rating_change": 25,
  "created_at": "2026-01-01T12:30:00Z"
}

Get Game Outcomes

GET /outcomes?page=1&page_size=50&user_id=42

5. User Statistics

Get User Statistics

GET /statistics/{user_id}

Response:

{
  "user_id": 42,
  "total_games": 150,
  "total_wins": 90,
  "total_losses": 55,
  "total_concessions": 5,
  "win_rate": 60.0,
  "current_streak": 3,
  "best_streak": 8,
  "average_rating": 1450.5,
  "last_game_date": "2026-01-01T12:00:00Z",
  "updated_at": "2026-01-01T12:30:00Z"
}

Update User Statistics

POST /statistics/update
Content-Type: application/json

{
  "user_id": 42,
  "outcome": "WIN"
}

Response:

{
  "user_id": 42,
  "total_games": 151,
  "total_wins": 91,
  "total_losses": 55,
  "win_rate": 60.26,
  "current_streak": 4,
  "updated_at": "2026-01-01T12:35:00Z"
}

6. Card Collection

Add Card to Collection

POST /collection
Content-Type: application/json

{
  "card_id": 12345,
  "quantity": 4,
  "condition": "NEAR_MINT",
  "language": "EN",
  "is_foil": true,
  "is_alt_art": false,
  "acquired_date": "2026-01-01T00:00:00Z",
  "acquisition_method": "Bought",
  "notes": "From card shop"
}

Response:

{
  "id": 1,
  "user_id": 42,
  "card_id": 12345,
  "quantity": 4,
  "condition": "NEAR_MINT",
  "language": "EN",
  "is_foil": true,
  "is_alt_art": false,
  "acquired_date": "2026-01-01T00:00:00Z",
  "acquisition_method": "Bought",
  "notes": "From card shop",
  "created_at": "2026-01-01T12:00:00Z",
  "updated_at": "2026-01-01T12:00:00Z"
}

Get Card Collection

GET /collection?page=1&page_size=50&is_foil=true&is_alt_art=false

Response:

{
  "cards": [...],
  "total": 500,
  "page": 1,
  "page_size": 50,
  "total_pages": 10
}

Update Card in Collection

PATCH /collection/{card_id}
Content-Type: application/json

{
  "quantity": 3,
  "condition": "EX",
  "notes": "Slightly worn"
}

Remove Card from Collection

DELETE /collection/{card_id}

7. Wishlist

Add to Wishlist

POST /wishlist
Content-Type: application/json

{
  "card_id": 12345,
  "max_price": 50.00,
  "notes": "Looking for foil version"
}

Response:

{
  "id": 1,
  "user_id": 42,
  "card_id": 12345,
  "max_price": 50.00,
  "notes": "Looking for foil version",
  "created_at": "2026-01-01T12:00:00Z"
}

Get Wishlist

GET /wishlist?page=1&page_size=50

Update Wishlist Item

PATCH /wishlist/{item_id}
Content-Type: application/json

{
  "max_price": 75.00,
  "notes": "Willing to pay more"
}

Remove from Wishlist

DELETE /wishlist/{item_id}

8. Groups

Create Group

POST /groups
Content-Type: application/json

{
  "name": "Standard Players",
  "description": "Casual Standard players",
  "is_public": true,
  "max_members": 50
}

Response:

{
  "id": 1,
  "name": "Standard Players",
  "description": "Casual Standard players",
  "owner_id": 42,
  "is_public": true,
  "max_members": 50,
  "created_at": "2026-01-01T12:00:00Z",
  "updated_at": "2026-01-01T12:00:00Z",
  "member_count": 1,
  "is_member": true
}

Get User Groups

GET /groups?page=1&page_size=50&is_public=true

Response:

{
  "groups": [...],
  "total": 5,
  "page": 1,
  "page_size": 50,
  "total_pages": 1
}

Update Group

PATCH /groups/{group_id}
Content-Type: application/json

{
  "description": "Updated description",
  "max_members": 100
}

Delete Group

DELETE /groups/{group_id}

9. Group Members

Add Group Member

POST /groups/{group_id}/members
Content-Type: application/json

{
  "user_id": 99,
  "role": "MEMBER"
}

Response:

{
  "message": "Member added",
  "member_id": 5
}

Update Group Member Role

PATCH /groups/{group_id}/members/{member_id}
Content-Type: application/json

{
  "role": "ADMIN"
}

Response:

{
  "message": "Member role updated"
}

Remove Group Member

DELETE /groups/{group_id}/members/{member_id}

10. Group Chat Messages

Send Group Message

POST /groups/{group_id}/messages
Content-Type: application/json

{
  "message": "Hey everyone! Ready for a game?"
}

Response:

{
  "id": 1,
  "group_id": 1,
  "sender_id": 42,
  "sender_username": "player42",
  "message": "Hey everyone! Ready for a game?",
  "created_at": "2026-01-01T12:00:00Z"
}

Get Group Messages

GET /groups/{group_id}/messages?page=1&page_size=50

Response:

{
  "messages": [...],
  "total": 25,
  "page": 1,
  "page_size": 50,
  "total_pages": 1
}

11. Networks

Create Network

POST /networks
Content-Type: application/json

{
  "name": "MTG Enthusiasts",
  "description": "Friends who play Magic",
  "is_public": true
}

Response:

{
  "id": 1,
  "name": "MTG Enthusiasts",
  "description": "Friends who play Magic",
  "creator_id": 42,
  "is_public": true,
  "created_at": "2026-01-01T12:00:00Z",
  "member_count": 1,
  "is_member": true
}

Get User Networks

GET /networks?page=1&page_size=50

Update Network

PATCH /networks/{network_id}
Content-Type: application/json

{
  "description": "Updated network description"
}

Delete Network

DELETE /networks/{network_id}

12. Network Members

Add Network Member

POST /networks/{network_id}/members
Content-Type: application/json

{
  "user_id": 99,
  "role": "MEMBER"
}

Response:

{
  "message": "Member added",
  "member_id": 3
}

13. User Preferences

Get User Preferences

GET /preferences

Response:

{
  "user_id": 42,
  "theme": "light",
  "notifications_enabled": true,
  "email_notifications": true,
  "auto_save_decks": true,
  "default_format": "standard",
  "language": "EN",
  "updated_at": "2026-01-01T12:00:00Z"
}

Update User Preferences

PATCH /preferences
Content-Type: application/json

{
  "theme": "dark",
  "notifications_enabled": false,
  "default_format": "modern"
}

Response:

{
  "user_id": 42,
  "theme": "dark",
  "notifications_enabled": false,
  "email_notifications": true,
  "auto_save_decks": true,
  "default_format": "modern",
  "language": "EN",
  "updated_at": "2026-01-01T12:05:00Z"
}

14. Activity Log

Get Activity Log

GET /activity?page=1&page_size=50&activity_type=LOGIN

Response:

{
  "entries": [
    {
      "id": 1,
      "user_id": 42,
      "activity_type": "LOGIN",
      "activity_data": {"ip": "192.168.1.1"},
      "ip_address": "192.168.1.1",
      "created_at": "2026-01-01T12:00:00Z"
    }
  ],
  "total": 100,
  "page": 1,
  "page_size": 50,
  "total_pages": 2
}

Error Responses

All endpoints return consistent error responses:

{
  "detail": "Error message"
}

Common Error Codes

Status Code Description
400 Bad Request - Invalid input
401 Unauthorized - Missing or invalid token
403 Forbidden - Insufficient permissions
404 Not Found - Resource doesn't exist
409 Conflict - Resource already exists
500 Internal Server Error

Testing with cURL

Example: Create a Deck Version

curl -X POST "http://localhost:8000/api/v1/user-data/decks/42/versions" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "4x Thoughtseize, 4x Lightning Bolt, ...",
    "status": "DRAFT",
    "comment": "Updated for meta"
  }'

Example: Get Card Collection

curl "http://localhost:8000/api/v1/user-data/collection?page=1&page_size=10" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Example: Add to Wishlist

curl -X POST "http://localhost:8000/api/v1/user-data/wishlist" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "card_id": 12345,
    "max_price": 50.00,
    "notes": "Looking for foil"
  }'

Available Endpoints Summary

Method Endpoint Description
GET /sessions/me Get active sessions
DELETE /sessions/cleanup Cleanup expired sessions
POST /sessions/logout Logout current session
POST /decks/{id}/versions Create deck version
GET /decks/{id}/versions Get deck versions
PATCH /decks/{id}/versions/{vid} Update deck version
DELETE /decks/{id}/versions/{vid} Delete deck version
POST /replays Create game replay
GET /replays Get game replays
GET /replays/{id} Get specific replay
PATCH /replays/{id} Update replay
DELETE /replays/{id} Delete replay
POST /replays/{id}/players Add player to replay
GET /replays/{id}/players Get replay players
POST /outcomes Create game outcome
GET /outcomes Get game outcomes
GET /statistics/{id} Get user statistics
POST /statistics/update Update user statistics
POST /collection Add card to collection
GET /collection Get card collection
PATCH /collection/{id} Update card
DELETE /collection/{id} Remove card
POST /wishlist Add to wishlist
GET /wishlist Get wishlist
PATCH /wishlist/{id} Update wishlist item
DELETE /wishlist/{id} Remove from wishlist
POST /groups Create group
GET /groups Get user groups
GET /groups/{id} Get specific group
PATCH /groups/{id} Update group
DELETE /groups/{id} Delete group
POST /groups/{id}/members Add group member
PATCH /groups/{id}/members/{mid} Update member role
DELETE /groups/{id}/members/{mid} Remove member
POST /groups/{id}/messages Send group message
GET /groups/{id}/messages Get group messages
POST /networks Create network
GET /networks Get user networks
GET /networks/{id} Get specific network
PATCH /networks/{id} Update network
DELETE /networks/{id} Delete network
POST /networks/{id}/members Add network member
GET /preferences Get user preferences
PATCH /preferences Update preferences
GET /activity Get activity log

Next Steps

  1. Test endpoints with curl or Postman
  2. Create integration tests for each endpoint
  3. Add rate limiting for production
  4. Implement pagination optimization for large datasets
  5. Add search functionality for cards and decks
  6. Create webhook endpoints for real-time notifications