root 7d84d8f00d ci: add build pipeline (build -> push -> dispatch to orchestrator)
This replaces the old 'manual docker run' workflow. Pushing to main
now:
1. Builds the multi-stage Docker image (Node build + nginx runtime)
2. Tags with :latest and :<short-sha> for reproducibility
3. Pushes both to the Gitea container registry
4. Dispatches to gitea-deploy-orchestrator with the image+SHA+branch

The orchestrator handles the actual deploy (Portainer, DNS, healthcheck).
Single source of truth for 'where do we deploy' lives in the orchestrator
repo, not in scattered docker run commands.

Required secrets (Kay's manual step):
- REGISTRY_TOKEN: Gitea API token with write:package scope
- GITEA_DISPATCH_TOKEN: Gitea API token with repository scope
  (for posting repository_dispatch to the orchestrator)

Refs: gitea-deploy-orchestrator#3 (Phase B5)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-18 23:48:28 +00:00

WH40K Points Comparator

Compare Warhammer 40,000 unit points across Munitorum Field Manual versions.

Features

  • Multi-version comparison — Track points changes across 5 MFM versions (1.14 → current)
  • Faction filtering — Browse by faction or view all 1,449 units
  • Biggest movers — Top 5 price drops and rises for the current view
  • Historical graph — Click any unit to see a points history chart across all MFM versions
  • Shareable URLs — Filter state is stored in URL query params (?faction=...&dir=...&q=...)
  • Mobile responsive — Flex-based layout that scales to any device
  • Social embeds — OG/Twitter meta tags with grimdark favicon and preview image

Tech Stack

  • React + MUI (Material UI DataGrid)
  • Vite build
  • nginx (Alpine) in Docker
  • Traefik reverse proxy with Cloudflare TLS

Data Sources

  • Current MFM — Scraped from warhammer-community.com (live data)
  • MFM 4.3 (Jun 2026), 3.2 (Aug 2025), 2.3 (Mar 2025), 1.14 (Dec 2024) — Parsed from PDFs

Deployment

  1. Edit docker-compose.yml — change the Host() rule to your domain
  2. Build and deploy:
docker compose up -d --build

Without Traefik

Uncomment the ports section in docker-compose.yml:

ports:
  - "8080:80"

Then access at http://localhost:8080.

Building from scratch

The Dockerfile is multi-stage:

  1. Build stagenode:20-alpine installs deps and runs npm run build
  2. Runtime stagenginx:alpine serves the static files

No pre-built artifacts needed — just docker compose build.

Data Pipeline

PDFs + live scrape → per-faction JSON files
                         ↓
              build_deduped_data.py
                         ↓
              react-app/public/data.json
                         ↓
                   React app (fetched at runtime)

Run python3 build_deduped_data.py to rebuild data.json from source data.

Project Structure

wh40k-factions/
├── Dockerfile              # Multi-stage: node build → nginx serve
├── docker-compose.yml      # Traefik + Cloudflare TLS config
├── build_deduped_data.py   # Merges all MFM versions into data.json
├── parse_pdf_per_faction.py # PDF → per-faction JSON (MFM 4.3)
├── react-app/
│   ├── index.html          # OG meta tags, favicon
│   ├── package.json
│   ├── vite.config.js
│   ├── public/
│   │   ├── data.json       # Merged dataset (5 MFM versions)
│   │   ├── favicon.png     # Grimdark Aquila icon
│   │   └── og-image.png    # Social embed banner
│   └── src/
│       ├── main.jsx
│       └── App.jsx         # Main app: filters, movers, DataGrid, graph modal
├── live/                   # Current MFM scrape (per-faction JSON)
├── pdf/                    # MFM 4.3 PDF parse (per-faction JSON)
├── pdf32/                  # MFM 3.2 PDF parse
├── pdf23/                  # MFM 2.3 PDF parse
└── pdf114/                 # MFM 1.14 PDF parse

License

MIT

Description
WH40K Points Comparator — compare unit points across Munitorum Field Manual versions
Readme 2.3 MiB
Languages
Python 48.9%
JavaScript 38.2%
CSS 7.7%
HTML 4.1%
Dockerfile 1.1%