From cadc4d783c8d9066168bdaace41d3f7c22d6fd1d Mon Sep 17 00:00:00 2001 From: Antoine Van Elstraete Date: Wed, 11 Mar 2026 16:45:24 +0100 Subject: [PATCH] docs: add CLAUDE.md with architecture and commands --- CLAUDE.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c7abe20 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,49 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Commands + +```bash +# Setup (first time) +python -m venv .venv +.venv/bin/pip install -r requirements.txt + +# Run dev server +.venv/bin/python run.py + +# Run all tests +.venv/bin/python -m pytest + +# Run a single test file +.venv/bin/python -m pytest tests/test_time_calc.py -v + +# Run a single test +.venv/bin/python -m pytest tests/test_routes.py::test_create_entry -v + +# Production (Gunicorn) +SECRET_KEY= ./start.sh +``` + +## Architecture + +Flask app using the factory pattern (`create_app()` in `app/__init__.py`). The DB is SQLite via SQLAlchemy, stored in `instance/worklog.db`. All vehicle/journey/tax configuration lives in `config.toml` (loaded at startup into `app.config["TOML"]`), not in the database. + +**Data flow:** +- `config.toml` → `app/config_loader.py` → accessed via `get_vehicles()`, `get_journeys()`, `get_bareme(year, cv)` +- `app/models.py` defines `WorkEntry` (one row per day), `TimeSlot` (N plages horaires per entry), `LeaveBalance` (annual quotas) +- `app/business/` contains pure functions with no Flask dependencies: `time_calc.py` (minutes/reference), `travel_calc.py` (km, CO2, frais réels), `leave_calc.py` (solde congés/RTT) +- Routes in `app/routes/` use business functions and config_loader, then render Jinja2 templates + +**Key domain rules:** +- Day types: `WORK | TT | GARDE | ASTREINTE | FORMATION | RTT | CONGE | MALADE | FERIE` +- Types without journey: `TT, MALADE, CONGE, RTT, FERIE` (see `day_types_without_journey()`) +- Work reference: 7h45 (465 min) for WORK/TT/FORMATION, 10h (600 min) for GARDE, 0 for absences +- `total_minutes()` on `WorkEntry` sums `TimeSlot` durations, handles midnight crossing +- Frais réels: uses `bareme_kilometrique` tranches from config.toml; `km_max = 0` means "no upper limit" + +**Frontend:** Tailwind CSS and HTMX loaded from CDN in `base.html`. No build step. JavaScript is inline in templates (only `entry_form.html` has JS for dynamic time slots and journey section visibility). + +**Auth:** Handled entirely by HAProxy upstream. The app has no authentication. + +**Tests:** `tests/conftest.py` provides `app` and `client` fixtures using an in-memory SQLite DB and a temporary TOML config file. Business logic tests (`test_time_calc.py`, `test_travel_calc.py`) have no Flask dependencies and need no fixtures.