mtg_python_deckbuilder/DOCKER.md

21 KiB
Raw Permalink Blame History

Docker Guide

Spin up the MTG Python Deckbuilder inside containers. The image defaults to the Web UI; switch to the CLI/headless runner by flipping environment variables. All commands assume Windows PowerShell.

Windows note: PowerShell uses ${PWD} for the current directory in volume mounts; CMD uses %cd%. The commands below use PowerShell syntax. If you are on Linux/macOS, replace ${PWD} with $(pwd) and backtick line continuations with backslashes.

Build a Deck (Web UI)

  • Build the image (first run only) and start the web service in detached mode:
docker compose up --build --no-deps -d web
  • Open http://localhost:8080 to use the browser experience. First launch seeds data, downloads the latest card catalog, and tags cards automatically (WEB_AUTO_SETUP=1, WEB_TAG_PARALLEL=1, WEB_TAG_WORKERS=4 in docker-compose.yml).

  • Stop or restart the service when you're done:

docker compose stop web
docker compose start web

Then open http://localhost:8080

Volumes are the same as the CLI service, so deck exports/logs/configs persist in your working folder. The app serves a favicon at /favicon.ico and exposes a health endpoint at /healthz. Compare view offers a Copy summary button to copy a plain-text diff of two runs. The sidebar has a subtle depth shadow for clearer separation.

Web UI feature highlights:

  • Locks: Click a card or the lock control in Step 5; locks persist across reruns.
  • Replace: Enable Replace in Step 5, click a card to open Alternatives (filters include Owned-only), then choose a swap.
  • Permalinks: Copy a permalink from Step 5 or a Finished deck; paste via “Open Permalink…” to restore.
  • Compare: Use the Compare page from Finished Decks; quick actions include Latest two and Swap A/B.

