Co-authored-by: OpenAI/GPT-5.6-Terra <vibecoder@antoineve.me> Co-authored-by: Google/Gemini-3.5-Flash <vibecoder@antoineve.me> Co-authored-by: DeepSeek/DeepSeek-v4-Flash <vibecoder@antoineve.me>
5.7 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éfautdev-secret-change-in-proden 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é :
Exemple :
Co-authored-by: Fournisseur/Modèle <vibecoder@antoineve.me>Co-authored-by: Anthropic/Claude-3.5-Sonnet <vibecoder@antoineve.me>ouCo-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.toml→app/config_loader.py→ accessed viaget_vehicles(),get_journeys(),get_bareme(year, cv)app/models.pydefinesWorkEntry(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(seeday_types_without_journey()) - Work reference: 7h45 (465 min) for WORK/TT/FORMATION, 10h (600 min) for GARDE, 0 for absences
total_minutes()onWorkEntrysumsTimeSlotdurations, handles midnight crossing- Frais réels: uses
bareme_kilometriquetranches from config.toml;km_max = 0means "no upper limit". Keys:cv_3,cv_4,cv_5,cv_6,cv_7plus. Vehicles withfuel = "electric"get +20% applied incompute_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 supprimerinstance/worklog.dben dev, ou une migration manuelle en prod. - Barème kilométrique : les tranches dans
config.tomlsont à mettre à jour manuellement chaque année (section[bareme_kilometrique.YYYY]). datetime.utcnow()déprécié : Les modèles utilisent actuellementdatetime.utcnow(générant un avertissement sur Python 3.12+ et obsolète sur Python 3.14+). Il est formellement recommandé d'utiliserdatetime.now(UTC)(avecfrom datetime import UTC) à la place pour toute nouvelle manipulation de date/heure ou lors de la 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 → utiliserdb.engine.- Migration
_migrate_db: vérifier l'existence de la table avantALTER TABLE— SQLite peut avoir un fichier DB sans tables (ex: premier démarrage avecinstance/worklog.dbvide). - Tests de routes :
test_routes.pyvé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.