From 98042833961069ec0fb760106a51519c70a1df44 Mon Sep 17 00:00:00 2001 From: mattie726 Date: Tue, 25 Aug 2026 23:36:06 -0700 Subject: [PATCH] Add CLAUDE.md documenting architecture and deploy pipeline --- CLAUDE.md | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..d935591 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,82 @@ +# Arr Summary (Greendale) + +Flask dashboard aggregating status from the user's self-hosted media stack +— Sonarr, Radarr, SABnzbd, Tautulli, Prowlarr, Ombi — plus Unraid array +stats and a Rotten Tomatoes "what's popular that I don't have yet" feed. +Branded "Greendale Media Centre." Runs as one Docker container on the +user's Unraid home server. Server-side project directory is named +`greendale`; the container/repo are named `arr-summary`. + +## Architecture + +- **`app.py`** — single Flask app, session-based single-shared-password + auth (`LOGIN_PASSWORD` env var, hashed comparison; can be changed at + runtime via `/api/change-password`, persisted to `settings.json`). + Supports running behind a reverse-proxy subpath via `SCRIPT_NAME` + + `ScriptNameMiddleware` + `ProxyFix` (currently deployed at domain root, + not a subpath, but the capability exists — see `nginx/` configs for + both). + - Per-service client functions (`sonarr_get`, `radarr_get`, + `sabnzbd_get`, `tautulli_get`, `prowlarr_get`, `ombi_get`) each call + that service's REST API directly with its API key from env vars. + - The dashboard route (`/`) fetches all services **in parallel** via + `ThreadPoolExecutor` with a hard 5-second wall-clock deadline — any + slow/unreachable service degrades to an error dict rather than + blocking the whole page. This matters for remote/cellular access. + - Aggressive per-service caching with different TTLs tuned to how often + each actually changes: Sonarr/Radarr library lists 5 min (the biggest + latency cost — full Radarr list is ~4.4MB), Tautulli stats 2 min, + SABnzbd history 10 min, Ombi requests 4 hours, Rotten Tomatoes scrapes + 4 hours. Active streams (Tautulli) and the SABnzbd queue are always + fetched live, never cached — those need to be current-second accurate. + - Rotten Tomatoes / IMDB are scraped directly (`requests` + + `BeautifulSoup`, JSON-LD parsing), not via an official API — brittle + to upstream HTML changes by nature. +- **`templates/`** — Jinja2 templates (`dashboard.html`, `login.html`, + `settings.html`); duplicated at the top level too (`dashboard.html` etc. + outside `templates/`) — appears to be a leftover from an earlier project + layout or the `export-to-unraid.sh` tooling. Left as-is rather than + restructured without confirming with the user first. +- **`export-to-unraid.sh`** — a pre-existing standalone deploy script + (build image locally → tarball → rsync + `docker load` over SSH) that + predates the Forgejo pipeline below. Still present, not removed, but the + Forgejo pipeline is now the primary deploy path going forward. +- **`nginx/`** — reference nginx location-block snippets for subdomain vs. + subpath reverse-proxy setups; not actually consumed by the app at + runtime (NPM handles proxying in practice), kept as documentation/config + reference. + +## Local development + +```bash +pip install -r requirements.txt +python3 app.py +``` + +Runs on port 5000. Needs the various `*_API_KEY` and `*_HOST`/`ARR_HOST` +env vars (see `.env.example`) to reach real services — without them, +dashboard cards degrade to "error" status individually rather than +crashing the page. + +## Deployment + +**Target:** Unraid server, container path `/mnt/user/appdata/greendale` +(note the directory name differs from the container/repo name), built from +`Dockerfile`/`docker-compose.yml` in this repo. Container name +`arr-summary`, port `5055` (overridable via `HOST_PORT`) → 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/arr-summary.git`) triggers +`.forgejo/workflows/deploy.yml`, which syncs into +`/mnt/user/appdata/greendale` (excluding `.git`, `.env`) and runs +`docker compose up -d --build`. + +**Persistent state, never touched by deploys:** `.env` holds every API key +and `LOGIN_PASSWORD` — this project was already doing this correctly +before the Forgejo migration (compose file uses `${VAR}` substitution from +`.env`, no hardcoded secrets), unlike `n64-tracker` which needed fixing. +`settings.json` (timezone, theme, changed login password) also persists +server-side outside git.