diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..8546ebb --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,64 @@ +# Lunch Notifier + +Single-file Flask app that scrapes the daily Mariposa (Kyrene school +district) lunch menu and texts it to a list of phone numbers via +email-to-SMS carrier gateways (e.g. `4805551234@vtext.com` for Verizon). +Runs as one Docker container on the user's Unraid home server. + +## Architecture + +- **`app.py`** — everything: Flask web UI/API, APScheduler-style job + scheduling (`schedule` library), and the email-to-SMS send logic + (`smtplib` via Gmail, app password auth). The HTML/CSS/JS frontend is + embedded as a Python string constant (`HTML`) rather than a separate + template file — no build step, no template engine. +- **`scraper.py`** — fetches and parses the school's published lunch menu. +- **`scheduler.py`** — day-of-week/time scheduling helpers used by `app.py`. +- Settings (phone numbers, send time, days, vacation date ranges) persist + to `/data/settings.json`, not environment variables — env vars + (`PHONE_NUMBER`, `RUN_TIME`, `RUN_DAYS`) are defaults used only the very + first time, before a settings file exists. +- Vacation ranges suppress sends without disabling the schedule — checked + fresh on every run via `is_on_vacation()`. + +## Local development + +```bash +pip install -r requirements.txt +python3 app.py +``` + +Needs `GMAIL_USER` and `GMAIL_APP_PASSWORD` env vars to actually send +(a Gmail **app password**, not the account password — required since Gmail +disallows plain SMTP auth with the real password). Visit +`http://localhost:2323`. + +## Deployment + +**Target:** Unraid server, container path `/mnt/user/appdata/lunch-notifier`, +built from `Dockerfile`/`docker-compose.yml` in this repo. Container name +`Lunch-Notifier`, port `2323`. No reverse proxy — accessed directly via +`http://:2323` on the LAN. + +**Deploy mechanism: Forgejo push-to-deploy**, same pattern as the other +three projects on this box (`card-grader`, `n64-tracker`, `arr-summary`) — +see `card-grader`'s `CLAUDE.md` for the full pipeline mechanics (runner +config, HTTPS-not-SSH git auth, known tradeoffs). In short: push to `main` +on the `forgejo` remote (`https://git.hippofam.com/ninja_hippo/lunch-notifier.git`) +triggers `.forgejo/workflows/deploy.yml`, which syncs into +`/mnt/user/appdata/lunch-notifier` (excluding `.git`, `.env`, `data/`) and +runs `docker compose up -d --build`. + +**Persistent state, never touched by deploys:** `data/settings.json` (the +volume-mounted `/data` inside the container) holds phone numbers, schedule, +and vacation ranges — this is live user data, not deploy-managed. `.env` +holds `GMAIL_USER`/`GMAIL_APP_PASSWORD`/`PHONE_NUMBER` etc. and is +server-only, gitignored, never committed. + +**Migration note (2026-08-25):** this container originally used a Docker +**named volume** (`lunch-notifier_lunch-settings`) instead of a bind mount. +That meant Unraid's Appdata Backup plugin — which only knows about +`/mnt/user/appdata` and `/mnt/cache/appdata` as backup sources — silently +skipped it entirely; the settings data was never included in any backup. +Migrated to a bind mount (`./data:/data`) with the existing settings copied +over first and verified intact before the old named volume was deleted.