Files
tableau-de-bord/AGENTS.md
2026-08-13 15:23:09 +02:00

6.4 KiB

AGENTS.md

Ce fichier fournit des directives et des consignes pour les agents d'intelligence artificielle et assistants de développement (multi-modèles et multi-fournisseurs) travaillant sur ce dépôt.

Pour une présentation complète de l'architecture, de la configuration et du guide de démarrage, se référer à docs/onboarding.md.

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

# Qualité du code (Ruff)
.venv/bin/ruff check .
.venv/bin/ruff format --check .
.venv/bin/ruff format .

# Découverte des modèles OpenCode (configuration environnementale hors dépôt)
grep -A 1 -B 1 subagent /home/antoine/.config/opencode/opencode.json

Variables d'environnement

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

Git & Conventions de Commit

  • Politique Git : Les commits intermédiaires générés par les agents d'IA doivent être non signés en utilisant l'option git -c commit.gpgsign=false commit -m "..." (car pinentry est inaccessible dans cet environnement). L'utilisateur effectuera un amend signé (git commit --amend -S) du commit final lorsqu'il sera disponible.
  • Convention de trailers : Chaque commit réalisé par un agent d'IA doit inclure le trailer suivant à la fin du message de commit pour identifier le modèle utilisé :
    Co-authored-by: Fournisseur/Modèle <vibecoder@antoineve.me>
    
    Exemple : Co-authored-by: Anthropic/Claude-3.5-Sonnet <vibecoder@antoineve.me> ou Co-authored-by: Google/Gemini-3.5-Flash <vibecoder@antoineve.me>.

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]).
  • Métadonnées et horodatages (created_at / updated_at) : L'application utilise datetime.now(UTC) pour enregistrer ces métadonnées. Bien que les valeurs soient émises en UTC, SQLite et SQLAlchemy restituent par défaut des objets datetime naïfs (sans tzinfo). Ces champs sont actuellement informatifs et non exploités par la logique métier. En cas de besoin ultérieur d'exploitation de ces métadonnées avec fuseau, les pistes incluent la conservation explicite du fuseau (DateTime(timezone=True)) ou la stricte convention documentée « naïf = UTC ».
  • Calculs de durée métier et transitions DST : Le calcul de la durée des plages horaires de travail (TimeSlot via total_minutes()) est totalement indépendant des métadonnées et repose sur des heures murales (locales). Une plage horaire traversant un changement d'heure saisonnier (passage heure d'été/hiver / DST) soulève un enjeu métier spécifique (gestion des durées d'heures locales) qui nécessiterait, le cas échéant, une représentation dédiée ou une politique métier spécifique.
  • 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.