Cycle de vie complet de la mission KORIDO : 8 états, transitions manuelles et automatiques, démarrage à 2 étages, pause/reprise, light missions, suppression d'alertes pendant pause. 19 cas d'usage.
La mission passe par 8 états. Les transitions combinent des déclencheurs manuels (propriétaire, chauffeur) et des détections automatiques (moteur GPS). Le propriétaire peut annuler depuis n'importe quel état.
| Transition | Déclencheur préféré | Détection automatique |
|---|---|---|
| created → assigned | Owner assigne véhicule + chauffeur | — |
| assigned → en_route_to_origin | — | Mouvement vers l'origine, distance > 50 km |
| assigned → active | Chauffeur confirmé "chargement terminé" | Camion sort du waypoint origin |
| en_route_to_origin → active | Chauffeur confirmé à l'origine | Camion entre dans le waypoint origin |
| active → paused | Owner ou chauffeur signale problème | Système détecte arrêt prolongé inhabituel, demande aux 2 acteurs |
| paused → active | Owner envoie #R sur WhatsApp | Mouvement repris + réentrée dans le corridor |
| active → arrived | — (toujours auto) | Camion entre dans le rayon du dernier waypoint destination |
| arrived → complèted | Owner ferme manuellement | — (toujours manuel) |
| * → cancelled | Owner annule | — (toujours manuel) |
Schema : missions.status enum a 8 états. Colonnes ajoutees : paused_at, paused_reason, arrived_at, pause_count, total_pause_seconds.
La mission traverse 8 états de created a complèted ou cancelled. Chaque transition a un déclencheur préféré (manuel) et une détection automatique de secours.
Index unique partiel sur missions(vehicle_id) WHERE status IN ('assigned','en_route_to_origin','active','paused'). Rejet API : "Ce véhicule a deja une mission active."
Le moteur détecte un mouvement vers l'origine quand la distance diminue sous 50 km. Transition assigned → en_route_to_origin : ETA vers le point de chargement, prédiction carburant à l'arrivée.
Le démarrage de mission utilise deux couches de détection basées sur les waypoints imbriqués. Le port/entrepôt (rayon ~500m-1km) est imbriqué dans la ville (rayon 3-5km, rattachée au premier segment).
Déclencheur préféré : le chauffeur confirme "chargement terminé" sur l'app. Transition directe assigned → active. Aucune ambiguïté.
Si le chauffeur ne confirme pas : démarrage auto quand le camion sort du waypoint origin. Combinaison de 2 étages de détection pour éviter les faux positifs.
auto-detect(1) Sortie port = suspected_start : notification, PAS de changement de status. Réentrée port = reset. (2) Sortie ville = confirmed : status → active.
À chaque transition arrêt→mouvement dans la ville : push notification "K12 en mouvement dans Douala. Départ mission ?" Si confirmation → active. Sinon, attente du prochain cycle.
L'owner signale un faux départ après le démarrage auto. Mission reset à assigned. Les trips sont préservés dans le journal mais mission_id est délié. Pas de perte de données GPS.
Cron détecte : >2h après assignation, le camion ne s'approche pas du point de chargement (statique ou s'éloigne). Événement mission_delayed_start (info).
"K12 s'éloigne du point de chargement depuis 2h."
paused avec confirmation + liste des alertes supprimées + code de reprise #R6 raisons de pause : Panne / Route barree / Attente ordres / Controle / Personnel / Autre. La pause génère un événement mission_paused (info) dans vehicle_events.
Supprimées : corridor_deviation, unauthorized_stop (séquence). Actives : speeding, fuel_drain_anomaly, off_station_refueling, device_offline, towing_detected, power_disconnection.
suppression partielle3 déclencheurs : (1) Owner envoie #R sur WhatsApp, (2) chauffeur via l'app, (3) auto-detect : mouvement repris + réentrée dans le corridor. Événement mission_resumed.
Le camion entre dans le rayon du dernier waypoint destination. Transition automatique active → arrived. L'owner est notifié. Événement destination_reached.
Le propriétaire voit "K12 arrivé à N'Djamena" sur le dashboard et WhatsApp.
L'owner ferme la mission manuellement après vérification : paiement reçu, documents signés. La fermeture automatique balayerait les tickets d'action non résolus.
ownerÉtats terminaux : complèted, cancelled
L'owner annule depuis n'importe quel état non-terminal. Les données (trips, stops, positions) restent dans le journal. Seul le lien mission est clos.
owner depuis tout étatUne light mission se crée en 10 secondes : choisir un véhicule, choisir une destination. Tout le reste est optionnel. Si la destination est sur un corridor connu, le système assigne automatiquement la séquence de waypoints et le polygone corridor.
Vehicle_id + 1 destination. Auto-route si corridor connu : le système détermine la position actuelle, cherche les routes connues vers la destination, assigne la séquence de waypoints + polygone corridor.
D-light-missionsÉvolutive vers une mission complète à tout moment (ajouter waypoints, corridor, dates). Même mission_id, pas de perte de données.
Destination inconnue → journal uniquement. Pas de corridor, pas de segments, pas d'ETA. Le pin-drop est sauvegarde comme waypoint custom pour une utilisation future.
"Une light mission sans polygone corridor fournit un suivi journal mais pas une surveillance garde."
| Fonctionnalité | Mission complète | Light mission |
|---|---|---|
| Suivi de position | Oui | Oui |
| Événements carburant | Oui | Oui |
| Arrêts + labels | Oui | Oui |
| Notification d'arrivée | Oui | Oui |
| Polygone corridor | Oui | Si corridor connu |
| Corridor deviation | Oui | Non (si hors corridor) |
| Enregistrements de segment | Oui | Non (si hors corridor) |
| ETA prédictive | Oui | Non (si hors corridor) |
| Séquence de waypoints | Complète | 1 destination min |
| Évolutive | — | Oui, même mission_id |
| Temps de creation | 2-5 min | ~10 secondes |
Séquence de waypoints avec numérotation gappée (10, 20, 30, 40, 50) pour faciliter les insertions. L'entrée dans le dernier waypoint (role: destination) déclenche arrived automatiquement. Chaque paire de waypoints consécutifs génère un segment_record à l'arrivée au second waypoint. Forward-only matching (currentSéquencePosition) pour éviter les faux matchs sur les aller-retours.
Quand la deadline est dépassée : mission_sla_breach (critical). Ne s'auto-resolve jamais — une violation SLA est un fait. Nécessite une revue humaine.
Cron check | Notification immediate : WhatsApp + Dashboard + Portal
Pendant une pause : "ETA en attente — mission en pause" sur le portail de suivi. Si l'historique existe, ETA += durée estimée de réparation (moyenne flotte). Sinon, aucune prédiction.
portailETA recalculé = now + sum(p50_driving[restants]) + sum(avg_stop[restants]) + pause_duration
À chaque entrée de waypoint, l'ETA projetée est recalculée. Si elle dépasse la deadline : mission_delay_predicted (immediate). Si le camion rattrape, auto-resolve.
| Événement | Mode | Dashboard | Portal | Driver push | |
|---|---|---|---|---|---|
mission_sla_breach | immediate | oui | oui | oui | — |
mission_delay_predicted | immediate | oui | oui | oui | — |
mission_paused | immediate | oui | oui | oui | push |
mission_resumed | none | — | oui | oui | push |
destination_reached | immediate | — | oui | oui | — |
trip_started | none | — | oui | oui | — |
trip_complèted | none | — | oui | oui | — |
unauthorized_stop | immediate | oui | oui | — | push |
stop_labelled | none | — | oui | — | — |
Le driver push est indépendant du WhatsApp owner : les deux peuvent se déclencher pour le même événement. Les événements avec Driver = push sont : unauthorized_stop (label prompt), low_fuel_driving, towing_detected, driver_alarm_violation, mission_paused, mission_resumed.
KORIDO surveille pour le propriétaire afin que le propriétaire n'ait pas à surveiller le camion. Le système est proactif : détecter, classifier, notifier, et avertir uniquement quand l'attention est nécessaire.
| Phase véhicule | Mission ? | Ce que KORIDO fait |
|---|---|---|
| Transit pré-mission | Assignée, pas démarrée | ETA vers l'origine, alerte si retard, surveillance position |
| Mission active | En cours | Surveillance complète : corridor, waypoints, carburant, ETA, segments, événements |
| Ordres informels | Aucune (instructions verbales) | Position, proximite waypoints, notifications, historique |
| Repos | Aucune | Position, batterie, alertes offline, détection de gap |
Mission-Optional : le moteur tourne de façon identique avec ou sans mission active. mission_id est nullable partout. Pas de mission = pas de polygone corridor, donc detectCorridorDeviation ne retourne rien. Tout est piloté par des FK nullables, pas des branches if/else.
Deux flux de télémétrie : télémétrie machine (GPS, capteurs, moteur) = automatique, toujours active. Télémétrie humaine (app chauffeur) = manuelle, événementielle. L'app chauffeur est la couche de labellisation — l'humain sur la route qui confirme, annote et classifie ce que la machine détecte. Conception pour dégradation gracieuse : fonctionne sans input chauffeur, fonctionne mieux avec.