# App technicien & capture passive du temps (durées apprises)

> But : mesurer **sans effort tech** le temps réel passé par job → apprendre les durées par **type × technicien** → alimenter le recommandeur « prochaine dispo » et le solveur. Principe directeur : **aucun tap dédié** — la durée se *déduit* d'événements que le tech produit déjà + géorepérage GPS automatique.

## 1. Modèle « fil de checkpoints »
Chaque job accumule des **checkpoints** horodatés (et géolocalisés). La durée réelle = **1er checkpoint sur place → dernier** (ou entrée→sortie de géorepérage).

| Type de checkpoint | Source | Effort tech |
|---|---|---|
| `geo_enter` / `geo_exit` | Géorepérage GPS (zone de l'adresse) | **nul** (auto) |
| `scan` (série / MAC / code-barre) | Caméra app (modem, ONU, mesh, STB) | déjà fait (activation) |
| `photo` / `signature` | App | déjà fait |
| `reply` | Réponse au ticket | déjà fait |
| `manual_start` / `manual_finish` | Override répartiteur (Ops) ou tech | filet de sécurité |

**Dérivation** : `actual_start` = 1er checkpoint « sur place » (geo_enter, ou 1er scan/photo/reply à < R m de l'adresse) ; `actual_end` = dernier ; `actual_minutes = end − start`. Les checkpoints hors-zone (> R m) sont ignorés pour la durée mais conservés pour l'audit.

## 2. Backend (cette itération — indépendant de l'app)
- **Endpoint public token-gated** `POST /field/checkpoint` `{ token, type, ts, lat, lon, acc, ref }` → vérifie le token (HMAC du job), enregistre le checkpoint, recalcule `actual_start/end` du Dispatch Job, ajoute une ligne d'audit dans `completion_notes`. Réponse : `{ ok, on_site, distance_m, minutes }`.
- **Lecture** `GET /field/job?t=<token>` → infos job (sujet, client, adresse, coords, état) pour l'app.
- **Token** = `base64url(jobName).hmac12` signé (`crypto`, secret stable du hub) → stateless, valable pour tout job, aucun champ DB ni login.
- `/field` + `/field/*` câblés **publics** dans `server.js` (calqués sur `/book`, hors forwardAuth Authentik).

## 3. App Capacitor (projet natif dédié — `apps/field-tech/`)
Véhicule unique pour les techs (remplace le mobile legacy) :
- **Géorepérage arrière-plan économe** : `@transistorsoft/capacitor-background-geolocation` (référence batterie + geofencing natif iOS/Android) — ou `@capacitor-community/background-geolocation` pour démarrer. On enregistre un geofence par job du jour ; `enter`/`exit` → POST `/field/checkpoint`.
- **Scan caméra** : `@capacitor-mlkit/barcode-scanning` → série/MAC → checkpoint `scan` **et** push vers GenieACS (par MAC) — réunit l'item roadmap « scan série/MAC des devices ».
- **Offline-first** : file d'attente locale (Preferences/SQLite) → rejoue les checkpoints à la reconnexion.
- **Auth** : login Authentik (groupe `tech`) → l'app reçoit ses jobs du jour + un token par job ; ou device-token. (À finaliser.)
- **Push** : web-push/FCM (déjà côté legacy) pour les nouvelles assignations.
- Builds : iOS (TestFlight) + Android (APK interne) ; permissions localisation « toujours » + caméra.

## 4. Amorçage SANS app (mineur legacy — cette itération)
Estimer une 1re durée par ticket depuis les événements legacy **déjà horodatés** : `ticket_msg.date_orig` du staff (réponses), création `device` (scan série), activation Ministra. Fenêtre sur-site ≈ (dernière activité − première) le même jour, filtrée < 8 h (exclut le multi-jour). **Bruité à l'unité, mais l'agrégat (médiane par type) donne une baseline d'apprentissage dès aujourd'hui.** Rapport `GET /dispatch/legacy-sync/mine-durations` (lecture seule).

## 5. Boucle d'apprentissage (consomme les durées)
1. Capture (checkpoints app + override Ops + baseline minée) → `actual_minutes` par job.
2. Agrégation : **médiane / p75 par sous-type × tech** (sous-types fins par mots-clés du sujet : « modem » vs « fil/fibre/drop » vs « ONT » vs « install »).
3. Remplace la table statique `DUR` (util/legacy-parse) + affine `skill_eff` (facteur vitesse par tech×compétence).
4. Le recommandeur « prochaine dispo » (`bookingSlots/fitBooking`) utilise la durée apprise ajustée au tech.

## 6. Phasage
- **P1 (maintenant)** : backend checkpoints (§2) + mineur legacy (§4).
- **P2** : recommandeur « prochaine dispo » (UI Ops) + sous-types fins + durées seed.
- **P3** : app Capacitor (§3) — scaffold → geofence → scan → offline → stores.
- **P4** : agrégation apprise (§5) qui remplace les seeds, une fois les données accumulées.

## 7. Sécurité / contraintes
- Endpoint checkpoint **public mais token-gaté** (HMAC par job) ; pas de PII dans le token.
- N'écrit QUE sur le Dispatch Job (ERPNext) ; ne touche pas le legacy en écriture.
- GPS = **preuve + contrôle de distance**, pas du tracking continu serveur (le geofencing reste sur l'appareil).
- Le tap répartiteur ▶/⏹ (Ops) reste comme override/fallback.
