agentbox 7a90fec638
CI / test-and-package (push) Successful in 1m11s
CI / build-android (push) Successful in 1m31s
fix: chip text and input backgrounds in both light/dark modes
Root fixes:
- .chip now has explicit color: var(--text) in base theme,
  not just dark — buttons no longer use browser default
- All inputs/selects/textareas get background: var(--surface)
  and color: var(--text) in both light and dark themes
- Removed color-scheme: dark on body (prevented browser from
  forcing dark form controls regardless of data-theme)
- Dark mode input override only changes background shade now

This fixes: unreadable chip text and always-dark inputs.
2026-08-01 13:29:55 +00:00
2026-07-31 22:25:57 +02:00
2026-07-31 22:25:57 +02:00

Meal Tracker

A lightweight Flask web application for tracking household meal attendance. Members respond yes or no to lunch and dinner each day, providing an at-a-glance dashboard of who will be eating at home.

Features

  • User accounts — register, log in, log out with password hashing (Werkzeug)
  • Households — multi-tenant; users join an existing household or create a new one on registration
  • Daily meal tracking — lunch and dinner periods auto-created for each day
  • Dashboard — see all household members and their responses for a given date
  • History — browse past days; responses to past dates are read-only
  • Admin controls — household admin can remove members or delete the entire household
  • Self-service — users can delete their own account (password confirmation required)
  • SQLite — zero-dependency storage, database file persisted via Docker volume

Technology Stack

Layer Choice
Runtime Python 3.13
Framework Flask 3.x
Database SQLite (via Python sqlite3)
Passwords Werkzeug generate_password_hash / check_password_hash
Frontend Jinja2 templates, vanilla CSS
Deployment Docker + docker-compose, Caddy reverse proxy network

Project Structure

.
├── app.py                  # Flask application entry point
├── auth.py                 # Authentication blueprint (login, register, logout)
├── meals.py                # Meals blueprint (dashboard, responses, history, admin)
├── models.py               # Database models and helpers
├── i18n.py                 # Internationalization (en/fr/de)
├── ntfy.py                 # Ntfy notification helpers
├── requirements.txt        # Python dependencies
├── Dockerfile              # Container image definition
├── docker-compose.yml      # Container orchestration
├── watch-for-updates.sh    # Auto-deploy poller script
├── .gitea/                 # Gitea CI/CD workflows
├── templates/              # Jinja2 HTML templates
│   ├── base.html
│   ├── login.html
│   ├── register.html
│   └── dashboard.html
├── static/
│   └── style.css
├── tests/                  # Pytest test suite
│   ├── conftest.py
│   ├── test_auth.py
│   ├── test_meals.py
│   └── test_routes.py
└── doc/                    # Documentation
    └── index.md

Getting Started

Prerequisites

  • Docker and docker-compose
  • A Caddy reverse proxy network named caddy (already present on CozyTren infrastructure)

Quick Start

# Clone the repository
git clone https://gitea.ct.cozytren.ch/romane/agentbox-test
cd agentbox-test

# Set your secret key (or it defaults to a dev value)
export SECRET_KEY="your-secret-here"

# Build and run
docker compose up -d --build

The app will be available at http://meal-tracker:5000 (reachable through Caddy if configured).

Auto-Deploy

The watch-for-updates.sh script polls the Gitea repository every 20 seconds and automatically rebuilds and redeploys the containers on new commits:

# Source credentials and start the watcher
source .env
./watch-for-updates.sh

Configuration

Environment Variable Default Description
SECRET_KEY change-me-in-production Flask session signing secret
DB_PATH /data/meals.db in Docker Path to the SQLite database file
GITEA_PASSWORD (required for auto-deploy) Gitea password for agentbox user

Usage

Registration

  1. Navigate to the app
  2. Click Register
  3. Choose a username and password
  4. Either join an existing household or create a new one
  5. The first user in a new household becomes the admin

Responding to Meals

  1. On the dashboard, click I'll be there (green) or I won't be there (red) for lunch and dinner
  2. Your response appears alongside other household members
  3. A timestamp records the last change between yes ↔ no

Admin Actions

  • Remove a user: click the × button next to a member's name
  • Delete household: use the dangerous action section (requires password confirmation)
  • Delete your own account: available to all users, also requires password confirmation

API / Routes

Ntfy Callback (public)

Method Path Description
POST /api/ntfy-callback Receive ntfy action callbacks. Auth via per-user callback_token. Body: `{"token":"...", "meal_type":"lunch

Ntfy Settings (authenticated)

Method Path Description
POST /ntfy-settings Save ntfy topic URL and access token
POST /ntfy-test Send a test notification to verify configuration

Authentication

Method Path Description
GET/POST /login Login page
GET/POST /register Registration page
GET /logout Logout (clears session)

Meals

Method Path Description
GET / Redirects to dashboard or login
GET /dashboard Main dashboard (?date=YYYY-MM-DD to view other dates)
POST /respond Submit a meal response (meal_type, status, date)
GET /history History view (?date=YYYY-MM-DD)

Account / Admin

Method Path Description
POST /delete-account Delete own account (needs password)
POST /admin/remove-user/<id> Admin removes a household member
POST /admin/delete-household Admin deletes the entire household

Database Schema

households

Column Type Notes
id INTEGER PRIMARY KEY AUTOINCREMENT
name TEXT UNIQUE NOT NULL
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

users

Column Type Notes
id INTEGER PRIMARY KEY AUTOINCREMENT
username TEXT UNIQUE NOT NULL
password_hash TEXT NOT NULL
is_admin INTEGER DEFAULT 0
household_id INTEGER REFERENCES households(id)
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

meal_periods

Column Type Notes
id INTEGER PRIMARY KEY AUTOINCREMENT
date TEXT NOT NULL (ISO format YYYY-MM-DD)
meal_type TEXT NOT NULL, CHECK(lunch OR dinner)
UNIQUE(date, meal_type)

responses

Column Type Notes
id INTEGER PRIMARY KEY AUTOINCREMENT
user_id INTEGER NOT NULL, REFERENCES users(id)
period_id INTEGER NOT NULL, REFERENCES meal_periods(id)
status TEXT DEFAULT 'not_answered', CHECK(yes, no, not_answered)
changed_at TIMESTAMP Set when flipping between yes↔no
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
UNIQUE(user_id, period_id)

Running Tests

pip install -r requirements.txt
pytest tests/ -v

Tests use a temporary in-memory SQLite database (configured per test via conftest.py).

Ntfy Notifications

Users can configure ntfy to receive push notifications with action buttons, allowing them to respond to meals directly from their phone without opening the web UI.

Setup

  1. Install the ntfy app on your phone and subscribe to a topic (e.g. your-name-meals)
  2. (Optional) Create an access token for authenticated publishing
  3. In the web UI, open Account Settings and enter:
    • Ntfy Topic URL: Your topic (e.g. https://ntfy.sh/your-name-meals)
    • Access Token: Your ntfy access token (if using auth)
  4. Click Send Test to verify it works

How It Works

  • Reminders are sent automatically by the meal-cron container via POST /api/cron-tick every 60 seconds
  • The notification contains Home and Out buttons
  • Pressing a button sends an HTTP callback to the app, recording your response instantly
  • Tapping the notification itself opens the dashboard
S
Description
A lightweight Flask meal attendance tracker with household scoping, ntfy push notifications, and i18n (en/fr/de). 100% vibecoded.
Readme
400 KiB
Languages
Python 68.4%
HTML 12.5%
CSS 7.1%
Java 7%
Shell 4.7%
Other 0.3%