Add documentation in doc/index.md
CI / test-and-package (push) Successful in 29s

This commit is contained in:
agentbox
2026-08-01 05:54:31 +00:00
parent 219003dffb
commit be75738aa7
+191
View File
@@ -0,0 +1,191 @@
# 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
├── 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
```bash
# 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:
```bash
# 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
### 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
```bash
pip install -r requirements.txt
pytest tests/ -v
```
Tests use a temporary in-memory SQLite database (configured per test via `conftest.py`).