Files
tableau-de-bord/docs/onboarding.md
Antoine Van Elstraete 21fd877d7a doc: add developer onboarding guide
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>
2026-08-13 11:38:04 +02:00

13 KiB

Guide d'intégration (Onboarding) pour les développeurs

Bienvenue sur le projet Tableau de bord pro ! Ce guide est conçu pour t'aider à prendre en main rapidement l'application, comprendre son architecture, ses règles métier et savoir comment y apporter des modifications courantes.


1. Objectif fonctionnel

Le Tableau de bord pro est une application web personnelle permettant de suivre :

  • Le temps de travail quotidien : saisie des heures travaillées, des types de journées (travail, télétravail, garde, astreinte, formation, RTT, congé, maladie, férié) et des commentaires associés.
  • Les déplacements professionnels : calcul automatique des distances parcourues par véhicule, estimation des émissions de CO₂ et calcul des frais réels déductibles selon le barème kilométrique fiscal officiel.
  • Le solde des congés et RTT : suivi annuel des jours posés et du solde restant par rapport aux quotas alloués.
  • Les rapports d'activité : bilans annuels et mensuels compilant les kilomètres, le CO₂, les frais réels et la répartition des types de journées.

2. Prérequis et démarrage local

Prérequis

  • Python 3.11+ installé sur ta machine.

Démarrage local

Pour lancer l'application en mode développement, exécute les commandes suivantes dans ton terminal :

# 1. Créer l'environnement virtuel Python
python -m venv .venv

# 2. Activer l'environnement virtuel et installer les dépendances
.venv/bin/pip install -r requirements.txt

# 3. Lancer le serveur de développement Flask
.venv/bin/python run.py

L'application est alors accessible localement à l'adresse suivante : http://localhost:5000.


3. Architecture de l'application

L'application est construite avec le framework Flask en utilisant le Factory Pattern (via la fonction create_app dans app/__init__.py).

Structure des dossiers et fichiers clés

  • run.py : Point d'entrée pour lancer le serveur de développement.
  • config.toml : Fichier de configuration statique (véhicules, trajets, barèmes fiscaux).
  • app/ : Code source de l'application.
    • __init__.py : Initialisation de Flask, configuration de la base de données, enregistrement des blueprints et des filtres Jinja2.
    • config_loader.py : Interface de lecture du fichier config.toml.
    • models.py : Définition des modèles de données SQLAlchemy (SQLite).
    • business/ : Logique métier pure, sans dépendance à Flask (facile à tester) :
      • time_calc.py : Calculs de durées, de soldes d'heures et statistiques de temps.
      • travel_calc.py : Calculs de distances, d'émissions de CO₂ et de frais réels.
      • leave_calc.py : Calculs de congés et RTT consommés.
    • routes/ : Contrôleurs Flask gérant les requêtes HTTP et le rendu des templates :
      • dashboard.py : Page d'accueil et vue d'ensemble.
      • entries.py : Gestion (CRUD) des entrées de temps.
      • reports.py : Génération des rapports annuels et mensuels.
    • templates/ : Fichiers HTML utilisant Jinja2.
  • tests/ : Tests unitaires et d'intégration (pytest).

Technologies Frontend

  • Tailwind CSS (via CDN) : Utilisé pour le style. Les variables de design et les classes personnalisées (comme .card, .btn-primary, etc.) sont définies directement dans la balise <style> de app/templates/base.html.
  • HTMX : Utilisé pour rendre l'interface dynamique sans rechargement complet de page.
  • JavaScript : Uniquement du JS inline dans app/templates/entry_form.html pour la gestion dynamique du formulaire de saisie.

Authentification

L'application n'intègre aucun système d'authentification interne. La sécurité et l'authentification sont entièrement déléguées à un serveur HAProxy situé en amont (upstream) en production.


4. Flux d'une saisie de journée

Voici ce qui se passe lorsqu'un utilisateur saisit ou modifie une journée de travail :

  1. Affichage du formulaire (GET /entries/new ou /entries/<id>/edit) :

    • La route entry_form dans app/routes/entries.py récupère les véhicules à moteur et les profils de trajets depuis config.toml via app/config_loader.py.
    • Elle transmet ces données au template entry_form.html.
  2. Soumission du formulaire (POST) :

    • L'utilisateur envoie la date, le type de journée, le trajet, le véhicule à moteur utilisé, le commentaire et les plages horaires.
    • Application des règles de cohérence :
      • Si le type de journée est un jour sans trajet (ex: Télétravail, Congé), le trajet est forcé à None.
      • Si le trajet sélectionné n'implique pas de véhicule à moteur, le véhicule à moteur est forcé à None.
    • Enregistrement de l'entrée (WorkEntry) :
      • En création, l'application vérifie qu'aucune entrée n'existe déjà à cette date (unicité de la date).
      • L'entrée est créée ou mise à jour dans la table work_entries.
    • Gestion des plages horaires (TimeSlot) :
      • Pour simplifier la mise à jour, toutes les plages horaires existantes de cette journée sont supprimées de la base de données.
      • Les nouvelles plages horaires soumises sont lues, validées et recréées sous forme d'objets TimeSlot liés à la WorkEntry.
    • Validation : La transaction est validée via db.session.commit(), et l'utilisateur est redirigé vers le tableau de bord.