Virtualized lists and lazy images (optin)

  • Set WEB_VIRTUALIZE=1 to enable virtualization in Step 5 grids/lists and the Owned library for smoother scrolling on large sets.
  • Example (Compose):
    services:
        web:
            environment:
                - WEB_VIRTUALIZE=1
    
  • Example (Docker Hub):
    docker run --rm -p 8080:8080 `
        -e WEB_VIRTUALIZE=1 `
        -v "${PWD}/deck_files:/app/deck_files" `
        -v "${PWD}/logs:/app/logs" `
        -v "${PWD}/csv_files:/app/csv_files" `
        -v "${PWD}/owned_cards:/app/owned_cards" `
        -v "${PWD}/config:/app/config" `
    -e SHOW_DIAGNOSTICS=1 ` # optional: enables diagnostics tools and overlay
    mwisnowski/mtg-python-deckbuilder:latest `
        bash -lc "cd /app && uvicorn code.web.app:app --host 0.0.0.0 --port 8080"
    

Diagnostics and logs (optional)

Enable internal diagnostics and a read-only logs viewer with environment flags.

  • SHOW_DIAGNOSTICS=1 — adds a Diagnostics nav link and /diagnostics tools
  • SHOW_LOGS=1 — enables /logs and /status/logs?tail=200

Per-face MDFC snapshot (opt-in)

  • DFC_PER_FACE_SNAPSHOT=1 — write merged MDFC face metadata to logs/dfc_per_face_snapshot.json; disable parallel tagging (WEB_TAG_PARALLEL=0) if you need the snapshot during setup.
  • DFC_PER_FACE_SNAPSHOT_PATH=/app/logs/custom_snapshot.json — optional path override for the snapshot artifact.

When enabled:

  • /logs supports an auto-refresh toggle with interval, a level filter (All/Error/Warning/Info/Debug), and a Copy button to copy the visible tail.
  • /status/sys returns a simple system summary (version, uptime, UTC server time, and feature flags) and is shown on the Diagnostics page when SHOW_DIAGNOSTICS=1.
  • Virtualization overlay: press v on pages with virtualized grids to toggle per-grid overlays and a global summary bubble.

Compose example (web service):

environment:
    - SHOW_LOGS=1
    - SHOW_DIAGNOSTICS=1
docker run --rm -p 8080:8080 `
  -v "${PWD}/deck_files:/app/deck_files" `
  -v "${PWD}/logs:/app/logs" `
  -v "${PWD}/csv_files:/app/csv_files" `
  -v "${PWD}/config:/app/config" `
  -v "${PWD}/owned_cards:/app/owned_cards" `
  mwisnowski/mtg-python-deckbuilder:latest

MDFC merge rollout (staging)

The web service now runs the MDFC merge by default. Set DFC_COMPAT_SNAPSHOT=1 on the web service when you need the legacy unmerged compatibility snapshot (csv_files/compat_faces/). Combine this with python -m code.scripts.refresh_commander_catalog --compat-snapshot inside the container to regenerate the commander files before smoke testing.

Follow the QA steps in docs/qa/mdfc_staging_checklist.md after toggling the flag.

Compose example:

services:
    web:
        environment:
            - DFC_COMPAT_SNAPSHOT=1

Verify the refresh inside the container:

docker compose run --rm web bash -lc "python -m code.scripts.refresh_commander_catalog"

Downstream consumers can diff csv_files/compat_faces/commander_cards_unmerged.csv against historical exports during the staging window.

Setup speed: parallel tagging (Web)

First-time setup or stale data triggers card tagging. The web service uses parallel workers by default.

Run a JSON Config

Use the homepage “Run a JSON Config” button or run the same flow in-container:

docker compose run --rm `
  -e APP_MODE=cli `
  -e DECK_MODE=headless `
  -e DECK_CONFIG=/app/config/deck.json `
  web
  • APP_MODE=cli routes the entrypoint to the CLI menu.
  • DECK_MODE=headless skips prompts and calls headless_runner.
  • Mount JSON configs under config/ so both the UI and CLI can pick them up.
  • Dual-commander support is feature-flagged: set ENABLE_PARTNER_MECHANICS=1 and pass --secondary-commander or --background (mutually exclusive) to layer partners/backgrounds into headless runs; Partner With and Doctor/Doctors Companion pairings auto-resolve (with opt-out), and --dry-run echoes the resolved pairing for verification.
  • Partner suggestions share the same dataset for headless and web flows; set ENABLE_PARTNER_SUGGESTIONS=1 (and ensure config/analytics/partner_synergy.json exists) to expose ranked pairings in the UI and API.

Override counts, theme tags, or include/exclude lists by setting the matching environment variables before running the container (see “Environment variables” below).

Initial Setup

The homepage “Initial Setup” tile appears when SHOW_SETUP=1 (enabled in compose). It re-runs:

  1. Card downloads and color-filtered CSV generation.
  2. Commander catalog rebuild (including multi-face merges).
  3. Tagging and caching.

To force a rebuild from the host:

docker compose run --rm --entrypoint bash web -lc "python -m code.file_setup.setup"

Add --entrypoint bash ... "python -m code.scripts.refresh_commander_catalog" when you only need the commander catalog (with MDFC merge and optional compatibility snapshot).

Owned Library

Store .txt or .csv lists in owned_cards/ (mounted to /app/owned_cards). The Web UI uses them for:

  • Owned-only or prefer-owned builds.
  • The Owned Library management page (virtualized when WEB_VIRTUALIZE=1).
  • Alternative suggestions that respect ownership.

Use /owned to upload files and export enriched lists. These files persist through the owned_cards volume.

Browse Commanders

SHOW_COMMANDERS=1 exposes the commander browser tile.

  • Data lives in csv_files/commander_cards.csv.
  • Refresh the catalog (including MDFC merges) from within the container:
docker compose run --rm --entrypoint bash web -lc "python -m code.scripts.refresh_commander_catalog"

Pass --compat-snapshot if you also need an unmerged compatibility CSV under csv_files/compat_faces/.

Finished Decks

The Finished Decks page reads the deck_files/ volume for completed builds:

  • Each run produces CSV, TXT, compliance JSON, and summary JSON sidecars.
  • Locks and replace history persist per deck.
  • Compare view can diff and export summaries.

Ensure the deck exports volume remains mounted so these artifacts survive container restarts.

Budget Mode

Enable cost-aware deck building with ENABLE_BUDGET_MODE=1 (default). A per-card budget ceiling is entered in the New Deck modal.

  • Soft enforcement only: cards above the ceiling are filtered from the selection pool, but no card is hard-rejected from the final result. The build summary flags over-budget cards for review and provides a per-category price breakdown.
  • BUDGET_POOL_TOLERANCE (default 0.15) sets fractional headroom above the ceiling before exclusion (e.g. 0.15 = 15% overhead). Read at build time; not surfaced in the diagnostics panel.
  • Price data comes from Scryfall bulk data cached locally. PRICE_LAZY_REFRESH=1 (default) refreshes stale per-card prices in the background. PRICE_AUTO_REFRESH=1 rebuilds the full cache daily at 01:00 UTC.
  • PRICE_STALE_WARNING_HOURS (default 24) controls when a cached price shows a stale indicator. Set to 0 to disable.
  • Price breakdown is included in build summary panels and exported summary JSON.

Smart Land Bases

Enable or disable smart land analysis per-build via the Smart Land Bases checkbox in the Preferences section of the New Deck modal (checked by default). Each build analyses the commander's speed and the card pool's color-pip intensity to pick a land base profile.

  • Basics-heavy: 12 color decks or low-pip pools. ~60% basics, reduced ETB-tapped tolerance.
  • Balanced: 23 color decks with moderate pip density. Standard ratios and ETB thresholds.
  • Fixing-heavy: 3+ colors or high pip density (≥15 double-pip or ≥3 triple-or-more-pip cards). Minimal basics, raised ETB-tapped tolerance.
  • Land targets: fast decks (commander CMC < 3) get 33 lands; slow decks (CMC > 4) get 3739.
  • Override with LAND_PROFILE=basics|mid|fixing or LAND_COUNT=<n> to bypass auto-detection (useful for headless/CLI builds).
  • The Land Summary section of each deck result shows a "Smart Lands" notice explaining the chosen profile.
  • See docs/user_guides/land_bases.md for the full guide.

Include / Exclude Lists

Set ALLOW_MUST_HAVES=1 (default) to enable include/exclude enforcement.

  • SHOW_MUST_HAVE_BUTTONS=1 surfaces the Must Include and Must Exclude buttons and quick-add UI in Step 5 (hidden by default).
  • Cards in Must Include are always added first. Cards in Must Exclude are never selected.
  • Lists can also be supplied in JSON configs via the must_include and must_exclude keys.
  • Priority: exclude > include > budget filter > bracket filter.

Browse Themes

The Themes browser exposes the merged theme catalog with search, filters, and diagnostics.

  • ENABLE_THEMES=1 keeps the selector visible.
  • WEB_THEME_PICKER_DIAGNOSTICS=1 unlocks uncapped synergies, extra metadata, and /themes/metrics.
  • Regenerate the catalog manually:
docker compose run --rm --entrypoint bash web -lc "python -m code.scripts.build_theme_catalog"

Advanced options (e.g., EDITORIAL_* variables) live in .env.example.

Random Build

Enable the Surprise/Reroll flow by setting:

  • RANDOM_MODES=1 to expose backend random endpoints.
  • RANDOM_UI=1 to show the Random Build tile.
  • Optional tunables: RANDOM_MAX_ATTEMPTS, RANDOM_TIMEOUT_MS, RANDOM_PRIMARY_THEME, RANDOM_SEED, and auto-fill flags.

Headless parity is available by pairing APP_MODE=cli with DECK_MODE=headless and the same random variables.

Diagnostics

SHOW_DIAGNOSTICS=1 unlocks /diagnostics for system summaries, feature flags, and performance probes. Highlights:

  • /healthz returns {status, version, uptime_seconds} for external monitoring.
  • Press v on pages with virtualized grids (when WEB_VIRTUALIZE=1) to toggle the range overlay.
  • WEB_AUTO_ENFORCE=1 (optional) applies bracket enforcement automatically after each build.

View Logs

SHOW_LOGS=1 enables the logs tile and /logs interface:

  • Tail the container log with filtering and copy-to-clipboard.
  • /status/logs?tail=200 offers a lightweight JSON endpoint.
  • Raw files live under logs/ on the host; rotate or archive them as needed.

Environment variables (Docker quick reference)

See .env.example for the full catalog. Common knobs:

Core mode and networking

Variable Default Purpose
APP_MODE web Switch between Web UI (web) and CLI (cli).
DECK_MODE (unset) headless auto-runs the headless builder when the CLI starts.
DECK_CONFIG /app/config/deck.json JSON config file or directory (auto-discovery).
HOST / PORT / WORKERS 0.0.0.0 / 8080 / 1 Uvicorn binding when APP_MODE=web.

Partner mechanics & suggestions

Variable Default Purpose
ENABLE_PARTNER_MECHANICS 0 Unlock partner/background commander inputs for headless runs and Step 2 of the web UI.
ENABLE_PARTNER_SUGGESTIONS 0 Serve partner/background/Doctor suggestion chips based on config/analytics/partner_synergy.json (auto-regenerated when missing; override path with PARTNER_SUGGESTIONS_DATASET).

Homepage visibility & UX

Variable Default Purpose
SHOW_SETUP 1 Show the Initial Setup card.
SHOW_LOGS 1 Enable the View Logs tile and endpoints.
SHOW_DIAGNOSTICS 1 Enable Diagnostics tools and overlays.
SHOW_COMMANDERS 1 Expose the commander browser.
ENABLE_THEMES 1 Keep the theme selector and themes explorer visible.
SHOW_THEME_QUALITY_BADGES 1 Show quality badges in theme catalog (editorial quality score).
SHOW_THEME_POOL_BADGES 1 Show pool size badges in theme catalog (total available cards).
SHOW_THEME_POPULARITY_BADGES 1 Show popularity badges in theme catalog (usage frequency).
SHOW_THEME_FILTERS 1 Show filter dropdowns and quick chips in theme catalog.
WEB_VIRTUALIZE 1 Opt-in to virtualized lists/grids for large result sets.
ALLOW_MUST_HAVES 1 Enable include/exclude enforcement in Step 5.
SHOW_MUST_HAVE_BUTTONS 0 Surface the must include/exclude buttons and quick-add UI (requires ALLOW_MUST_HAVES=1).
LAND_PROFILE (auto) Force a land profile: basics, mid, or fixing. Skips auto-detection.
LAND_COUNT (auto) Force total land count (e.g. 36). Skips curve calculation.
ENABLE_BUDGET_MODE 1 Enable budget mode controls (per-card ceiling, soft enforcement) and price display throughout the builder.
BUDGET_POOL_TOLERANCE 0.15 Fractional overhead above the per-card ceiling before a card is excluded from the selection pool (e.g. 0.15 = 15%).
PRICE_AUTO_REFRESH 0 Rebuild the price cache automatically once daily at 01:00 UTC.
PRICE_LAZY_REFRESH 1 Refresh per-card prices in the background when they are more than 7 days old (uses Scryfall named-card API with rate-limit delay).
PRICE_STALE_WARNING_HOURS 24 Hours before a cached price is marked stale with a visual indicator. Set to 0 to disable.
THEME dark Initial UI theme (system, light, or dark).
WEB_STAGE_ORDER new Build stage execution order: new (creatures→spells→lands) or legacy (lands→creatures→spells).
WEB_IDEALS_UI slider Ideal counts interface: slider (range inputs with live validation) or input (text boxes with placeholders).
WEB_PREFETCH 0 Enable hover-intent prefetch on key navigation targets (e.g. the Open button on Finished Decks). Requires 1 to activate; respects Data Saver / slow connections.
ENABLE_CARD_DETAILS 0 Show card detail pages with similar card recommendations at /cards/<name>.
SIMILARITY_CACHE_ENABLED 1 Use pre-computed similarity cache for fast card detail pages.
ENABLE_BATCH_BUILD 1 Enable Build X and Compare feature (build multiple decks in parallel and compare results).

Random build controls

Variable Default Purpose
RANDOM_MODES (unset) Enable random build endpoints.
RANDOM_UI (unset) Show the Random Build homepage tile.
RANDOM_MAX_ATTEMPTS 5 Retry budget for constrained random rolls.
RANDOM_TIMEOUT_MS 5000 Per-attempt timeout in milliseconds.
RANDOM_REROLL_THROTTLE_MS 350 Minimum ms between reroll requests (client guard).
RANDOM_STRUCTURED_LOGS 0 Emit structured JSON logs for random builds.
RANDOM_TELEMETRY 0 Enable lightweight timing/attempt counters.
RANDOM_PRIMARY_THEME / RANDOM_SECONDARY_THEME / RANDOM_TERTIARY_THEME (blank) Override theme slots for random runs.
RANDOM_SEED (blank) Deterministic seed.
RANDOM_AUTO_FILL 1 Allow automatic backfill of missing theme slots.

Automation & performance

Variable Default Purpose
WEB_AUTO_SETUP 1 Auto-run data setup when artifacts are missing or stale.
WEB_AUTO_REFRESH_DAYS 7 Refresh cards.csv if older than N days.
WEB_TAG_PARALLEL 1 Use parallel workers during tagging.
WEB_TAG_WORKERS 4 Worker count for parallel tagging.
CACHE_CARD_IMAGES 0 Download card images to card_files/images/ (1=enable, 0=fetch from API on demand). Requires ~3-6 GB.
WEB_AUTO_ENFORCE 0 Re-export decks after auto-applying compliance fixes.
WEB_THEME_PICKER_DIAGNOSTICS 1 Enable theme diagnostics endpoints.
THEME_MIN_CARDS 5 Minimum card count threshold for themes. Themes with fewer cards are stripped from YAML catalogs, JSON picker files, and parquet metadata during setup/tagging. Set to 1 to keep all themes.

Paths and data overrides

Variable Default Purpose
CSV_FILES_DIR /app/csv_files Point the app at an alternate dataset (e.g., test snapshots).
DECK_EXPORTS /app/deck_files Override where the web UI looks for exports.
OWNED_CARDS_DIR / CARD_LIBRARY_DIR /app/owned_cards Override owned library directory.
CARD_INDEX_EXTRA_CSV (blank) Inject a synthetic CSV into the card index for testing.

Supplemental themes

Variable Default Purpose
DECK_ADDITIONAL_THEMES (blank) Comma/semicolon separated list of supplemental themes for headless builds (JSON exports also include the camelCase userThemes alias and themeCatalogVersion metadata; either alias is accepted on import).
THEME_MATCH_MODE permissive Controls fuzzy theme resolution (strict blocks unresolved inputs).

Random rate limiting (optional)

Variable Default Purpose
RATE_LIMIT_ENABLED 0 Enable server-side rate limiting for random endpoints.
RATE_LIMIT_WINDOW_S 10 Rolling window in seconds.
RATE_LIMIT_RANDOM 10 Max random attempts per window.
RATE_LIMIT_BUILD 10 Max full builds per window.
RATE_LIMIT_SUGGEST 30 Max suggestion calls per window.

Advanced editorial and theme-catalog knobs (EDITORIAL_*, SPLASH_ADAPTIVE, etc.) are documented inline in docker-compose.yml and .env.example.

Shared volumes

Host path Container path Contents
deck_files/ /app/deck_files CSV/TXT exports, summary JSON, compliance reports.
logs/ /app/logs Application logs and taxonomy snapshots.
csv_files/ /app/csv_files Card datasets, commander catalog, tagging flags.
config/ /app/config JSON configs, bracket policy, card list overrides.
owned_cards/ /app/owned_cards Uploaded inventory files for owned-only flows.

Maintenance commands

Run ad-hoc tasks by overriding the entrypoint:

# Theme catalog rebuild
docker compose run --rm --entrypoint bash web -lc "python -m code.scripts.build_theme_catalog"

# Snapshot taxonomy (writes logs/taxonomy_snapshots/)
docker compose run --rm --entrypoint bash web -lc "python -m code.scripts.snapshot_taxonomy"

# Preview the MDFC commander diff
docker compose run --rm --entrypoint bash web -lc "python -m code.scripts.preview_dfc_catalog_diff"

Use the --compat-snapshot or other script arguments as needed.

Troubleshooting

  • Container starts but UI stays blank: check /healthz and /logs (enable with SHOW_LOGS=1), then inspect the logs/ volume.
  • Files missing on the host: ensure the host directories exist before starting Compose; Windows will create empty folders if the path is invalid.
  • Long first boot: dataset downloads and tagging can take several minutes the first time. Watch progress at /setup.
  • Random build hangs: lower RANDOM_MAX_ATTEMPTS or raise RANDOM_TIMEOUT_MS, and confirm your theme overrides are valid slugs via /themes/.
  • Commander catalog outdated: rerun the refresh command above or delete csv_files/.tagging_complete.json to force a full rebuild on next start.