gigafibre-fsm/docs/shifts-module-spec.md
louispaulb d8366ab0be docs: spec module Shifts (intégré dispatch, sans paie)
Spec v1 du module de gestion de shifts + approbations dans le dispatch
(décision build-our-own vs Frappe HR déjà actée: PG + multitenant + géofence-job).
Modèle de données, workflows d'approbation (ShiftRequest/Swap/AttendanceRequest),
géofence vs adresse du job dispatch, auto-attendance, auto-roster Timefold,
mapping validé vs Frappe HR, intégrations (Authentik/dispatch/ERPNext API), phasage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 18:06:19 -04:00

92 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Module Shifts — spécification (intégré au Dispatch, sans paie)
> Statut : spec v1 (2026-06-02). Décision d'architecture déjà prise
> (cf. `memory/project_punch_shift_tool.md`) : **build-our-own dans le domaine
> dispatch**, PAS Frappe HR. Raisons : ERPNext sur **PostgreSQL** (hrms = MariaDB-
> first), multitenant **shared-DB par org** (hrms = site/company-per-tenant), et
> géofence sur **adresse de job dynamique** (hrms = Shift Locations fixes).
## 1. Périmètre
Gestion de shifts + **approbations**. **Pas de paie.** On pousse les heures
approuvées vers ERPNext par API (la paie/compta reste côté ERPNext/legacy).
Validé contre la page Frappe HR « Shifts & Attendance » — toutes les fonctions
shift/approbation sont couvertes (voir mapping §7).
## 2. Contraintes transverses
- **Multitenant** : `org_id` sur chaque doctype (shared-DB), pour usage interne
Targo/Gigafibre **et** revente future à des tiers.
- **SSO** : Authentik OIDC (comme toutes les apps — cf. `reference_authentik`).
- **Stockage** : Postgres (hub ou base dédiée). Pas de dépendance ERPNext pour le
fonctionnement; sync sortante par API.
## 3. Modèle de données (doctypes / tables)
| Entité | Champs clés |
|---|---|
| **ShiftType** | `org_id`, nom, heure_début, heure_fin, durée_pause, seuil_demi_journée (h), seuil_absent (h), **grâce_retard** (min), **grâce_sortie_hâtive** (min), marge_pointage_avant/après (min), couleur |
| **ShiftAssignment** | `org_id`, employee_id, shift_type_id, date_début, date_fin, statut (Active/Inactive), source (manual/schedule/swap) |
| **ShiftSchedule** | `org_id`, nom, patron récurrent (RRULE hebdo), shift_type, équipe/employés, fenêtre de génération |
| **ShiftRequest** | `org_id`, employee_id, shift_type_id, date(s), motif, **approver_id**, statut (Draft→Submitted→Approved/Rejected), historique |
| **ShiftSwapRequest** | `org_id`, requester_id, counterparty_id, assignment_a, assignment_b, statut (Proposé→Accepté_par_pair→Approuvé_gestionnaire/Rejeté) |
| **Punch** (EmployeeCheckin) | `org_id`, employee_id, type (IN/OUT), timestamp, lat, lon, **job_id** (réf dispatch), device, source (mobile/web), within_geofence (bool) |
| **AttendanceDay** | `org_id`, employee_id, date, shift_assignment_id, statut (Présent/Retard/Demi/Absent), heures_calculées, première_IN, dernière_OUT |
| **AttendanceRequest** (régularisation) | `org_id`, employee_id, date, type, valeur_demandée, motif, **approver_id**, statut |
## 4. Workflows d'approbation
- **ShiftRequest** : employé soumet → `approver` (gestionnaire/département) approuve/rejette
→ si approuvé, crée/maj la `ShiftAssignment`. Multi-niveaux possible (chaîne d'approbateurs).
- **ShiftSwapRequest** : demandeur propose → **le pair accepte****gestionnaire approuve**
→ échange des deux `ShiftAssignment`. Tout refus annule.
- **AttendanceRequest** : employé demande correction → `approver` approuve → maj `AttendanceDay`.
- Approbateurs : configurables par employé / équipe / org. Notifs in-app + (option) SMS via le hub (Twilio).
## 5. Différenciateur — géofence vs **adresse du job dispatch**
À chaque punch terrain, on calcule la distance entre `(lat,lon)` du punch et
l'**adresse géocodée du job dispatch assigné** (RQA address DB), pas un lieu fixe.
`within_geofence = distance ≤ rayon_org` (configurable, ex. 150 m). Le punch hors
rayon est accepté mais **flaggé** (preuve de présence pour le dispatch).
## 6. Auto-attendance & auto-rostering
- **Auto-attendance** : à la clôture du shift, `AttendanceDay` est calculé depuis les
punchs vs le `ShiftType` (retard si IN > début+grâce ; sortie hâtive si OUT < fingrâce ;
demi-journée/absent selon seuils d'heures).
- **Auto-rostering** : **Timefold Solver** (Apache-2.0, successeur d'OptaPlanner)
même moteur que le dispatch par tags/compétences (`feedback_dispatch_tags`).
Contraintes : couverture des shifts, compétences requises, disponibilités,
équité, coûts. Génère des `ShiftAssignment` proposées (révisables).
## 7. Mapping Frappe HR → ce build (validé)
| Frappe HR | Ici |
|---|---|
| Shift Type (seuils, grâce) | ShiftType |
| Shift Assignment (+ outil lot) | ShiftAssignment (+ assignation en lot) |
| Repeating schedules / rotating | ShiftSchedule + Timefold |
| Shift Request + approbation multi-niveaux | ShiftRequest (workflow) |
| Roster drag-and-drop + échange | Vue roster + ShiftSwapRequest |
| Check-in/out mobile + géoloc | Punch (app field-tech) |
| Auto-attendance, retard/sortie hâtive | AttendanceDay |
| Attendance regularization | AttendanceRequest |
| Rapports/calendrier | Vues calendrier + exports |
| Paie | hors périmètre push heures ERPNext API |
## 8. Écrans
- **Ops (desktop)** : calendrier roster (drag-and-drop), définition ShiftType,
assignation en lot, file d'approbations (ShiftRequest/Swap/AttendanceRequest),
tableau de présence, déclencheur Timefold.
- **App field-tech** (déjà existante) : mon shift du jour, **punch IN/OUT** (géoloc
vs job), demander un shift / un échange, demander une régularisation.
## 9. Intégrations
- **Authentik OIDC** : auth + rôles (employé / gestionnaire / admin org).
- **Dispatch** : `Punch.job_id` jobs ; le solver partage les contraintes de skills/tags.
- **ERPNext** : push des heures approuvées (par employé/période) via l'API REST
(le hub a déjà `erpFetch` + token). Aucune dépendance hrms.
## 10. Phasage
- **MVP** : ShiftType, ShiftAssignment (+ lot), ShiftRequest + approbation, Punch
géoloc-vs-job, AttendanceDay auto, calendrier roster. Mono-org (Targo).
- **v2** : ShiftSchedule récurrent + **Timefold** auto-roster, ShiftSwap,
AttendanceRequest, multitenant `org_id` + revente, push ERPNext.