n64-tracker/CLAUDE.md
mattie726 e0e68bfba8
All checks were successful
Deploy / deploy (push) Successful in 39s
Add CLAUDE.md documenting architecture and deploy pipeline
2026-08-25 23:36:05 -07:00

81 lines
4 KiB
Markdown

# N64 Tracker
Flask app for tracking a personal N64 game collection: ownership status,
loose cartridge prices (scraped from PriceCharting), rarity percentages
(scraped from RarityGuide), and cover art (LaunchBox games DB, cached
locally as WebP thumbnails). Runs as one Docker container on the user's
Unraid home server.
## Architecture
- **`app.py`** — Flask routes for the game list/stats API, session-based
password auth (single shared password, SHA-256 hashed in
`/app/data/settings.json`), and three scrapers:
- `scrape_pricecharting()` — loose cartridge prices, paginated via a
cursor-based form POST loop.
- `scrape_rarityguide()` — rarity % + label, fuzzy-matched to game titles
via `difflib` (handles minor title spelling differences between
sources).
- `scrape_game_info()` — cover art + metadata from LaunchBox's games DB,
only fetched lazily on first view/ownership toggle of a game, not
upfront for the whole collection.
- Thumbnails: `generate_thumbnails()` runs in a background thread at
startup, converting `Coverart/*.png` to 300px-wide WebP in
`/app/data/thumbs` — serving thumbnails instead of full PNGs is what
keeps the game grid fast.
- `BASE_PREFIX = '/n64'` — the app expects to run under this subpath
behind a reverse proxy; all routes are prefixed with it.
- **`static/`** — frontend (vanilla JS/HTML/CSS), served by Flask directly.
- **`games.json`** at the repo root is a **seed/reference copy**, not the
live database — the actual live data is `/app/data/games.json` on the
bind-mounted `data/` volume (gitignored, server-only).
- **`Coverart/`** — ~1,600 PNG cover art images (~1.6GB). Deliberately
**excluded from git** (`.gitignore`) — this is static reference data
that doesn't change, and 1.6GB in git history would make every clone of
this repo download all of it. It lives only on the server; the deploy
workflow explicitly excludes it from the rsync `--delete` so a deploy
never wipes it (see below).
## Local development
```bash
pip install -r requirements.txt
python3 app.py
```
Runs on port 5000. Needs `Coverart/` populated locally to see cover art
(not in git — copy it from the server if working on cover-art-related
features, or work without it since it degrades gracefully).
## Deployment
**Target:** Unraid server, container path `/mnt/user/appdata/n64-tracker`,
built from `Dockerfile`/`docker-compose.yml` in this repo. Container name
`n64-tracker-n64-tracker-1`, host port `8585` → container port `5000`.
**Deploy mechanism: Forgejo push-to-deploy**, same pattern as the other
three projects on this box — see `card-grader`'s `CLAUDE.md` for the full
pipeline mechanics. Push to `main` on the `forgejo` remote
(`https://git.hippofam.com/ninja_hippo/n64-tracker.git`) triggers
`.forgejo/workflows/deploy.yml`, which syncs into
`/mnt/user/appdata/n64-tracker` (excluding `.git`, `.env`, `data/`, and
**`Coverart/`** — that last exclusion is load-bearing, since `Coverart/`
isn't tracked in git at all and a `--delete` sync without excluding it
would wipe the images on every deploy) and runs `docker compose up -d --build`.
**Persistent state, never touched by deploys:** `data/` (games.json,
settings.json, thumbnail cache) and `Coverart/` are both server-only.
`.env` holds `ADMIN_PASSWORD`/`SECRET_KEY`.
**Migration notes (2026-08-25):**
- This container originally used a Docker **named volume**
(`n64-tracker_game-data`) instead of a bind mount, which meant Unraid's
Appdata Backup plugin (only knows about `/mnt/user/appdata`) silently
never backed up the live game database. Migrated to a bind mount
(`./data:/app/data`) with existing data copied over and verified intact
before the named volume was deleted.
- `ADMIN_PASSWORD` and `SECRET_KEY` were previously hardcoded in plain text
directly in `docker-compose.yml`, which would have landed in git history
the moment this repo was created. Moved to a gitignored `.env` file
referenced via `env_file: .env` before this repo was ever initialized —
neither secret is in git history.