MDA-07 — Delegate app — new reseller (offline) & edit
Sign-up form with wilaya/commune pickers, GPS capture, façade photo, status stepper, duplicate-phone feedback; client-generated id for offline creation.
| Field | Details |
|---|---|
| Task code | MDA-07 |
| Phase | P1 — V1 build & integration |
| Product scope | V1 |
| Status | Planned |
| Start | Mon 7 Dec 2026 |
| Due | Tue 8 Dec 2026 |
| Responsible | Imad — Mobile developer (Flutter) |
| Co-responsible | — |
| Effort | 1.25 person-day(s) planned · 4 from scratch · size S |
| Area · app | Delegate app · mobile |
| Depends on | DES-14 |
| Unblocks | — |
| Milestones | — |
Summary
Sign-up form with wilaya/commune pickers, GPS capture, façade photo, status stepper, duplicate-phone feedback; client-generated id for offline creation.
Description
Signing up new points of sale in the field is the delegate's main growth lever: the record must be complete (GPS, façade photo), duplicate-free on the main phone, linked to the creating delegate, pending validation, and creatable with no network (FLD-11, CRM-03, CRM-10, SYN-04). Scope: new reseller DA-14 (store and owner, phones, wilaya/commune pickers, address, GPS capture with map pin, façade and interior photos, business type, potential, status stepper) and edit DA-15 with allowed status transitions. Creation uses a client-generated UUIDv7 and delegate.resellers.create through the outbox, with photos as dependent addPhoto mutations; an online duplicate check runs first and an offline duplicate surfaces as PHONE_ALREADY_EXISTS at sync. Customer type is not set here: the reseller declares it when claiming the account (AUTH-05, AUTH-11). It needs SRV-14 (create/update, check-phone, transitions) and Akram's DES-14 frames; MDA-08 invites the new record and MDA-09 can assist its first order.
Subtasks
| # | Subtask | Owner |
|---|---|---|
| 1 | NewResellerScreen DA-14: store name, owner name, main phone (E.164 normalisation), « WhatsApp = même numéro » toggle, email optional, business type (BUSINESS_TYPE), potential (« Faible », « Moyen », « Élevé ») | Imad |
| 2 | Duplicate check on phone blur: GET /delegate/resellers/check-phone → existing in scope opens its sheet; outside scope « Ce numéro est déjà enregistré — contactez le bureau »; offline → deferred to sync | Imad |
| 3 | Wilaya and commune pickers on cached reference data (COMMUNE_NOT_IN_WILAYA prevented locally), address field | Imad |
| 4 | GPS capture with MOB-10 getFix (accuracy shown, retry until ≤ 100 m) and a draggable map pin for correction | Imad |
| 5 | Façade photo required (PhotoKind FACADE) and interior optional via MOB-11, attached with delegate.resellers.addPhoto depending on the create mutation | Imad |
| 6 | Create with a client UUIDv7 → delegate.resellers.create through the outbox; record visible at once in DA-13 with « En attente de synchronisation » and « En attente de validation » once synced | Imad |
| 7 | Sync conflict handling for PHONE_ALREADY_EXISTS: sync-centre item with « Ouvrir la fiche existante » or « Corriger le numéro » | Imad |
| 8 | EditResellerScreen DA-15: PATCH /delegate/resellers/{id} with version (VERSION_CONFLICT → reload and reapply), status stepper limited to allowed transitions (RESELLER_TRANSITION_NOT_ALLOWED) | Imad |
| 9 | Draft autosave so an interrupted form (call, app kill) is restored | Imad |
Deliverables
- apps/delegate/lib/src/features/reseller_form/ (DA-14 new, DA-15 edit)
- Outbox mutation types delegate.resellers.create, delegate.resellers.update, delegate.resellers.addPhoto
- integration_test/new_reseller_offline_test.dart
Acceptance criteria
- A reseller created in airplane mode with GPS and façade photo appears immediately, syncs on reconnection and is linked to the creating delegate with validation pending (FLD-11)
- The form cannot be saved without the required minimum data, GPS position and façade photo (CRM-01, CRM-10)
- Online, a duplicate main phone is caught before saving; offline, it comes back as PHONE_ALREADY_EXISTS in the sync centre with a resolution path and no duplicate is created (CRM-03)
- Replaying the same create twice yields one reseller (client id + Idempotency-Key)
- Edit only offers allowed status transitions and handles VERSION_CONFLICT without losing the delegate's input
Requirements covered
| Requirement | Title | Release |
|---|---|---|
| FLD-11 | Field reseller sign-up with GPS and façade photo, offline-capable, linked to the creating delegate, pending validation | V1 |
| CRM-03 | Duplicate prevention: the main phone number is unique (normalised); duplicate check on every creation path | V1 |
| CRM-10 | Store photos and documents (façade, interior, RC, NIF, ID) with protected access | V1 |
| SYN-04 | Delegate app keeps the tour, visits, notes and photos locally under weak network | V1 |
Screens
API surface
| Endpoint group | Operations |
|---|---|
| Prospects, points of sale, follow-ups & invitations | 13 |
| File uploads & downloads | 3 |
Test measures
- integration_test: create offline with photo → kill → relaunch → reconnect → one reseller and one photo on the server
- Widget tests of form validation and phone normalisation
- Unit test of the create → addPhoto dependency chain in the outbox
Risks
- Prospect duplicates created offline by two delegates — server uniqueness wins; the sync-centre resolution path makes the loser's correction quick
KPI
- Delivered by Tue 8 Dec 2026 within 1.25 person-day(s).
- Every acceptance criterion above demonstrated before hand-off; linked requirements' acceptance criteria pass.
- Zero open critical defects, permission gaps or data-integrity regressions at sign-off.
Generated from content/plan/tasks.json by scripts/generate-team-tasks.mjs. Dates are computed by the scheduler (Sunday–Thursday weeks, holidays excluded) — change the plan, not this page.
MDA-06 — Delegate app — visit report & follow-ups
Structured report with chips/multi-selects, next action and follow-up date, attachments; follow-ups list with complete/reschedule.
MDA-08 — Delegate app — invitation (QR, share, tracking)
QR code, link copy, WhatsApp/SMS share intents, referral code, activation steps refreshed live.