Files
agentbox-test/AGENTS.md
T
agentbox 710cd1fbf9
CI / test-and-package (push) Successful in 33s
Refactor cron to call API via HTTP, capture base_url from browser
- meal-cron now runs send_reminders_cron.sh (simple wget loop, no DB mount)
- New /api/cron-tick endpoint handles all timezone logic server-side
- base_url captured from request.host_url when user saves ntfy settings,
  stored per-user — no APP_BASE_URL env var needed
- Cron endpoint protected by CRON_SECRET shared env var
- Removed send_reminders_cron.py, DB volume from cron container
- tests: 3 new cron-tick + base_url capture tests (69 total)
2026-08-01 06:32:09 +00:00

4.7 KiB

AGENTS.md — Meal Tracker

Overview

Flask web app for tracking household meal attendance. Users register into households, then mark yes/no for lunch & dinner each day. A dashboard shows all members' responses. SQLite backend, Docker deployment behind Caddy reverse proxy.

  • Repo: https://gitea.ct.cozytren.ch/romane/agentbox-test
  • Production: https://meals.ct.cozytren.ch
  • Auto-deploy: watch-for-updates.sh polls for new commits every 20s, rebuilds via docker compose, redeploys. Push-to-deploy in ~1 min.

Files — What Goes Where

File Role
app.py Flask factory (create_app()), registers blueprints and i18n
auth.py Auth blueprint: /login, /register, /logout. Session-based.
meals.py Meals blueprint: /dashboard, /respond, /history, /delete-account, /admin/*, /ntfy-settings, /ntfy-test, /api/ntfy-callback
models.py All DB access. SQLite via sqlite3. 4 tables: households, users, meal_periods, responses. Ntfy helpers in # Ntfy / notifications section.
i18n.py Translation module. t(key) helper for en/fr/de. Detects Accept-Language, session override via ?lang=. All user-visible strings flow through t().
ntfy.py Ntfy notification helpers. send_meal_reminder() sends push with Home/Out HTTP action buttons. send_test_notification() verifies config.
templates/ Jinja2: base.html (nav, lang footer), login.html, register.html, dashboard.html
static/style.css All CSS (no framework)
tests/ Pytest suite (47 tests): conftest.py sets up in-memory DB per test
Dockerfile Python 3.13-alpine. Must list every .py file in the COPY line.
docker-compose.yml Two services: meal-tracker (web) and meal-cron (sends reminders). Both on external caddy network, shared meal-data volume at /data.
watch-for-updates.sh Polls git remote, rebuilds on change. Uses docker compose with env vars from .env.
send_reminders_cron.sh Simple shell loop run by meal-cron: calls POST /api/cron-tick on meal-tracker:5000 every 60s with X-Cron-Secret header. No DB access — all logic is server-side.
doc/index.md Full project documentation
README.md Symlink → doc/index.md

Key Conventions

  • Blueprints: auth_bp and meals_bp registered in app.py. Decorator @login_required on protected routes.
  • Session keys: user_id, username, is_admin, household_id, household_name, lang.
  • i18n: Every user-visible string in templates uses {{ t('English text') }}. In Python, flash(t("message"), "category"). Translations live in TRANSLATIONS dict in i18n.py. English string is the key; only non-English translations stored. When adding new user-facing text, add it to TRANSLATIONS for fr/de.
  • DB: All access through get_db() context manager in models.py. Returns sqlite3.Row objects accessed as dicts. Path via DB_PATH env var (defaults to /data/meals.db in Docker, ./meals.db locally).
  • CSS: No framework. Variables in :root. Use existing utility classes (.btn, .chip, .badge, etc.).
  • Ntfy: Per-user topic URL + Bearer token stored in users table. Callback token auto-generated on first ntfy setup. /api/ntfy-callback is unauthenticated (uses callback token). Send reminders via flask send-reminders [--date] [--meal] [--base-url]. Schedule with cron.

Common Pitfalls

  1. Dockerfile COPY must include every .py file. If you add a new Python module, add it to the COPY line. Missing files cause ModuleNotFoundError → container crash → 502.
  2. meal_type values are lowercase (lunch, dinner) in DB/forms. Templates capitalize them for display: period.meal_type|capitalize.
  3. Past dates are read-only. The respond route rejects dates before today. Dashboard shows badges instead of buttons for other users' rows.
  4. changed_at logic: Set only when flipping between yesno. First answer and not_answered transitions leave it NULL.
  5. Response status values: yes, no, not_answered (stored in DB; CSS classes and display strings derived from these).

Running Locally (no Docker)

pip install -r requirements.txt
python app.py          # or: flask --app 'app:create_app()' run --debug
pytest tests/ -v

Running with Docker

docker compose up -d --build    # needs caddy network
# or standalone:
docker build -t meal-tracker .
docker run -p 5000:5000 meal-tracker

Adding a New Language

  1. Add the language code and name to LANGUAGES in i18n.py.
  2. Add translations for every key in TRANSLATIONS (keys are the English strings).
  3. Add the language to the footer loop in templates/base.html.