Files
tableau-de-bord/CLAUDE.md
Antoine Van Elstraete 4c0093c2b0 feat: increase RTT from 18 to 19
- Update LeaveBalance model default rtt_total to 19
- Update all tests to verify 19 RTT instead of 18
- Update documentation (design and technical plan)
- Update run.py to bind to 0.0.0.0 for external access
- Update CLAUDE.md deployment instructions

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-13 13:45:19 +01:00

4.4 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

# 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 (systemd) — déployé dans /var/www/tableau-de-bord-pro/
sudo systemctl edit --full tableau-de-bord-pro  # configurer SECRET_KEY
sudo systemctl restart tableau-de-bord-pro

# Git commit (GPG signing désactivé — pinentry inaccessible dans cet env)
git -c commit.gpgsign=false commit -m "..."

Variables d'environnement

  • SECRET_KEY : requis en production (défaut dev-secret-change-in-prod en dev)

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.tomlapp/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". Keys: cv_3, cv_4, cv_5, cv_6, cv_7plus. Vehicles with fuel = "electric" get +20% applied in compute_frais_reels(..., electric=True).

Frontend: Tailwind CSS CDN + HTMX in base.html. No build step. Design system defined via CSS variables (--ink, --amber, --sage, --rust, --cream) and custom classes (.card, .card-*, .btn-primary, .field-input, .font-display, .font-data) — all in base.html <style>. JS inline in entry_form.html only.

Tailwind CDN limitation: Dynamic Jinja2 classes (e.g. class="{{ var }}") are not included by the CDN. Use style= inline for dynamic colors.

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.

Gotchas

  • Pas de migration de schéma : l'app utilise db.create_all() uniquement (pas d'Alembic). Tout changement de modèle nécessite de supprimer instance/worklog.db en dev, ou une migration manuelle en prod.
  • Barème kilométrique : les tranches dans config.toml sont à mettre à jour manuellement chaque année (section [bareme_kilometrique.YYYY]).
  • datetime.utcnow() deprecated : les modèles utilisent datetime.utcnow (warning sur Python 3.14+). À remplacer par datetime.now(UTC) lors d'une prochaine évolution des modèles.
  • Filtres Jinja2 (définis dans app/__init__.py) : {{ date | date_fr }} pour les dates en français ; {{ day_type | day_type_fr }} pour les libellés de types de jours (WORK→Travail, TT→Télétravail, etc.).
  • db.get_engine() deprecated en Flask-SQLAlchemy 3.x → utiliser db.engine.
  • Migration _migrate_db : vérifier l'existence de la table avant ALTER TABLE — SQLite peut avoir un fichier DB sans tables (ex: premier démarrage avec instance/worklog.db vide).
  • Tests de routes : test_routes.py vérifie des chaînes de la réponse HTML. Utiliser les libellés affichés (ex: "Télétravail" pas "TT"), et les noms de véhicules du TOML (pas les IDs). Mettre à jour si les libellés changent.