Files
Commander-Deck-App-backup/PROJECT_STATE.md
T

5.8 KiB

MTG Commander Deck Builder — Project State

Overview

Self-hosted, AI-powered Magic: The Gathering Commander deck builder. Runs as a Docker Compose stack managed via Portainer, exposed externally via Cloudflare Tunnel + Traefik.

Stack: FastAPI (Python 3.12) · React/Vite (TypeScript) · PostgreSQL 16 · Redis 7 · Nginx · Docker Compose


Build Progress

Steps 1-7 — Complete

All backend, frontend, and deployment steps are complete. App is live and accessible.


Live Deployment


Deployment Architecture

Networking

  • Cloudflare Tunnel → http://localhost:80 → Traefik → nginx (traefik-public network)
  • Traefik routes by hostname label using traefik.docker.network=traefik-public
  • All other services (backend, db, cache, frontend) on commander-forge_internal network
  • Cloudflared runs on host network — must use localhost not container hostnames

Image Management

All three custom images are built manually on the server and Portainer uses pre-built images:

sudo docker build -t commander-forge-nginx:latest --no-cache --pull http://192.168.0.62:3001/Dan/Commander-Deck-App.git#master:nginx
sudo docker build -t commander-forge-frontend:latest --no-cache http://192.168.0.62:3001/Dan/Commander-Deck-App.git#master:frontend
sudo docker build -t commander-forge-backend:latest --no-cache --pull http://192.168.0.62:3001/Dan/Commander-Deck-App.git#master:backend

After rebuilding, redeploy the stack in Portainer to pick up the new images.

Why pre-built images?

Portainer's repository-based builds aggressively cache the git source. Even with --no-cache --pull, Portainer's internal git clone cache serves stale code. Pre-built images bypass this entirely.


Known Fixes Applied

  • passlib replaced with bcrypt==4.1.3 in requirements.txt and security.py
  • npm ci replaced with npm install in frontend Dockerfile (Windows-generated lockfile missing Linux binaries)
  • package-lock.json added to repo
  • nginx baked into its own image via nginx/Dockerfile (Portainer pre-creates volume mount paths as directories)
  • docker-compose.yml uses Traefik labels + traefik.docker.network=traefik-public
  • DATABASE_URL and REDIS_URL passed explicitly as env vars
  • UserRole enum members renamed to lowercase (pending/approved/admin) to match database values
  • admin_bootstrap.py and deps.py updated to use lowercase UserRole.admin, UserRole.pending, etc.
  • Portainer git source caches aggressively — always use --no-cache --pull and pre-built images

Infrastructure

Service URL Notes
Commander Forge https://commander.bussenet.ca Main app
Portainer https://portainer.bussenet.ca Stack management
Gitea https://gitea.bussenet.ca Primary git (SSH port 2222)
GitHub mirror https://github.com/danbusse/Commander-Deck-App Private, Claude's file access path
Vault https://vault.bussenet.ca Secrets store
Portainer MCP https://mcp-portainer.bussenet.ca/sse Custom image with entrypoint fix

Portainer MCP

Custom mcp-portainer:latest image built from ghcr.io/serraniel/portainer-mcp-docker:http with a fixed entrypoint that passes -- before the portainer-mcp command. Tools written to /tmp/tools.yaml. PORTAINER_SERVER must be set without protocol prefix (e.g. 192.168.0.62:9443) since the MCP binary always prepends https://.

Cloudflare Tunnel

  • Tunnel ID: 3a032a2b-aa42-46a2-b749-e3fa9166ac59
  • Only region1 (198.41.192.x) is reachable — region2 (198.41.200.x) times out (ISP routing issue, outside our control)
  • Tunnel maintains 1 of 4 connections; services are accessible but logs show constant reconnect attempts
  • Cloudflared runs on host network — all tunnel ingress entries use localhost not container IPs

GitHub API Access

Claude can read/write files to the GitHub mirror using token stored in Vault at secret/github.claude-api-token. This is the primary mechanism for Claude to update project files between sessions.


Environment Variables (Portainer stack env)

Variable Value Notes
SECRET_KEY changeme ⚠️ Needs replacing
POSTGRES_PASSWORD changeme ⚠️ Needs replacing
POSTGRES_DB mtgdb
POSTGRES_USER mtg
DATABASE_URL postgresql+asyncpg://mtg:changeme@db:5432/mtgdb ⚠️ Update with new password
REDIS_URL redis://cache:6379
ANTHROPIC_API_KEY (in Vault at secret/anthropic)
ADMIN_EMAIL busse.daniel@gmail.com
ADMIN_PASSWORD Admin1234

Git Workflow

Two remotes are configured:

  • origin → Gitea (ssh://git@192.168.0.62:2222/Dan/Commander-Deck-App.git)
  • github → GitHub (https://github.com/danbusse/Commander-Deck-App.git)

Always push to both:

git push origin master
git push github master

Next Session — Start Here

Priority 1 — Harden credentials:

  • Generate new SECRET_KEY: openssl rand -hex 32
  • Set strong POSTGRES_PASSWORD
  • Update DATABASE_URL to match
  • Update these in Portainer stack env vars

Priority 2 — Test end to end:

  • Try building a deck via Generate mode
  • Test collection import with an Archidekt export
  • Verify admin approval flow for a new registered user

Priority 3 — Commit docker-compose.yml changes to repo: The docker-compose.yml in the repo still has build: directives. Update it to use image: directives to match the actual deployment approach:

  backend:
    image: commander-forge-backend:latest
  frontend:
    image: commander-forge-frontend:latest
  nginx:
    image: commander-forge-nginx:latest