docs: add initial design document for work time tracking dashboard
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
203
docs/plans/2026-03-11-tableau-de-bord-travail-design.md
Normal file
203
docs/plans/2026-03-11-tableau-de-bord-travail-design.md
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
# Design : Tableau de bord temps de travail
|
||||||
|
|
||||||
|
**Date :** 2026-03-11
|
||||||
|
**Statut :** Approuvé
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Objectif
|
||||||
|
|
||||||
|
Application web personnelle auto-hébergée pour tracer au quotidien le temps de travail : heures de présence, déplacements domicile-travail (coût, CO2, frais réels fiscaux), solde congés/RTT.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Stack technique
|
||||||
|
|
||||||
|
- **Backend :** Python 3.12+, Flask, SQLAlchemy, SQLite
|
||||||
|
- **Frontend :** Jinja2 + HTMX + Tailwind CSS (CDN Play, sans build chain)
|
||||||
|
- **Configuration :** TOML (`config.toml`) chargé au démarrage
|
||||||
|
- **Déploiement :** Gunicorn sur port local, derrière HAProxy (TLS + auth gérés en amont)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Structure du projet
|
||||||
|
|
||||||
|
```
|
||||||
|
tableau-de-bord/
|
||||||
|
├── app/
|
||||||
|
│ ├── __init__.py # factory Flask
|
||||||
|
│ ├── models.py # SQLAlchemy models
|
||||||
|
│ ├── routes/
|
||||||
|
│ │ ├── dashboard.py # page principale / synthèse
|
||||||
|
│ │ ├── entries.py # saisie / édition des jours
|
||||||
|
│ │ └── reports.py # rapports (frais réels, CO2...)
|
||||||
|
│ ├── templates/
|
||||||
|
│ │ ├── base.html
|
||||||
|
│ │ ├── dashboard.html
|
||||||
|
│ │ ├── entry.html
|
||||||
|
│ │ └── reports.html
|
||||||
|
│ └── static/
|
||||||
|
├── config.toml
|
||||||
|
├── instance/
|
||||||
|
│ └── worklog.db
|
||||||
|
└── run.py
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Modèle de données
|
||||||
|
|
||||||
|
### Table `work_entries`
|
||||||
|
|
||||||
|
| Colonne | Type | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| id | INTEGER PK | |
|
||||||
|
| date | DATE UNIQUE | Date du jour |
|
||||||
|
| journey_profile_id | TEXT NULL | Clé du profil dans config.toml (null si TT/MALADE/CONGE/RTT/FERIE) |
|
||||||
|
| day_type | TEXT | Voir types ci-dessous |
|
||||||
|
| comment | TEXT NULL | Commentaire libre |
|
||||||
|
| created_at | DATETIME | |
|
||||||
|
| updated_at | DATETIME | |
|
||||||
|
|
||||||
|
**Types de journées (`day_type`) :**
|
||||||
|
- `WORK` — Jour de travail normal sur site
|
||||||
|
- `TT` — Télétravail (7h45, pas de déplacement)
|
||||||
|
- `GARDE` — Garde physique sur site (9h-19h, weekend/férié)
|
||||||
|
- `ASTREINTE` — Disponibilité sans présence obligatoire (déplacement si besoin réel)
|
||||||
|
- `FORMATION` — Formation
|
||||||
|
- `RTT` — Jour de RTT
|
||||||
|
- `CONGE` — Congé payé
|
||||||
|
- `MALADE` — Arrêt maladie
|
||||||
|
- `FERIE` — Jour férié
|
||||||
|
|
||||||
|
### Table `time_slots`
|
||||||
|
|
||||||
|
| Colonne | Type | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| id | INTEGER PK | |
|
||||||
|
| entry_id | INTEGER FK | Référence work_entries |
|
||||||
|
| start_time | TIME | Heure de début |
|
||||||
|
| end_time | TIME | Heure de fin |
|
||||||
|
|
||||||
|
Une journée peut avoir N plages horaires non-consécutives (ex: 9h-18h + 22h-00h pour coupures ou réunion de nuit). Le temps total = somme des plages.
|
||||||
|
|
||||||
|
### Table `leave_balance`
|
||||||
|
|
||||||
|
| Colonne | Type | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| id | INTEGER PK | |
|
||||||
|
| year | INTEGER UNIQUE | Année |
|
||||||
|
| conges_total | INTEGER | Total congés (défaut 28) |
|
||||||
|
| rtt_total | INTEGER | Total RTT (défaut 18) |
|
||||||
|
|
||||||
|
Les jours utilisés sont calculés dynamiquement depuis `work_entries`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Configuration TOML
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[vehicles.voiture]
|
||||||
|
name = "Peugeot 308"
|
||||||
|
fuel = "diesel"
|
||||||
|
co2_per_km = 142 # g/km
|
||||||
|
|
||||||
|
[vehicles.velo]
|
||||||
|
name = "Vélo"
|
||||||
|
fuel = "none"
|
||||||
|
co2_per_km = 0
|
||||||
|
|
||||||
|
# Profils de trajet : distances par véhicule (km aller-retour)
|
||||||
|
[journeys.voiture_seule]
|
||||||
|
name = "Voiture seule"
|
||||||
|
distances = { voiture = 25 }
|
||||||
|
|
||||||
|
[journeys.voiture_velo]
|
||||||
|
name = "Voiture + Vélo"
|
||||||
|
distances = { voiture = 14, velo = 8 }
|
||||||
|
|
||||||
|
[journeys.velo_seul]
|
||||||
|
name = "Vélo seul"
|
||||||
|
distances = { velo = 24 }
|
||||||
|
|
||||||
|
# Barème kilométrique officiel (mise à jour annuelle)
|
||||||
|
# Structure : puissance fiscale -> liste de tranches [km_max, taux]
|
||||||
|
# km_max = null pour la dernière tranche (pas de limite)
|
||||||
|
[bareme_kilometrique.2025.cv5]
|
||||||
|
tranches = [
|
||||||
|
{ km_max = 3000, taux = 0.548 },
|
||||||
|
{ km_max = 6000, taux = 0.316 },
|
||||||
|
{ km_max = null, taux = 0.364 },
|
||||||
|
]
|
||||||
|
|
||||||
|
[bareme_kilometrique.2025.cv6_7]
|
||||||
|
tranches = [
|
||||||
|
{ km_max = 3000, taux = 0.655 },
|
||||||
|
{ km_max = 6000, taux = 0.374 },
|
||||||
|
{ km_max = null, taux = 0.435 },
|
||||||
|
]
|
||||||
|
# etc. pour les autres puissances fiscales
|
||||||
|
|
||||||
|
# Puissance fiscale par véhicule
|
||||||
|
[vehicles.voiture]
|
||||||
|
cv = 5
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Interface utilisateur
|
||||||
|
|
||||||
|
### Mobile-first
|
||||||
|
|
||||||
|
Toutes les vues sont conçues pour mobile en premier (Tailwind responsive).
|
||||||
|
|
||||||
|
### Page Dashboard (principale)
|
||||||
|
|
||||||
|
- **Carte "Aujourd'hui"** : boutons rapides "Arrivée" / "Départ" (horodatage automatique), sélecteur de profil de trajet
|
||||||
|
- **Synthèse semaine courante** (lun-dim) : total heures, écart vs objectif (5 × 7h45 = 38h45)
|
||||||
|
- **Synthèse mensuelle** : jours travaillés, km par véhicule, CO2
|
||||||
|
- **Solde congés/RTT** : jauge visuelle (ex: "12/18 RTT utilisés")
|
||||||
|
|
||||||
|
### Page Saisie / Édition d'un jour
|
||||||
|
|
||||||
|
- Sélecteur de date
|
||||||
|
- Type de journée (boutons radio visuels)
|
||||||
|
- Plages horaires : liste de paires heure début/fin, bouton "+ Ajouter une plage" (via HTMX)
|
||||||
|
- Profil de trajet (masqué si TT, MALADE, CONGE, RTT, FERIE)
|
||||||
|
- Commentaire libre
|
||||||
|
|
||||||
|
### Page Rapports
|
||||||
|
|
||||||
|
- **Frais réels** : total annuel, détail par véhicule, tableau récapitulatif
|
||||||
|
- **CO2** : total annuel par véhicule
|
||||||
|
- **Historique mensuel** : tableau des jours avec filtres
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Calculs métier
|
||||||
|
|
||||||
|
### Temps de travail
|
||||||
|
- Référence : 7h45/jour, 5j/semaine (38h45/semaine)
|
||||||
|
- GARDE : 10h (9h-19h)
|
||||||
|
- ASTREINTE : selon les plages time_slots renseignées
|
||||||
|
- Temps total d'une journée = somme des time_slots
|
||||||
|
|
||||||
|
### Frais kilométriques (frais réels)
|
||||||
|
- Utilise le barème kilométrique officiel configuré dans config.toml
|
||||||
|
- Calcul annuel : total km voiture × taux selon tranche kilométrique et puissance fiscale
|
||||||
|
|
||||||
|
### CO2
|
||||||
|
- CO2 (g) = km × co2_per_km (configuré par véhicule)
|
||||||
|
|
||||||
|
### Solde congés/RTT
|
||||||
|
- Déduit dynamiquement depuis work_entries (count des day_type = CONGE/RTT pour l'année)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Déploiement
|
||||||
|
|
||||||
|
```
|
||||||
|
HAProxy (TLS + auth basic) → Gunicorn (127.0.0.1:5000) → Flask app
|
||||||
|
```
|
||||||
|
|
||||||
|
Pas de gestion d'authentification dans l'application elle-même.
|
||||||
Reference in New Issue
Block a user