5. Rôle de config.toml vs SQLite

L'application sépare strictement la configuration métier statique des données utilisateur dynamiques.

config.toml (Configuration statique)

Ce fichier contient les paramètres qui ne changent pas fréquemment et qui définissent les règles de calcul :

  • Véhicules ([vehicles.*]) : Nom, type (moteur ou velo), carburant (electric, diesel, essence, none), émissions de CO₂ par km, et puissance fiscale (CV).
  • Trajets ([journeys.*]) : Profils de trajets prédéfinis (ex: "moteur_seul", "moteur_velo") avec les distances associées par type de moyen de transport.
  • Barème kilométrique ([bareme_kilometrique.YYYY.*]) : Les tranches fiscales officielles de remboursement par année et par puissance fiscale (CV).

Note : Ces données sont chargées en mémoire au démarrage de l'application dans app.config["TOML"].

SQLite / instance/worklog.db (Données dynamiques)

La base de données stocke l'activité saisie par l'utilisateur :

  • work_entries : Une ligne par jour saisi (date, type de jour, ID du trajet, ID du véhicule, commentaire, timestamps).
  • time_slots : Les plages horaires travaillées associées à une journée (heure de début, heure de fin, ID de l'entrée).
  • leave_balance : Les quotas annuels de congés et de RTT (année, total congés, total RTT).

6. Règles métier essentielles

Pour éviter les erreurs de calcul, garde bien en tête ces règles fondamentales :

  • Types de journées : Les types autorisés sont WORK, TT, GARDE, ASTREINTE, FORMATION, RTT, CONGE, MALADE, FERIE.
  • Absence de trajet : Les types TT, MALADE, CONGE, RTT et FERIE n'impliquent aucun trajet physique (définis dans day_types_without_journey()).
  • Durée de référence du travail :
    • WORK, TT, FORMATION : 7h45 (soit 465 minutes).
    • GARDE : 10h00 (soit 600 minutes).
    • ASTREINTE, RTT, CONGE, MALADE, FERIE : 0 minute.
  • Calcul du temps de travail : La méthode total_minutes() de WorkEntry somme les durées des TimeSlot. Elle gère le passage de minuit : si l'heure de fin est inférieure ou égale à l'heure de début (ex: 22:00 à 02:00), elle ajoute automatiquement 24 heures à la plage.
  • Frais réels et véhicules électriques :
    • Le calcul des frais réels applique les tranches du barème kilométrique de config.toml. Une tranche avec km_max = 0 représente la tranche supérieure sans limite.
    • Les véhicules électriques (fuel = "electric") bénéficient d'une majoration automatique de 20 % sur le montant calculé des frais réels (géré dans app/business/travel_calc.py).

7. Tests et Qualité du code

Exécuter les tests

Les tests sont écrits avec pytest. Les tests de logique métier (test_time_calc.py, test_travel_calc.py) n'ont aucune dépendance à Flask et s'exécutent très rapidement. Les tests de routes utilisent des fixtures définies dans tests/conftest.py (base de données SQLite en mémoire et configuration TOML temporaire).

# Exécuter tous les tests
.venv/bin/python -m pytest

# Exécuter un fichier de test spécifique
.venv/bin/python -m pytest tests/test_time_calc.py -v

# Exécuter un test unitaire précis
.venv/bin/python -m pytest tests/test_routes.py::test_create_entry -v

Qualité et Formatage du code

Le projet utilise Ruff comme outil unique pour le linting, le tri des imports et le formatage du code. La configuration est définie dans pyproject.toml.

# Vérifier le code (linter)
.venv/bin/ruff check .

# Vérifier le formatage
.venv/bin/ruff format --check .

# Appliquer automatiquement le formatage et corriger les imports
.venv/bin/ruff format .
.venv/bin/ruff check --fix .

8. Guide de modifications courantes

A. Ajouter ou modifier un véhicule

Pour ajouter un nouveau véhicule (par exemple, une nouvelle voiture de 4 CV), ouvre config.toml et ajoute une section sous [vehicles] :

[vehicles.ma_nouvelle_voiture]
name = "Ma Nouvelle Voiture"
fuel = "essence"
co2_per_km = 120
cv = 4
type = "moteur"

B. Ajouter ou modifier un trajet prédéfini

Pour ajouter un trajet combinant voiture et vélo, ouvre config.toml et ajoute une section sous [journeys] :

[journeys.mon_nouveau_trajet]
name = "Mon Nouveau Trajet"
distances = { moteur = 10, velo = 5 }

C. Mettre à jour le barème kilométrique annuel

Chaque année, l'administration fiscale publie un nouveau barème. Pour l'ajouter (par exemple pour l'année 2027), ajoute les tranches correspondantes dans config.toml :

[[bareme_kilometrique.2027.cv_4.tranches]]
km_max = 5000
taux = 0.606
forfait = 0

[[bareme_kilometrique.2027.cv_4.tranches]]
km_max = 20000
taux = 0.340
forfait = 1330

[[bareme_kilometrique.2027.cv_4.tranches]]
km_max = 0
taux = 0.407
forfait = 0

D. Ajouter un nouveau type de journée

Si tu dois ajouter un nouveau type de journée (par exemple REPOS) :

  1. Ouvre app/routes/entries.py et ajoute le type à la liste DAY_TYPES :
    DAY_TYPES = [
        ...
        ("REPOS", "Repos"),
    ]
    
  2. Ouvre app/__init__.py et ajoute sa traduction française dans _DAY_TYPE_LABELS :
    _DAY_TYPE_LABELS = {
        ...
        "REPOS": "Repos",
    }
    
  3. Ouvre app/business/time_calc.py et définis sa durée de référence dans _REFERENCE_MINUTES (ex: 0 minute pour un repos) :
    _REFERENCE_MINUTES = {
        ...
        "REPOS": 0,
    }
    
  4. Si ce type de journée n'implique aucun trajet, ouvre app/config_loader.py et ajoute-le dans day_types_without_journey() :
    def day_types_without_journey():
        return {"TT", "MALADE", "CONGE", "RTT", "FERIE", "REPOS"}
    

9. Déploiement, limites et migrations

Déploiement en production

L'application est déployée dans /var/www/tableau-de-bord-pro/ et est gérée par un service systemd qui lance Gunicorn.

Pour mettre à jour la production :

# 1. Copier les fichiers (en excluant l'environnement virtuel et la base de données locale)
sudo rsync -a --exclude='.venv' --exclude='instance' . /var/www/tableau-de-bord-pro/

# 2. Se positionner dans le dossier de production
cd /var/www/tableau-de-bord-pro

# 3. Mettre à jour les dépendances si nécessaire
sudo .venv/bin/pip install -r requirements.txt

# 4. S'assurer que les permissions sont correctes
sudo chown -R www-data:www-data /var/www/tableau-de-bord-pro

# 5. Redémarrer le service systemd
sudo systemctl restart tableau-de-bord-pro

Limites et Migrations de base de données

  • Pas d'Alembic : Le projet n'utilise pas d'outil de migration automatique comme Alembic. La base de données est initialisée avec db.create_all().
  • Changement de schéma : Si tu modifies un modèle dans app/models.py (par exemple en ajoutant un champ) :
    • En développement : Tu peux simplement supprimer le fichier instance/worklog.db pour qu'il soit recréé au prochain démarrage (attention, cela supprime tes données de test).
    • En production : Tu dois écrire une migration manuelle dans la fonction _migrate_db située dans app/__init__.py. Cette fonction s'exécute au démarrage de l'application, vérifie l'existence des colonnes via SQLite, et applique les instructions ALTER TABLE nécessaires de manière sécurisée.

Dépréciations à surveiller

  • datetime.utcnow() : Utilisé dans les modèles de données. Cette méthode est dépréciée depuis Python 3.12. Lors d'une prochaine évolution majeure des modèles, il faudra la remplacer par datetime.now(UTC).
  • db.get_engine() : Déprécié dans Flask-SQLAlchemy 3.x. Utilise toujours db.engine à la place.

10. Liens utiles

Pour aller plus loin, n'hésite pas à consulter les documents suivants à la racine du projet :

  • README.md : Présentation générale, instructions d'installation détaillées et script d'import CSV en masse.
  • AGENTS.md : Guide de développement et consignes pour les agents d'intelligence artificielle travaillant sur ce dépôt.