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>
This commit is contained in:
2026-08-13 11:38:04 +02:00
parent bd5bc496eb
commit 21fd877d7a

275
docs/onboarding.md Normal file
View File

@@ -0,0 +1,275 @@
# 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 :
```bash
# 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](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).
```bash
# 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`.
```bash
# 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]` :
```toml
[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]` :
```toml
[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` :
```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` :
```python
DAY_TYPES = [
...
("REPOS", "Repos"),
]
```
2. Ouvre `app/__init__.py` et ajoute sa traduction française dans `_DAY_TYPE_LABELS` :
```python
_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) :
```python
_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()` :
```python
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 :
```bash
# 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](../README.md) : Présentation générale, instructions d'installation détaillées et script d'import CSV en masse.
- [AGENTS.md](../AGENTS.md) : Guide de développement et consignes pour les agents d'intelligence artificielle travaillant sur ce dépôt.