Field operations
Page specs BO-16 to BO-26: delegates, zones, objectives, the tour planner, tour editor and live tour detail, visits and visit configuration.
These pages plan and follow the field work of the delegates (délégués commerciaux) (cahier §4.5). Delegates work in the offline-first delegate app. The back-office creates zones, objectives and tours (tournées), which sync to the app (SYN-01). It receives positions, visits, reports and closings in return, live through the event stream. Tour and visit statuses are TourStatus and VisitStatus.
Defaults used on these pages (tunable settings, several still open decisions):
- GPS check-in tolerance 150 m, with accuracy of 100 m or better.
- Location sampled only while a tour is
IN_PROGRESS, every 5 minutes or 200 m. - Positions kept 90 days.
- One tour per delegate per day: the delegate app shows a single « tournée du jour » (
delegate.tours.today).
| ID | Screen | Section | Template | Release | Design | Build |
|---|---|---|---|---|---|---|
BO-16 | Delegates list | Field | template | V1 | Day 19 | DSH-08 |
BO-17 | Delegate detail & performance | Field | bespoke | V1 | Day 19 | DSH-08 |
BO-18 | Delegate create / edit | Field | template | V1 | Day 19 | DSH-08 |
BO-19 | Zones (list + map editor) | Field | bespoke | V1 | Day 19 | DSH-08 |
BO-20 | Objectives | Field | template | V1 | Day 19 | DSH-08 |
BO-21 | Tour planner (calendar) | Field | bespoke | V1 | Day 19 | DSH-08 |
BO-22 | Tour editor (stops, order, recommendation) | Field | bespoke | V1 | Day 19 | DSH-08 |
BO-23 | Tour live detail | Field | bespoke | V1 | Day 19 | DSH-08 |
BO-24 | Visits list | Field | template | V1 | Day 19 | DSH-08 |
BO-25 | Visit detail | Field | template | V1 | Day 19 | DSH-08 |
BO-26 | Visit types & checklist templates | Field | template | V1 | Day 19 | DSH-08 |
BO-16 — Delegates list
| Field | Value |
|---|---|
| Template | List |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-08 |
| Route | /field/delegates |
| Requirements | FLD-01 · FLD-02 |
| Permissions required | field.view · field.create (« Nouveau délégué ») · field.update (suspend, reactivate) · field.export |
Purpose. List the delegates with their zones, today's tour and their month to date.
Who uses it. Commercial admin, direction, super admin.
Entry points. Terrain › Délégués, and delegate names anywhere in the back-office.
Layout.
| Column | Source field | Sortable | Default visible |
|---|---|---|---|
| Délégué | displayName + avatar | Yes | Yes |
| Code | code | Yes | Yes |
| Téléphone | phone | No | Yes |
| Zones | zones[].name | No | Yes |
| Statut du compte | accountStatus | Yes | Yes |
| Tournée du jour | todayTour.status (TourStatus pill, or « Aucune ») + progress « 7 / 12 » | Yes | Yes |
| Revendeurs assignés | assignedResellersCount | Yes | Yes |
| Visites du mois | monthVisitsDone / monthVisitsPlanned | Yes | Yes |
| Objectif du mois | Achievement % of the main objective, with a bar | Yes | Yes |
| Dernière synchronisation | lastSyncAt (amber after 24 h) | Yes | No |
| Version de l'app | appVersion (amber below the latest version) | Yes | No |
| Consentement localisation | locationConsentAt (« Non donné » in danger) | Yes | No |
- Filters:
q,zone,wilaya,accountStatus,onTourToday(yes/no). - Default sort:
displayNameascending. - Row actions: « Ouvrir » (BO-17), « Modifier » (BO-18), « Planifier une tournée » (BO-22 prefilled), « Suspendre » / « Réactiver ».
- Export: XLSX / CSV.
Data. admin.delegates.crud (GET list, PATCH status).
Actions.
- « Suspendre »: « Suspendre Yacine M. ? Il ne pourra plus se connecter à l'application délégué ; ses tournées planifiées restent à réaffecter. ». A reason is required. Sessions are revoked and the action is audited
STATUS_CHANGE. - « Réactiver »: confirmation, then audited.
Rules.
- A suspended delegate is refused at sign-in with an explicit message (AUTH-02).
- Their future tours are flagged « Délégué suspendu » in BO-21.
Real-time. tour.started and tour.closed update the Tournée du jour column.
States. First use: « Aucun délégué », with « Nouveau délégué ».
Acceptance criteria.
- The visits column matches BO-24 for the delegate and the current month.
- Suspending a delegate signs them out of the app at the next request, and BO-21 flags their future tours.
BO-17 — Delegate detail & performance
| Field | Value |
|---|---|
| Template | Bespoke (Detail skeleton) |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-08 |
| Route | /field/delegates/[delegateId] (?tab=, ?period=) |
| Requirements | FLD-01 · FLD-02 · ANA-03 · ORD-09 · IVT-03 |
| Permissions required | field.view · field.update (edit, reassign resellers) · crm.update (bulk reassignment of resellers) |
Purpose. Measure one delegate's results against their objectives (cahier §4.5 « Planifier l'activité terrain et mesurer les résultats commerciaux »), and see their tours, visits, resellers and invitations.
Who uses it. Commercial admin (one-to-ones, coaching), direction.
Entry points. BO-16, the classement table of BO-05, delegate links, and BO-06.
Layout.
- Header: avatar, name, code, phone, zones, account status, today's tour pill, app version, last sync, location consent date. Actions: « Modifier », « Planifier une tournée », « Réaffecter ses revendeurs ».
- Period selector:
week,month(default),quarteror a custom range. - Tabs:
- Performance (default):
- KPI cards:
- Visites réalisées / planifiées and rate.
- Inscriptions (prospects created).
- Installations (invitations reaching
APP_INSTALLED). - Comptes créés.
- Premières commandes: attributed to the delegate (ORD-09).
- Commandes and CA HT: counted orders attributed to the delegate, same basis as BO-04.
- Taux de conversion (prospects → first orders).
- Kilomètres (from tour trails).
- Durée moyenne de visite.
- Check-ins dans la tolérance (%).
- Objective bars per
ObjectiveMetric(target, actual, %). - Trend chart (visits and revenue per week).
- KPI cards:
- Tournées: tours table (number, date, status, stops done/planned, km, closing comment). A row opens BO-23.
- Visites: the BO-24 table filtered on the delegate.
- Revendeurs: assigned resellers (BO-09 columns), with bulk « Réaffecter ».
- Invitations: the funnel sent → installed → account → verified → catalog → first order, with counts and conversion between steps, and the invitation list.
- Profil: zones, communes covered, start point, devices.
- Performance (default):
Data.
admin.delegates.crud(GET one).admin.delegates.performance(from,to).admin.objectives.crud.admin.tours.listandadmin.visits.listwithdelegate=.admin.resellers.listwithdelegate=.admin.invitations.listwithdelegate=.
Actions. « Réaffecter ses revendeurs » calls admin.resellers.bulk (ASSIGN) after « Réaffecter 86 revendeurs de Yacine M. à Samir K. ? ». It is audited per reseller, and both delegates are notified.
Rules.
- The figures use the same definitions as BO-04 and the delegate app's performance screen (FLD-19), so both show the same numbers.
- Revenue and orders are attributed through the order's delegate snapshot.
- Kilometres sum the straight-line distance between consecutive pings of the period's tours.
Real-time. visit.completed and tour.closed for this delegate refresh the Performance cards (debounced 10 s).
States.
- No tour in the period: « Aucune tournée sur la période ».
- No objective: « Aucun objectif défini », with a link to BO-20.
Acceptance criteria.
- For a given month, the figures equal the delegate app's « Mes performances » for the same month.
- First orders attributed through assisted orders count for the source delegate, even after the reseller is reassigned.
- « Réaffecter » moves all assigned resellers and records one
ResellerAssignmentper reseller.
BO-18 — Delegate create / edit
| Field | Value |
|---|---|
| Template | Form |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-08 |
| Route | /field/delegates/new · /field/delegates/[delegateId]/edit |
| Requirements | FLD-01 · ADM-01 · GEO-02 |
| Permissions required | field.create (new) · field.update (edit) |
Purpose. Create a delegate account with its profile, zones and start point, or edit them.
Who uses it. Commercial admin, super admin.
Entry points. « Nouveau délégué » on BO-16, « Modifier » on BO-16 and BO-17.
Layout.
| Field | Type | Validation | Default | Help text |
|---|---|---|---|---|
| Prénom, Nom | Text | Required, 2–40 characters each | — | — |
| Téléphone | Phone | Required, unique among users (sign-in identifier) | — | « Identifiant de connexion à l'application délégué » |
| Optional, unique | — | — | ||
| Code délégué | Text, uppercase | Required, unique, 2–10 characters A–Z 0–9 - | Suggested from the zone (ORN-01) | Assumption: free format chosen by HOCO |
| Zones | Multi-select of zones | At least one | — | Defines the delegate's scope (ACL-03) |
| Point de départ | Map picker + address | Optional | The centroid of the first zone | Used by the recommended visit order (BO-22) |
| Langue de l'application | Select | — | Français | — |
| Envoyer les accès | Checkbox (create only) | — | Ticked | « Un SMS avec un mot de passe temporaire est envoyé au délégué. » |
Data. admin.delegates.crud (POST or PATCH, with version), admin.zones.crud (GET).
Actions.
- « Créer le délégué » creates the
User(typeDELEGATE, roleDELEGATE) and itsDelegateProfile, then sends the temporary password by SMS when the box is ticked. AuditedCREATE. - « Enregistrer » is audited
UPDATE. - Removing a zone that holds planned tours or assigned resellers asks: « Retirer la zone Oran Est ? 12 revendeurs et 3 tournées planifiées sont concernés. »
Rules.
- The phone is unique across all users:
409 PHONE_ALREADY_EXISTSnames the existing account type. - Zone changes sync to the app at the next delta: points of sale outside the new scope disappear from the app.
- The location consent itself is given by the delegate in the app (DA-04). The back-office only displays it.
Real-time. None.
States. Unsaved changes are guarded. SMS sending failure shows « Délégué créé, mais l'envoi du SMS a échoué — Renvoyer les accès » (via admin.users.resetPassword).
Acceptance criteria.
- A new delegate receives the SMS, signs in to the delegate app, and must change the temporary password.
- After a zone is removed, the delegate no longer sees that zone's points of sale after sync.
- Reusing a staff user's phone is refused with a clear message.
BO-19 — Zones (list + map editor)
| Field | Value |
|---|---|
| Template | Bespoke |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-08 |
| Route | /field/zones (?zone= selected) |
| Requirements | GEO-02 · GEO-01 · FLD-01 |
| Permissions required | field.administer |
Purpose. Group wilayas and communes into commercial zones and assign them to delegates (cahier §4.5 « Attribution des wilayas, communes et points de vente »).
Who uses it. Commercial admin, super admin.
Entry points. Terrain › Zones, and zone links from BO-16 to BO-18.
Layout.
- Left panel: the zone list (name, colour, delegates, number of communes, resellers, prospects), « Nouvelle zone » and a search field.
- Right: the map editor.
- Commune polygons, coloured by zone. A commune outside any zone shows hatched grey.
- Click a commune to toggle it in the selected zone. Shift-click selects a range. « Ajouter toute la wilaya » sits in the wilaya tooltip.
- Above the map, a tree list (wilaya ▸ communes, with checkboxes) mirrors the map for keyboard use.
- Zone form (drawer):
- Nom: required, unique.
- Code: required, unique.
- Couleur.
- Délégués: multi-select.
- Description.
- Counts: communes, resellers, prospects, active resellers.
Data.
admin.zones.crud.reference.wilayasandreference.communes.- Commune boundaries come from a static GeoJSON shipped with the dashboard. Assumption — the dataset is still to choose; without polygons, the editor falls back to the tree list and commune centroids.
Actions.
- « Enregistrer la zone » (PATCH with the commune list) shows a summary first: « +4 communes, −1 commune ; 37 revendeurs changent de zone. »
- « Supprimer » is allowed only for a zone without delegates and without planned tours. Otherwise it is refused, with « Désactivez ou videz la zone d'abord ».
- Both are audited.
Rules.
- A commune belongs to at most one zone. Selecting a commune owned by another zone asks « Déplacer Bir El Djir de Oran Ouest vers Oran Est ? ». Assumption — overlapping zones are not supported in V1.
- Changing a zone updates the zone of the resellers it contains. Delegates' scopes follow at their next sync.
Real-time. None.
States. First use: « Créez votre première zone en sélectionnant des communes sur la carte. » A failed GeoJSON load falls back to the tree list.
Acceptance criteria.
- A commune cannot be in two zones at once.
- Adding a commune to a zone makes its points of sale visible to the zone's delegates after sync.
- The resellers count of a zone equals BO-09 filtered on that zone.
BO-20 — Objectives
| Field | Value |
|---|---|
| Template | List |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-08 |
| Route | /field/objectives (?period=MONTH&start=2026-11-01) |
| Requirements | FLD-02 |
| Permissions required | field.view · field.create · field.update · field.delete |
Purpose. Set targets per delegate and period for visits, sign-ups, installs, orders, first orders and revenue (cahier §4.5 « Objectifs de visites, inscriptions, installations et commandes »), and follow how far each delegate has got.
Who uses it. Commercial admin. Direction reads it.
Entry points. Terrain › Objectifs, and the objective bars of BO-17.
Layout.
- A matrix view:
- Rows are delegates and columns are
ObjectiveMetricvalues (Visites, Inscriptions, Installations, Premières commandes, Commandes, CA HT). - Each cell shows target, actual and a % bar (danger below 50 % past mid-period, success at 100 % or more).
- The period picker (
ObjectivePeriod: day, week, month) defaults to the current month.
- Rows are delegates and columns are
- A list view toggle shows one row per objective.
- Drawer « Objectif »:
- Délégué, or « Tous les délégués de la zone » (bulk create).
- Indicateur, Période, Début de période.
- Cible: integer 1 or more; amount in DA for revenue.
- Header action: « Reprendre les objectifs du mois précédent » (copies targets to the selected month).
Data. admin.objectives.crud. Actuals come with the list.
Actions.
- Create, edit and delete are audited. Deleting a running objective asks for confirmation.
- Copying shows « Créer 48 objectifs pour novembre 2026 à partir d'octobre ? »
Rules. Metric definitions:
VISITS: visitsDONE.SIGNUPS: prospects created by the delegate.APP_INSTALLS: invitations reachingAPP_INSTALLED.FIRST_ORDERS: first orders attributed to the delegate.ORDERSandREVENUE: counted orders attributed to the delegate, net HT (same basis as BO-04).
An objective is unique per delegate, metric, period and start: 409 on a duplicate. Objectives sync to the delegate app (DA-22).
Real-time. None. Actuals refresh on focus.
States. No objective for the period: « Aucun objectif pour novembre 2026 », with the copy action.
Acceptance criteria.
- The actual of
VISITSfor a delegate and month equals BO-24's done count for the same filters. - Copying last month's objectives creates exactly one objective per delegate and metric that existed.
- Duplicates are refused.
BO-21 — Tour planner (calendar)
| Field | Value |
|---|---|
| Template | Bespoke |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-08 |
| Route | /field/tours (?view=week&date=2026-11-08&zone=&delegate=) |
| Requirements | FLD-03 · FLD-04 · CRM-08 |
| Permissions required | field.view (page) · field.create (plan, duplicate, recurring series) · field.update (move, cancel) |
Purpose. Plan tours daily, weekly or monthly (cahier §4.5 « Planification quotidienne, hebdomadaire ou mensuelle »). See at a glance who works where and when, how far today's tours have got, and which points of sale still need a visit.
Who uses it. Commercial admin (planning, usually on Thursday for the next week), super admin. Direction reads it.
Entry points. Terrain › Tournées, « Planifier une tournée » on BO-16 and BO-17, and the tour links of BO-06.
Layout
- Toolbar:
- Views « Jour », « Semaine » (default), « Mois ».
- Previous / « Aujourd'hui » / next.
- Filters Zone (
zone), Délégué (delegate, multi), Statut (status), « Avec arrêts prioritaires ». - Primary action « Planifier une tournée ».
- « Série récurrente ».
- Week view (resource timeline):
- One row per delegate (avatar, name, zone) and one column per day, Sunday to Saturday. Friday and Saturday are shaded but still plannable. Today is outlined.
- Tour chip in a cell:
TRN-2026-000045and theTourStatuspill.- « 12 arrêts » (« 7 / 12 » once started).
- The ordering-mode icon (padlock for
IMPOSED, shuffle forRECOMMENDED). - « 2 prioritaires » when there are
HIGHstops. - « Délégué suspendu » in danger when relevant.
- An empty cell shows « + Planifier » on hover.
- Day view: one row per delegate with planned start, stops, km estimate, live progress bar and last-position age. A click opens BO-23.
- Month view: calendar grid with a small chip per tour, coloured by status (one delegate selected), or counts per day (several delegates).
- Right drawer « À planifier » (toggle):
- Points of sale needing a visit in the filtered zone, in four groups:
- follow-ups of type
VISITdue by the end of the shown period (CRM-08); - prospects
NEW_PROSPECT,TO_CONTACTorINTERESTEDnever visited; - resellers not visited for more than 30 days;
- accounts awaiting validation (new points of sale).
- follow-ups of type
- Each item can be dragged onto a tour chip (adds a stop) or onto an empty cell (creates a tour with that stop).
- Points of sale needing a visit in the filtered zone, in four groups:
Actions
| Action | Endpoint | Confirmation / input | Optimistic | Audit | Notifies |
|---|---|---|---|---|---|
| « Planifier une tournée » or click an empty cell | — | Opens BO-22 with delegate and date | — | — | — |
| Drag a backlog item onto a chip | admin.tours.setStops (stops + 1) | Toast « Arrêt ajouté à TRN-… » with « Annuler » | Yes, rolled back on error | UPDATE | Delegate when the tour is today or tomorrow |
| Drag a backlog item onto an empty cell | admin.tours.create | « Créer une tournée pour Yacine M. le dim. 08/11 avec Boutique Nour ? » | No | CREATE | Delegate (« Nouvelle tournée planifiée ») |
Drag a PLANNED chip to another day of the same delegate | admin.tours.update (date) | « Déplacer la tournée au lun. 09/11 ? » | Yes | UPDATE | Delegate |
| « Dupliquer » (chip menu) | admin.tours.create, one per date | Date multi-picker; dates that already have a tour are disabled | No | CREATE ×N | Delegate |
| « Série récurrente » | admin.tours.create with recurrence | Delegate, weekdays, from–to (3 months max), stop template (an existing tour) | No | CREATE per tour | Delegate (one summary notification) |
| « Annuler la tournée » | admin.tours.cancel | « Annuler TRN-2026-000045 du 08/11 ? Le délégué en sera informé. » | No | STATUS_CHANGE (reason) | Delegate (push) |
A required free-text reason accompanies every cancellation.
Rules
- One tour per delegate per day. A second tour on the same date is refused (
409; Assumption: codeTOUR_ALREADY_PLANNED), and its drop target is disabled. - Dates: tours are planned for today or later. Past days are read-only.
- Statuses:
- The
PLANNED→TO_STARTtransition is made by the 00:05 job on the tour's day (TourStatus). - Only the assigned delegate can start a tour (FLD-04). The back-office never starts, suspends or closes one.
- The
- Moving tours: only
PLANNEDandTO_STARTtours can be moved or cancelled. The delegate cannot be changed on an existing tour (create a new one and cancel the old). - Stops must be points of sale in the delegate's zones or assigned to them (
403 OUT_OF_SCOPEotherwise), since the delegate could not open them in the app (ACL-03). - Recurring series create independent tours; editing one does not change the others.
- Suspended delegates keep their tours, which are flagged for reassignment.
Data. admin.tours.list (from, to, zone, delegate, status), admin.delegates.crud, admin.tasks.list (type=VISIT), admin.resellers.list (backlog filters).
Real-time.
tour.startedandtour.closedupdate the chip pill.visit.completedupdates « 7 / 12 ».- No reload is needed, and an open drawer is not disturbed.
States.
- Loading: a skeleton grid with delegate rows.
- No delegate in the filtered zone: « Aucun délégué dans cette zone », with a link to BO-18.
- Empty week: « Aucune tournée planifiée cette semaine », with « Dupliquer la semaine précédente » (creates the same tours one week later, skipping dates that already have a tour).
- Drop refused: the chip shakes, with a tooltip giving the reason (out of scope, already planned, past date).
Acceptance criteria
- Week, day and month views show the same tours for the same filters. Each tour appears exactly once per day.
- Planning a second tour for the same delegate and day is impossible, both by drag and from BO-22.
- Dragging an overdue Nouvelle visite follow-up onto Monday's chip adds the stop. After sync, the delegate's app shows it in Monday's programme.
- When a delegate starts a tour, its chip turns En cours within 5 s.
- A recurring series every Sunday and Tuesday for 4 weeks creates 8 tours with the template's stops.
BO-22 — Tour editor (stops, order, recommendation)
| Field | Value |
|---|---|
| Template | Bespoke (Form skeleton) |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-08 |
| Route | /field/tours/new?delegate=&date=&stops= · /field/tours/[tourId]/edit |
| Requirements | FLD-03 · FLD-17 · FLD-06 · FLD-16 |
| Permissions required | field.create (new) · field.update (edit, recommend order, cancel) |
Purpose. Compose one tour: the ordered stops with their priority, time slot and visit type, an imposed or recommended order, and the nearest-neighbour recommendation (cahier §4.5 « Ordre manuel ou recommandé des visites »; §6.2).
Who uses it. Commercial admin.
Entry points. BO-21 (« Planifier », chip « Modifier »), « Planifier une visite » from BO-09, BO-10 and BO-11 (stops preselected), and « Modifier » on BO-23.
Layout
- Header form:
| Field | Type | Validation | Default | Help text |
|---|---|---|---|---|
| Délégué | Select (active delegates) | Required; fixed after creation | From the URL | — |
| Date | Date picker | Required; today or later; no other tour that day | From the URL | — |
| Ordre des visites | Segmented: « Ordre imposé » (IMPOSED) / « Ordre recommandé » (RECOMMENDED) | Required | RECOMMENDED | « En ordre recommandé, le délégué peut réorganiser les visites restantes. » |
| Point de départ | « Point de départ du délégué » / « Personnalisé » (map pick) | — | The delegate's start point | — |
| Heure de départ prévue | Time | Optional | 08:30 | — |
| Note pour le délégué | Textarea | 500 characters max | — | Shown at the top of the tour in the app |
- Left panel, the stops list (drag handles, numbered):
- Each row:
- point of sale (name,
REV, status pill, commune); - Priorité toggle (
NORMAL/HIGH« Prioritaire »); - Créneau (from–to, optional);
- Type de visite (select, defaulting to the visit type set in settings);
- Objectif de l'arrêt (200 characters max);
- distance from the previous stop (km, straight line);
- estimated arrival time;
- remove (✕).
- point of sale (name,
- Stops already
DONEorNOT_DONE(tour in progress) are locked and greyed, with their status pill.
- Each row:
- Map (centre and right):
- The start marker and numbered stop markers in list order, joined by a polyline.
- Candidate points of sale of the delegate's scope as grey dots: click to add, lasso to add several.
- Markers flash when their row is hovered, and the other way round.
- « Ajouter des arrêts » panel (tabs):
- « Recherche »: scope-filtered search.
- « Relances dues »:
VISITtasks due by the tour date. - « Prospects à visiter ».
- « Non visités depuis 30 j ».
- « Sélection carte ».
- Totals bar: number of stops, total straight-line distance, estimated duration (travel + visit durations), estimated end time.
- Warnings shown in the totals bar:
- more than 25 stops (« Journée chargée »);
- stops without GPS;
- a stop already in another tour that day;
- a time slot that cannot be met by the estimate.
- Footer: « Recommander l'ordre » (secondary), « Annuler », « Enregistrer la tournée » (primary).
Recommended order
- « Recommander l'ordre » calls
admin.tours.recommendOrderwith the current stops and the start point. For a new tour, the draft is saved first. - The server returns an ordered list using a nearest-neighbour heuristic from the start point over stops that have GPS (FLD-17):
- stops without GPS are appended at the end and flagged;
- with « Garder les prioritaires en tête » ticked,
HIGHstops are ordered first (by nearest neighbour among themselves), then the others. Assumption — the operation accepts apriorityFirstflag.
- A preview dialog shows the old and new order side by side, with « Distance estimée : 48,6 km → 31,2 km ». Choices: « Appliquer » or « Garder mon ordre ».
- Applying changes the list only. « Enregistrer » persists it.
Time slots are not optimised in V1. Routing with time windows is V2 (FLD-18).
Estimates use straight-line distance × 1.3 at 30 km/h, plus each visit type's default duration. They are labelled « estimation » everywhere. Assumption — the factors are to tune during the pilot.
Data.
admin.tours.get(edit),admin.tours.create,admin.tours.update(header).admin.tours.setStops: the orderedstops[]withresellerId,priority,timeSlot,visitTypeIdandnote.admin.tours.recommendOrder.admin.resellers.listandadmin.resellers.map(candidates, scope-filtered).admin.tasks.list,admin.visitTypes.crud(GET).
Actions.
| Action | Endpoint | Confirmation | Optimistic | Audit | Notifies |
|---|---|---|---|---|---|
| « Enregistrer la tournée » (new) | admin.tours.create with stops | — | No | CREATE | Delegate: « Nouvelle tournée le 08/11 — 12 visites » |
| « Enregistrer » (edit) | admin.tours.update, then admin.tours.setStops | For a tour of today, TO_START: « Le délégué a peut-être déjà consulté cette tournée. Il sera notifié du changement. » | No | UPDATE (before/after stops) | Delegate, when the tour is today or tomorrow (push « Votre tournée du 08/11 a été modifiée ») |
| « Recommander l'ordre » | admin.tours.recommendOrder | Preview dialog (above) | — | — | — |
| « Annuler la tournée » (menu) | admin.tours.cancel | As in BO-21 | No | STATUS_CHANGE | Delegate |
Rules
- What can be edited, by status:
PLANNEDandTO_STARTtours are fully editable.- For
IN_PROGRESSandSUSPENDEDtours, only the remainingPLANNEDstops can be added, removed or reordered; visited stops are locked. Assumption — confirm with the field team; header fields are frozen (admin.tours.updateis limited to planned tours). COMPLETEDandCANCELLEDtours open read-only and redirect to BO-23.
- Stops:
- Stops must be in the delegate's scope (
403 OUT_OF_SCOPE). - A point of sale appears at most once per tour.
- A tour holds 1 to 40 stops. Assumption — the 40 cap is to confirm.
- Stops must be in the delegate's scope (
- Ordering mode: in
IMPOSEDmode the delegate cannot reorder (delegate.tours.reorderis refused). InRECOMMENDEDmode they can reorder the remaining stops, and the new order shows here. - Sync: the same order appears in the app's list and map (FLD-06). Changes reach the app through
sync.delta. - Concurrency: the tour carries
version. When the delegate reordered meanwhile, saving returns409 VERSION_CONFLICT. A dialog then shows the delegate's order, with « Recharger » or « Écraser avec mon ordre » (the latter only forPLANNEDstops not yet visited).
Real-time. visit.checked_in and visit.completed for this tour lock the corresponding stop rows live.
States.
- Empty tour: « Ajoutez des points de vente depuis la carte ou la liste ».
- Recommendation failure: « Recommandation impossible », and the order is unchanged.
- Delegate without GPS-located stops: the recommendation button is disabled with a tooltip.
- Map provider failure: list-only editing.
Acceptance criteria
- After « Recommander l'ordre » and « Appliquer », saving persists the recommended order. The delegate app's list and map show the stops in that order after sync.
- With
IMPOSED, the delegate app offers no reorder action. WithRECOMMENDED, it does, and a reorder made in the app is visible here on reload. - Adding a point of sale outside the delegate's zones is refused with « Ce point de vente n'est pas dans le périmètre du délégué ».
- On a tour in progress, visited stops cannot be moved or removed, and a new stop added at the end reaches the app.
- The preview shows the total distance before and after, and the applied order matches the server's response.
BO-23 — Tour live detail
| Field | Value |
|---|---|
| Template | Bespoke (Detail skeleton) |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-08 |
| Route | /field/tours/[tourId] (?tab=) |
| Requirements | FLD-13 · FLD-12 · FLD-04 · FLD-08 · FLD-15 · SYN-07 |
| Permissions required | field.view (page) · field.update (edit, cancel) · field.validate (reopen a closed tour) |
Purpose. Follow one tour live and review it afterwards (cahier §4.5 « Suivi du démarrage, des visites, des positions et de la clôture »):
- start time and position;
- each check-in with its distance to the point of sale;
- visit durations, photos and reports;
- the position trail;
- the closing summary with its comment.
The cahier's acceptance « La visite apparaît en temps réel dans le back-office » (§6.4) is checked here.
Who uses it. Commercial admin (live supervision, next-day review), direction.
Entry points. BO-06 (delegate popover, tours list), BO-21 chips, BO-17 Tournées, and BO-25 (link to its tour).
Layout
- Header:
TRN-2026-000045, theTourStatuspill and the ordering-mode pill.- The delegate (link to BO-17, « Appeler »), the date, and planned versus actual start.
- Progress « 7 / 12 visitées · 1 non réalisée ».
- Km travelled, last position age with its accuracy, and the sync badge (« 3 actions hors ligne reçues en différé »).
- Actions: « Modifier » (BO-22;
PLANNED,TO_START, or remaining stops while in progress), « Annuler » (PLANNED,TO_START), « Rouvrir » (COMPLETED, withfield.validate).
- Main area: the map, two thirds of the width.
- Planned stops are numbered markers coloured by
VisitStatus, with derived « En retard » in danger. - The live delegate marker sits on top, with a pulse while
IN_PROGRESS. - The trail is a polyline of the location pings (
admin.tours.track), coloured by time. Gaps longer than 15 min are dashed. - Check-in markers show a tolerance circle (150 m) around each point of sale, with a line to the actual check-in position labelled « 86 m » (success) or « 412 m » (danger). Low accuracy (over 100 m) is labelled « précision 140 m ».
- Toggles: « Trajet », « Check-ins », « Tolérance ».
- Planned stops are numbered markers coloured by
- Right panel, the stop timeline:
- Each stop shows:
- its planned slot;
- check-in time and distance, start/end, duration;
- its status pill;
- photo count (thumbnails);
- report summary (interest level, next action);
- the not-done reason (
VISIT_NOT_DONE_REASONlabel).
- A click selects the marker. « Voir la visite » opens BO-25.
- Each stop shows:
- Tabs:
- Visites (default).
- Trajet: pings table with time, lat/lng, accuracy, speed, and gaps.
- Clôture: the closing summary (FLD-12), as the delegate submitted it:
- visits done / planned, not-done count with reasons;
- new prospects, invitations, installs, accounts, first orders;
- orders and revenue HT;
- km;
- end-of-day comment;
- objectives achievement and conversion;
- closing time.
- Historique:
TourStatusChangeentries (planned, to start, started with position, suspended withTOUR_SUSPEND_REASON, resumed, completed, reopened), plus edits made in the back-office.
Data.
admin.tours.get: visits, check-ins, distances, photos, reports, closing summary, history andversion.admin.tours.track: the position trail.admin.tours.reopen,admin.tours.cancel.files.downloadUrlfor photos.
Actions.
| Action | Endpoint | Confirmation (FR) | Reason | Audit | Notifies |
|---|---|---|---|---|---|
| « Rouvrir la tournée » | admin.tours.reopen | « Rouvrir TRN-2026-000045 ? Le délégué pourra compléter les visites et devra clôturer à nouveau. » | Required | STATUS_CHANGE (COMPLETED → IN_PROGRESS) | Delegate (push) |
| « Annuler la tournée » | admin.tours.cancel | As in BO-21 | Required | STATUS_CHANGE | Delegate |
| « Appeler » | — | tel: link | — | — | — |
Rules.
- Who drives the tour: only the delegate starts, suspends, resumes and closes it (FLD-04). The back-office observes, cancels before the start, and reopens after closing.
- Location:
- Positions exist only while
IN_PROGRESS; sampling stops whileSUSPENDED(FLD-15). - Trails older than 90 days are deleted by retention. The trail tab of an older tour reads « Trajet supprimé (conservation 90 jours) », while check-in positions and distances stay with the visit.
- Positions exist only while
- Offline actions arrive with
occurredAt(device time) andreceivedAt. The timeline orders byoccurredAtand badges entries received more than 10 min late (« saisi hors ligne »). - Closing requires a reason for every unvisited stop and all offline data synced (cahier §6.9). The closing is definitive unless reopened by a holder of
field.validate.
Real-time.
delegate.positionmoves the marker and extends the trail (only for this tour's delegate).visit.checked_inturns the stop Arrivé, draws the check-in line, and flashes the row.visit.completedturns the stop Visité or Non réalisée, adds photo and report counts, and updates progress.tour.startedandtour.closedupdate the header and open the Clôture tab on close.- All without a page reload.
States.
- Not started (
PLANNED/TO_START): planned markers only, with « La tournée n'a pas encore démarré ». - Suspended: a banner gives the reason and time; the last position is greyed.
- Position stale for more than 15 min while
IN_PROGRESS: amber header chip « Position non mise à jour depuis 18 min ». - Stream lost: a banner;
admin.tours.getis polled every 30 s. - Cancelled: a read-only banner with the reason.
Acceptance criteria
- A check-in made in the delegate app appears here within 5 s with its distance to the point of sale. A check-in beyond 150 m is shown in danger with its distance.
- The trail shows the pings of the tour only while it was
IN_PROGRESS, with gaps during suspensions. - After closing, the Clôture tab shows the delegate's summary and comment exactly as submitted, and the indicators of BO-04 and BO-17 are recalculated (cahier §6.9 acceptance).
- « Rouvrir » requires
field.validateand a reason. The delegate app then allows completing the tour again. - Visits recorded offline show at their
occurredAttime with the « saisi hors ligne » badge.
BO-24 — Visits list
| Field | Value |
|---|---|
| Template | List |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-08 |
| Route | /field/visits |
| Requirements | FLD-08 · FLD-09 · FLD-14 |
| Permissions required | field.view · field.export |
Purpose. Analyse all visits across tours: what was done, where, how long, with which outcome, and why visits were not done (cahier §4.5 « Validation des nouveaux points de vente et analyse des rapports »).
Who uses it. Commercial admin, direction.
Entry points. Terrain › Visites, the Visites réalisées card on BO-04, BO-17 and BO-11.
Layout.
| Column | Source field | Sortable | Default visible |
|---|---|---|---|
| N° | number (VIS-2026-001234) | Yes | Yes |
| Date | checkedInAt, else plannedDate + slot | Yes (default descending) | Yes |
| Délégué | delegate.displayName | Yes | Yes |
| Point de vente | reseller.storeName + status pill | Yes | Yes |
| Tournée | tour.number | Yes | Yes |
| Type | visitType.name | Yes | Yes |
| Statut | status (VisitStatus, plus derived « En retard ») | Yes | Yes |
| Distance check-in | checkInDistanceM (danger beyond tolerance) | Yes | Yes |
| Durée | durationMin | Yes | Yes |
| Intérêt | report.interestLevel | Yes | Yes |
| Prochaine action | report.nextAction | No | No |
| Motif non réalisée | notDoneReason | No | No |
| Photos | photosCount | Yes | No |
| Problèmes signalés | report.issueTags[] (VISIT_ISSUE_TAG) | No | No |
| Hors ligne | « saisi hors ligne » badge when receivedAt − occurredAt exceeds 10 min | No | No |
- Filters:
from/to(default this week),delegate,zone,wilaya,status,visitType,interestLevel,issueTag,notDoneReason,outOfTolerance=true,reseller,hasReport. - Export: XLSX / CSV.
Data. admin.visits.list, reference.lists (VISIT_NOT_DONE_REASON, VISIT_ISSUE_TAG).
Actions. A row opens BO-25. « Exporter ».
Rules.
- A
NOT_DONEvisit always has a reason (FLD-09). The column is never empty for them. - Distances are computed by the server from the check-in position to the point of sale's GPS (GEO-03).
Real-time. visit.checked_in and visit.completed show the banner « 3 nouvelles visites — Actualiser » rather than inserting rows.
States. First use: « Les visites apparaîtront dès la première tournée. »
Acceptance criteria.
outOfTolerance=truelists exactly the visits whose check-in distance exceeds the tolerance setting.- Every
NOT_DONErow shows its reason label. - The count for a delegate and day equals BO-23's progress for that tour.
BO-25 — Visit detail
| Field | Value |
|---|---|
| Template | Detail |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-08 |
| Route | /field/visits/[visitId] |
| Requirements | FLD-08 · FLD-10 · FLD-14 · CRM-10 |
| Permissions required | field.view · field.validate (unlock for correction) · crm.update (create a task) |
Purpose. Everything about one visit: check-in proof, timing, checklist, note, photos and the structured report that triggered the follow-up (cahier §6.4, §6.8).
Who uses it. Commercial admin.
Entry points. BO-24, BO-23 timeline, BO-11 Visites, and the validation queue (origin visit of a new point of sale).
Layout.
- Header:
VIS-2026-001234, theVisitStatuspill and a « Verrouillée » badge once finished.- Delegate, point of sale (link to BO-11), tour (link to BO-23), visit type.
- Times: check-in, start, end, duration.
- The « saisi hors ligne » badge with
occurredAt/receivedAtwhen relevant.
- Check-in card: a mini-map with the point of sale, the tolerance circle and the check-in position; distance and accuracy; the result « Dans la tolérance » or « Hors tolérance ».
- Sections:
- Checklist: items of the template snapshot, ticked or not, with required items marked.
- Note: 300 characters max.
- Photos: gallery with capture time and position, opened through signed URLs.
- Rapport (FLD-10):
- person met (
PERSON_ROLE); - interest level (
InterestLevel); - products and promotions presented;
- issues (
VISIT_ISSUE_TAG) and needs; - next action (
NextAction) and follow-up date, with a link to the created task; - comments and attachments.
- person met (
- Non réalisée: reason and comment, instead of the sections above.
- Historique: status changes and unlock events.
Data. admin.visits.get, admin.visits.unlock, admin.tasks.create, files.downloadUrl.
Actions.
- « Déverrouiller pour correction » (
field.validate): confirmation « Autoriser Yacine M. à corriger cette visite ? La modification sera journalisée. ». A reason is required.- It is audited
UPDATEand notifies the delegate (push). - The visit becomes editable in the app until it is finished again.
- It is audited
- « Créer une tâche » opens the BO-14 drawer, prefilled.
Rules.
- A finished visit is locked (FLD-08, cahier §6.4 « Une visite terminée ne peut être modifiée sans permission »). Corrections after unlocking keep the previous values in the history.
- Photos may be mandatory per visit type (BO-26). A finished visit of such a type always has them.
Real-time. visit.completed for this visit (after an unlock) reloads the page data.
States. Photos still uploading from the delegate's queue: « 2 photos en cours de synchronisation ». Missing point-of-sale GPS: « Distance non calculable : point de vente sans position GPS ».
Acceptance criteria.
- The detail shows check-in position, distance, times, checklist, note, photos and report as recorded in the app.
- The follow-up created by the report's next action is linked and opens in BO-14.
- Unlocking requires
field.validateand a reason, and the change made by the delegate afterwards appears in the history with before/after values.
BO-26 — Visit types & checklist templates
| Field | Value |
|---|---|
| Template | Settings |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-08 |
| Route | /field/visit-types (?tab=types or checklists) |
| Requirements | FLD-16 · FLD-08 · FLD-10 |
| Permissions required | field.administer |
Purpose. Configure what each kind of visit requires: photos, report sections and checklist (cahier §6.4 « Les photos peuvent être obligatoires selon le type de visite », §6.8 « Les champs affichés peuvent dépendre du type de visite »).
Who uses it. Commercial admin, super admin.
Entry points. Terrain › Types de visite.
Layout. Two tabs, each a list with a drawer editor.
| Tab | Field | Type | Validation | Default |
|---|---|---|---|---|
| Types de visite | Nom | Text | Required, unique, 60 characters max | — |
| Description | Text | 200 characters max | — | |
| Photos obligatoires | Number + kinds (PhotoKind chips) | 0–5 | 0 | |
| Rapport obligatoire | Toggle | — | On | |
| Sections du rapport | Checkboxes (person met, interest, products presented, promotions presented, issues, next action, attachments) with « obligatoire » per section | At least one when the report is mandatory | All | |
| Checklist | Select a template | Optional | — | |
| Durée prévue | Minutes | 5–240 | 20 | |
| Type par défaut | Toggle (one type only) | — | — | |
| Actif | Toggle | — | On | |
| Checklists | Nom | Text | Required, unique | — |
| Éléments | Ordered list: label (120 characters max), « obligatoire » toggle, drag to reorder | 1–30 items | — | |
| Actif | Toggle | — | On |
Data. admin.visitTypes.crud, admin.checklists.crud.
Actions. Save each drawer, audited CREATE / UPDATE. Deactivating a type used by planned tours asks: « 14 visites planifiées utilisent ce type ; elles le conservent. Désactiver ? »
Rules.
- Nothing is deleted (no
DELETEin the contract); types and templates are deactivated. - Visits keep a snapshot of the checklist labels (
VisitChecklistItem), so editing a template never changes past visits. - Changes reach the delegate app through
sync.delta. Visits already started keep the rules they started with.
Real-time. None.
States. First use: the seeded types (« Prospection », « Visite de suivi », « Aide à la première commande ») are listed. Assumption — the seed is to validate with HOCO.
Acceptance criteria.
- With Photos obligatoires = 1 Façade on a type, the delegate app refuses to finish such a visit without a façade photo (
delegate.visits.end). - Editing a checklist does not change the checklist shown on past visits in BO-25.
- Only one type can be the default.
CRM
Page specs BO-09 to BO-15: resellers and prospects list and map, reseller 360°, create and edit form, validation queue, follow-ups and segments.
Catalog and stock
Page specs BO-27 to BO-37 and BO-71: products, the product editor with the three customer-type prices and attributes, brands, categories, the price grid, the import wizard, stock pages and attribute definitions.