gigafibre-fsm/docs/field-tech-app.md
louispaulb 98458861c3 feat(dispatch): capacité AM/PM, durées additives, capture terrain (/field), sync techs
Hub (lib/roster.js, vision.js, legacy-dispatch-sync.js, server.js) + Ops + pont legacy.

- Capacité par jour AM/PM (Soir = réserve garde/urgence, jamais offerte) calculée
  client-side sur les techs visibles -> suit le filtre de compétence.
- Modèle de durée ADDITIF (caractéristiques, tableur inline) + auto-détection
  DÉTERMINISTE par mots-clés (sans IA permanente) ; est_min branché sur capacité + pool.
- Capture terrain passive : endpoints publics /field (job/tech/checkpoint/ts/photo/
  device/vision), tokens HMAC signés sans PII ; dérive actual_start/end. UI hébergée
  public/field-app.html (liste/carte Mapbox/Street View/photo/scan MLKit->Gemini).
- Chrono job (start/finish), repositionnement carte (set-location), vue satellite,
  Street View clic-droit, année devant les dates dues groupées.
- Sync techniciens : rapport de réconciliation 3 systèmes (staff legacy / Dispatch
  Technician / groupe Authentik), application MANUELLE, zéro écriture Authentik (+11 fiches).
- vision.js : extractEquipment() réutilisable (marque/modèle/série/MAC/codes-barres).
- Pont legacy (ops_reassign.php) : désassignation reflétée, fermeture ticket, retour
  au pool ; notification courriel à l'assignation.

Déployé sur le hub ; ce commit aligne le repo sur l'état en production.

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

4.9 KiB
Raw Blame History

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.