docs/miler-auth-and-review-fixes-2026-09-16.md: what changed on main today and the current flow — the new /miler/login pin_set + /miler/set-pin first-login contract (app work needed), the seven fixes to the merged cx/handover commits, and the live-DB test data (no-PIN riders, sample multi-destination booking). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WRaFH5hMRqmUQvVPQsyjZD
6.3 KiB
Backend changes & current flow — for Dharaneesh (2026-09-16)
Covers three things landed on main today: the miler self-set-PIN login
flow (needs app work), the fixes made to the merged customer-app / base-handover
commits, and the test data seeded on the live DB. git pull before you
start.
Commits: ba2cd22 (review fixes), dd0fa75 (miler PIN flow), 5e5230e (seed).
1. Miler login — self-set PIN on first login (app change needed)
Riders now create their own PIN the first time they log in, instead of the
console assigning a shared 1234. The login endpoint tells the app which screen
to show.
Flow
flowchart TD
A["Rider enters phone number"] --> B["POST /miler/login"]
B --> C{"account found & active?"}
C -- "not found" --> D["404 — no miler account"]
C -- "inactive / not a miler" --> E["403"]
C -- "yes" --> F{"pin_set ?"}
F -- "pin_set: false" --> G["Show SET-PIN screen"]
F -- "pin_set: true" --> H["Show ENTER-PIN screen"]
G --> I["POST /miler/set-pin {phone, new_pin}"]
I --> J["200 — logged in (token + user)"]
H --> K["POST /miler/verify-pin {phone, pin}"]
K --> L["200 — logged in (token + user)"]
Endpoints
POST /miler/login — unchanged request, new pin_set field in the response.
Request:
{ "phone": "8000000001", "configid": 1001 }
Response (200):
{
"success": true,
"message": "PIN verification required",
"phone": "8000000001",
"pin_set": false
}
pin_set: false→ route to the Set-PIN screen.pin_set: true→ route to the Enter-PIN screen (existing behaviour).404= phone not registered;403= account inactive / not a miler.
POST /miler/set-pin — NEW. First-time PIN creation, self-service.
Request:
{ "phone": "8000000001", "new_pin": "1234", "configid": 1001, "device_token": "<fcm>" }
Response (200) — the rider is logged in immediately, same shape as verify-pin:
{
"success": true,
"token": "<jwt>",
"tenantid": 1,
"tenantname": "Doormile Coimbatore Logistics",
"user": { "userid": 46, "authname": "...", "contactno": "...", "profile": { ... } }
}
409if the account already has a PIN — send the rider to Enter-PIN instead.404phone not registered;403inactive / not a miler.
POST /miler/verify-pin — unchanged. Used when pin_set: true.
Notes for the app
- Branch on the
pin_setboolean, not on the message string. set-pinreturns a full session (token + user) — no need to callverify-pinafterwards.- The console no longer sends a PIN when creating a rider (the backend
ignores any
passwordfield onCreateMiler). New riders always start with no PIN and set it on first login. - The 6 existing riders keep their current
1234PIN (deliberate) — they reportpin_set: trueand go straight to Enter-PIN. Only newly created riders use the set-PIN screen.
Security note (for later)
set-pin is self-service and can't overwrite an existing PIN, so it can't take
over an active account. The only residual gap is a brand-new, never-logged-in
account being claimed by whoever knows the phone first. Close it by OTP-gating
set-pin once the SMS gateway is live.
2. Fixes to the merged customer-app / base-handover work
Reviewed the 10 merged commits — the OTP/auth, IDOR/tenant scoping, CHECK
constraints and pagination were solid. These defects were fixed (ba2cd22):
| Severity | What was wrong | Fix |
|---|---|---|
| HIGH (money) | CreateCxBooking let the request body's estimate set the billed price with no server check; it flows into Estimatedprice → ridercharges (miler pay + tenant bill). estimate:{min:1,max:1} settled a delivery at ₹1. |
Client estimate is honoured only when within 15% of the server quote; otherwise the server quote stands. |
| MED | Multi-destination handover freed the rider and closed the booking assignment after the first parcel, dropping the remaining stops and crediting one leg. | Assignment closes / rider frees only when no parcel of the booking is still in their hands. |
| MED | inwardedat / completedat written with time.Now() (UTC) instead of DBNow() (IST) → ~5h30 off, skewing earnings/reconcile windows. |
Switched to DBNow() in the handover, inbound-scan, reconcile and pickup-complete paths. |
| MED | Customers got two "miler assigned" pushes on auto-assign (two token stores) and none on manual assign. | One cxstage.Notify on both paths. |
| LOW | ReconcileHubInbound could return 200 with a silently-missing audit row. |
Wrapped in a transaction; audit inserts checked. |
| LOW | CxLogout returned signedOut:true even when the token revoke failed. |
Returns 500 on a failed revoke. |
| LOW | A rider-named handover base far from their location silently rerouted the parcel to another city. | Rejected when the named base is >50 km from the rider's reported position. |
One thing to confirm your side
The CX_STAGING_OTP fixed-code OTP bypass is gated only on ENV == "production".
Confirm the live k8s manifest sets ENV=production exactly, or the bypass is
reachable in prod.
3. Test data seeded on the live DB
scratch/seed_test_data.go (committed, idempotent, safe to re-run) has been run
against live. Available now:
- Test riders — NO PIN (for the set-PIN flow): phones
8000000001,8000000002,8000000003(Coimbatore). - Test customer: phone
9000000001. - Sample multi-destination booking
DM-SEED-CX-001— one Coimbatore pickup → two destinations (Chennai, Bengaluru), two consignments in the rider's hands, assigned to8000000001. Use it to test the base-handover fix: inwarding the first parcel must not free the rider while the second is still carried. - Reference serviceable states / districts (TN, KA, KL; CBE, CHN, BLR, EKM), the base/hub network, a tenant location, and pricing.
Quick test path
- Miler app → enter
8000000001→ expectpin_set: false→ Set-PIN screen → set a PIN → land logged in. - That rider sees booking
DM-SEED-CX-001with two destinations. - Hand over parcel #1 at a base → rider stays on the job (assignment open).
- Hand over parcel #2 → assignment closes, rider freed, both legs credited.