docs: runbook for creating a test booking and assigning a miler
Captures the working request bodies for the customer login/booking and the admin/hub assign-miler endpoints, plus the constraints that are easy to hit and hard to diagnose: - CityGate only accepts pickup pincodes in 641/600/560/500 - hub assign-miler 403s unless milerprofiles.hubid matches the calling hub, and most milers have hubid NULL - CreateCustomerBooking auto-assigns in the background, so a booking is often already on a miler before you assign one - the routing watchdog sweeps unaccepted assignments within ~a minute and may re-assign under a new bookingassignmentid, so accept IDs must be re-read - reject takes its reason in the body, not the query string Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
241
docs/test-booking-runbook.md
Normal file
241
docs/test-booking-runbook.md
Normal file
@@ -0,0 +1,241 @@
|
||||
# Creating a test booking and assigning it to a miler
|
||||
|
||||
How to create a pickup booking through the real customer API and put it on a
|
||||
specific miler, against `https://api.doormile.com`. Every call below is the
|
||||
production API — nothing here is a test harness or a shortcut.
|
||||
|
||||
Base URL: `https://api.doormile.com/api/v1`
|
||||
|
||||
---
|
||||
|
||||
## 1. Log in as a customer (two steps)
|
||||
|
||||
Customer auth is phone lookup, then PIN. The first call only confirms the
|
||||
account exists; it returns no token.
|
||||
|
||||
```bash
|
||||
curl -X POST https://api.doormile.com/api/v1/customer/login \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"phone":"9876543222"}'
|
||||
```
|
||||
|
||||
```json
|
||||
{ "success": true, "message": "PIN verification required", "phone": "9876543222" }
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -X POST https://api.doormile.com/api/v1/customer/verify-pin \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"phone":"9876543222","pin":"1234"}'
|
||||
```
|
||||
|
||||
The token is at the top level as `token` — **not** under `data`.
|
||||
|
||||
```json
|
||||
{ "success": true, "token": "eyJhbGciOi...", "user": { "appcustomerid": 1, "firstname": "Rahul", ... } }
|
||||
```
|
||||
|
||||
Save it: `TOKEN=eyJhbGciOi...`
|
||||
|
||||
### Customer test logins (all PIN `1234`)
|
||||
|
||||
| City | Name | Phone | appcustomerid |
|
||||
|---|---|---|---|
|
||||
| Coimbatore | Rahul Sharma | 9876543222 | 1 |
|
||||
| Hyderabad | Test Customer HYD | 9999900001 | 7 |
|
||||
| Bangalore | Test Customer BLR | 9999999999 | 6 |
|
||||
|
||||
---
|
||||
|
||||
## 2. Create the booking
|
||||
|
||||
```bash
|
||||
curl -X POST https://api.doormile.com/api/v1/customer/bookings \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"pickupaddress": "123 Gandhipuram Main Rd, Coimbatore",
|
||||
"pickuppincode": "641012",
|
||||
"pickuplatitude": 11.0168,
|
||||
"pickuplongitude": 76.9558,
|
||||
"deliveryaddress": "45 Saravanampatti, Coimbatore",
|
||||
"deliverypincode": "641035",
|
||||
"deliverylatitude": 11.0780,
|
||||
"deliverylongitude": 77.0010,
|
||||
"serviceoption": "Normal",
|
||||
"parcels": [{
|
||||
"itemcategory": "Documents",
|
||||
"itemdescription": "Test parcel",
|
||||
"declaredvalue": 500,
|
||||
"weight": 1.5,
|
||||
"length": 20, "width": 15, "height": 10
|
||||
}]
|
||||
}'
|
||||
```
|
||||
|
||||
Returns the created booking under `data`, with `bookingid` and status
|
||||
`Pending_Pickup`. Note the `bookingid` — step 3 needs it.
|
||||
|
||||
### Required vs optional
|
||||
|
||||
Only **`pickupaddress`**, **`pickuppincode`** and a non-empty **`parcels`**
|
||||
array are enforced. Delivery fields are optional; if you give a
|
||||
`deliverypincode` but no delivery lat/lon, the server geocodes the pincode for
|
||||
you. Parcel weight and dimensions are optional too — the miler weighs at
|
||||
pickup — but supplying them makes the volumetric-weight and pricing path
|
||||
realistic.
|
||||
|
||||
`serviceoption` is one of `Normal`, `Fast`, `Superfast`.
|
||||
|
||||
### The pickup pincode must be in an operating city
|
||||
|
||||
`CityGateMiddleware` rejects anything else with
|
||||
`{"code":"CITY_NOT_SUPPORTED"}`. Allowed 3-digit prefixes:
|
||||
|
||||
| Prefix | City |
|
||||
|---|---|
|
||||
| `641` | Coimbatore |
|
||||
| `600` | Chennai |
|
||||
| `560` | Bengaluru |
|
||||
| `500` | Hyderabad |
|
||||
|
||||
### Same-prefix pickup and delivery goes hyperlocal
|
||||
|
||||
If pickup and delivery share the first 3 digits, `BookingPickupComplete` sends
|
||||
the consignment straight to `Out_for_Delivery` and the same miler does the
|
||||
final mile. Different prefixes park it at `Inwarded_at_Hub`, which currently
|
||||
has no automated path onward. Keep both pincodes in the same prefix unless
|
||||
you are specifically testing the cross-hub gap.
|
||||
|
||||
---
|
||||
|
||||
## 3. Assign it to a specific miler
|
||||
|
||||
**The AI routing layer usually gets there first.** `CreateCustomerBooking`
|
||||
kicks off `AssignCustomerMiler` in a background goroutine, so a booking is
|
||||
often auto-assigned within seconds of creation. Check before assigning
|
||||
manually — you may already have what you want, on a miler you didn't pick.
|
||||
|
||||
### Admin console — works for any miler
|
||||
|
||||
```bash
|
||||
curl -X POST https://api.doormile.com/api/v1/admin/bookings/26/assign-miler \
|
||||
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"mileruserid": 4}'
|
||||
```
|
||||
|
||||
Admin token comes from `POST /admin/login` (roles 1, 3, 4).
|
||||
|
||||
This path has **no hub check and no city check** — it will put any miler on
|
||||
any booking. That is what makes it the reliable option.
|
||||
|
||||
### Hub console — miler must belong to the calling hub
|
||||
|
||||
```bash
|
||||
curl -X POST https://api.doormile.com/api/v1/hub/bookings/26/assign-miler \
|
||||
-H "Authorization: Bearer $HUB_TOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"mileruserid": 4}'
|
||||
```
|
||||
|
||||
Two extra constraints, both common sources of confusion:
|
||||
|
||||
- The booking must be in an assignable state, else `400 booking is not in an
|
||||
assignable state`.
|
||||
- The miler's `milerprofiles.hubid` must equal the hub the token belongs to,
|
||||
else `403 miler does not belong to this hub`. **Most milers in production
|
||||
have `hubid = NULL` and therefore cannot be assigned here at all** — they
|
||||
are also invisible in the hub console's miler list. Use the admin endpoint,
|
||||
or set a `hubid` first.
|
||||
|
||||
Both endpoints take the same body and funnel into the same
|
||||
`AssignMilerToBooking` function, so the resulting DB state is identical:
|
||||
booking → `Miler_Assigned`, a new `bookingassignments` row with status
|
||||
`Assigned`, and the miler's `availabilitystatus` → `Assigned`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Accept it as the miler — within about a minute
|
||||
|
||||
A watchdog on the AI routing layer reverts assignments that are not accepted
|
||||
promptly: the assignment row is deleted and the booking goes back to
|
||||
`Created`. Observed turnaround is under a minute.
|
||||
|
||||
In practice it often re-assigns rather than leaving the booking idle, so the
|
||||
booking still looks assigned to the same miler — but under a **new
|
||||
`bookingassignmentid`**. Observed on booking 26: assignment 42 was swept and
|
||||
replaced by 43 within ~2 minutes, same miler, same booking. So never hardcode
|
||||
an assignment ID you noted earlier; always re-read `GET /miler/assignments`
|
||||
immediately before accepting, or the accept will 404.
|
||||
|
||||
```bash
|
||||
# Miler login mirrors the customer flow
|
||||
curl -X POST https://api.doormile.com/api/v1/miler/login \
|
||||
-H 'Content-Type: application/json' -d '{"phone":"9876543255"}'
|
||||
|
||||
curl -X POST https://api.doormile.com/api/v1/miler/verify-pin \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"phone":"9876543255","pin":"1234"}'
|
||||
|
||||
# List what is actually actionable, then accept
|
||||
curl -H "Authorization: Bearer $MILER_TOKEN" \
|
||||
https://api.doormile.com/api/v1/miler/assignments
|
||||
|
||||
curl -X POST https://api.doormile.com/api/v1/miler/assignments/42/accept \
|
||||
-H "Authorization: Bearer $MILER_TOKEN"
|
||||
```
|
||||
|
||||
`GET /miler/assignments` only returns assignments in `Assigned` or `Accepted`,
|
||||
and accept only succeeds on one currently `Assigned` — a completed or rejected
|
||||
job can no longer be revived.
|
||||
|
||||
To reject instead, the reason goes in the **body**, not the query string:
|
||||
|
||||
```bash
|
||||
curl -X POST https://api.doormile.com/api/v1/miler/assignments/42/reject \
|
||||
-H "Authorization: Bearer $MILER_TOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"reason":"too far"}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Rest of the delivery flow
|
||||
|
||||
In order, all as the miler, all `Authorization: Bearer $MILER_TOKEN`:
|
||||
|
||||
| Step | Call |
|
||||
|---|---|
|
||||
| Arrived at customer | `POST /miler/bookings/:bookingid/reached` |
|
||||
| Confirm parcels | `POST /miler/bookings/:bookingid/parcel-confirm` |
|
||||
| Pickup complete | `POST /miler/bookings/:bookingid/pickup-complete` |
|
||||
| Deliver | `POST /miler/consignments/:consignmentid/deliver` |
|
||||
|
||||
`pickup-complete` is what converts the booking into a consignment, sets the
|
||||
origin hub from the miler's own `hubid`, and applies the hyperlocal rule from
|
||||
step 2.
|
||||
|
||||
---
|
||||
|
||||
## Miler reference
|
||||
|
||||
Milers with `hubid = NULL` work fine via the admin endpoint but not the hub
|
||||
console. Verify the current roster before relying on this table — production
|
||||
has ~24 milers and the seed data has been reshaped more than once.
|
||||
|
||||
| userid | Name | Phone | Hub | City |
|
||||
|---|---|---|---|---|
|
||||
| 4 | Ramesh Kumar | 9876543255 | 1 — Jupiter | Coimbatore |
|
||||
| 23 | Karthikeyan Vel | 9876500003 | 1 — Jupiter | Coimbatore |
|
||||
| 6 | Rajesh Sekhar | 9876543256 | 2 — Neptune | Coimbatore |
|
||||
| 7 | Karthi Keyan | 9876543257 | 7 — RS Puram | Coimbatore |
|
||||
| 21 | Murugan Palani | 9876500001 | 8 — Saravanampatti | Coimbatore |
|
||||
| 22 | Selvam Raja | 9876500002 | 17 — Test Hub | Coimbatore |
|
||||
| 8 | Suresh Goud | 9876543261 | **NULL** | Hyderabad |
|
||||
| 28 | Suresh Naik | 9876500008 | **NULL** | Bangalore |
|
||||
|
||||
Coimbatore hubs: 1 Jupiter (641012, sorting centre), 2 Neptune (641004),
|
||||
7 RS Puram (641002), 8 Saravanampatti (641035), 17 Test Hub (641099).
|
||||
|
||||
All miler PINs above are `1234`.
|
||||
Reference in New Issue
Block a user