204 lines
5.6 KiB
Markdown
204 lines
5.6 KiB
Markdown
# 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.
|