Files

410 lines
23 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: nearlexpress-docs
description: "Architecture, navigation flow, per-page API map, optimisation pipeline, and FCM rules for the NearlExpress Console (nearlexpress-xpressconsole-d0ee01adebe9). Load when working anywhere in this repo or when the user asks about its pages (orders, deliveries, dispatch, tenants, pricing, customers, riders, invoices, reports, requests), the AI dispatch solvers (routes.workolik.com / routemate.workolik.com), the optimisation → preview → reconcile → assign → notify pipeline, FCM/Firebase notifications, TanStack Query data flow, or which API endpoint a given page calls."
metadata:
version: 2.0.0
---
# NearlExpress Console — Project Reference
A React 18 operator console for the NearlExpress dispatch platform. Operators use it to manage orders, run the AI dispatch optimiser, watch a live map of riders, edit tenants/pricing/invoices, and pull BI reports. Production users are warehouse staff, not end customers.
This skill is the **knowledge** Claude needs about the system (what each page does, which API each calls, how the pieces wire together). The **rules** Claude must follow when editing live in the root `CLAUDE.md` — don't restate them here.
---
## 1. Architecture at a glance
- **Brand colour: `#662582` (NearlExpress purple)** — defined in `src/themes/theme/default.js` as `primary.main`. Used by the sidebar, page headers, dialog/popup headers, KPI primary tiles, search bars, edit-action buttons. Gradient pair `#662582 → #9255AB`. Status badges use a separate semantic palette (amber/indigo/cyan/teal/emerald/red/orange) — see root `CLAUDE.md` §6.
- **Stack:** React 18.2 + react-app-rewired (CRA), MUI 5, TanStack Query 5, Redux Toolkit, react-router 6, axios, dayjs, leaflet, firebase 10 (FCM), notistack, formik+yup, react-dnd.
- **Entry:** `src/index.js` → providers (Redux store, QueryClient, Router, ThemeCustomization, Notistack) → `src/App.js`.
- **Auth gate:** `App.js` checks `localStorage.getItem('authname')` — empty redirects to `/login`. Login posts to `jupiter.nearle.app/users/console/login` with `configid: 9` and the device's FCM token.
- **Routing:** `src/routes/MainRoutes.js` declares all `/nearle/*` routes, lazy-loaded via `components/Loadable`. Sidebar items are declared in `src/menu-items/nearle.js`.
- **Data layer:** every server call lives in `src/pages/api/api.js`. Pages call those exports via `useQuery` / `useInfiniteQuery` / `useMutation`. Query keys MUST include every filter parameter so caching invalidates correctly.
- **State:** Redux Toolkit slices (`fcmSlice`, `loginUserSlice`, `menu`, `snackbar`, `toastSlice`, `auth`) for cross-page state; per-page UI state stays in `useState`.
- **Two API bases:** `process.env.REACT_APP_URL` (primary) and `process.env.REACT_APP_URL2` (used for `/users/update`, `/tenants/update`, archival `/orders/getorders`, rider logs).
- **External services (hardcoded):** `routes.workolik.com` (Bike/Manual solver), `routemate.workolik.com` (Auto/multi-trip solver), `jupiter.nearle.app` (login + final delivery commit).
- **localStorage keys:** `authname`, `userid`, `roleid`, `userfcmtoken`, `applocations` (cached zone list).
- **Notifications:** FCM init in `App.js` via `firebase_notification/notification.js` (`generateToken`, `initFirebaseNotificationListener`). Service worker at `public/firebase-messaging-sw.js`.
---
## 2. End-to-end console flow
```mermaid
flowchart TD
classDef entry fill:#f9f6ff,stroke:#a78bfa,stroke-width:2px,color:#2e1065;
classDef auth fill:#fdf2f8,stroke:#ec4899,stroke-width:2px,color:#831843;
classDef nav fill:#eef2ff,stroke:#6366f1,stroke-width:2px,color:#312e81;
classDef core fill:#e0f2fe,stroke:#0ea5e9,stroke-width:2px,color:#0c4a6e;
classDef sub fill:#ecfeff,stroke:#06b6d4,stroke-width:1.5px,color:#155e75;
classDef action fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#78350f;
classDef ext fill:#fef2f2,stroke:#ef4444,stroke-width:2px,color:#7f1d1d;
classDef report fill:#f5f5f4,stroke:#78716c,stroke-width:1.5px,color:#292524;
classDef state fill:#fdf4ff,stroke:#8b5cf6,stroke-width:1.5px,color:#581c87;
Boot([Browser load<br/>src/index.js]):::entry
Providers["Providers wiring<br/>Redux · QueryClient · Router · Theme · Notistack"]:::entry
App["src/App.js<br/>localStorage('authname') gate"]:::auth
FCMInit["generateToken()<br/>initFirebaseNotificationListener()"]:::auth
SW["public/firebase-messaging-sw.js"]:::auth
Login[/"/login<br/>pages/nearle/login1.js"/]:::auth
Boot --> Providers --> App
App -- no authname --> Login
Login -- POST jupiter.nearle.app/users/console/login --> AuthOK{Auth OK?}
AuthOK -- yes (save authname/userid/roleid/userfcmtoken) --> Layout
AuthOK -- no --> Login
App --> FCMInit --> SW
Layout["layout/MainLayout<br/>Sidebar + Header + Outlet"]:::nav
Sidebar["menu-items/nearle.js"]:::nav
Layout --- Sidebar
Sidebar --> Dispatch
Sidebar --> Orders
Sidebar --> Deliveries
Sidebar --> Tenants
Sidebar --> Pricing
Sidebar --> Customers
Sidebar --> Riders
Sidebar --> Invoice
Sidebar --> ReportsHub
Dispatch[/"/nearle/dispatch<br/>Live Map · Riders · Batches"/]:::core
Orders[/"/nearle/orders<br/>Orders Dashboard"/]:::core
Deliveries[/"/nearle/deliveries<br/>Dispatched Deliveries"/]:::core
Tenants[/"/nearle/tenants<br/>Client/Tenant Management"/]:::core
Pricing[/"/nearle/pricing<br/>Pricing Matrix (master-detail)"/]:::core
Customers[/"/nearle/customers<br/>Customer Directory"/]:::core
Riders[/"/nearle/riders<br/>Rider Pool"/]:::core
Invoice[/"/nearle/invoice<br/>Billing"/]:::core
Requests[/"/nearle/requests<br/>Expense Approvals"/]:::core
ReportsHub[/"/nearle/reports/*<br/>BI Suite"/]:::core
OrdersCreate[/"/orders/create"/]:::sub
OrdersMulti[/"/orders/createorders"/]:::sub
OrdersDetails[/"/orders/details"/]:::sub
OrdersPreview[/"/orders/preview"/]:::sub
DispatchPreview[/"/dispatch/preview"/]:::sub
RidersCreate[/"/riders/create"/]:::sub
RidersEdit[/"/riders/edit"/]:::sub
ClientsCreate[/"/clients/create"/]:::sub
CustomerCreate[/"/customer/create"/]:::sub
InvoicePreview[/"/invoice/preview"/]:::sub
ReportsOS[/"/reports/orderssummary"/]:::report
ReportsOD[/"/reports/ordersdetails"/]:::report
ReportsRS[/"/reports/riderssummary"/]:::report
ReportsRL[/"/reports/riderslogs"/]:::report
Orders --> OrdersCreate
Orders --> OrdersMulti
Orders --> OrdersDetails
Riders --> RidersCreate
Riders --> RidersEdit
Tenants --> ClientsCreate
Customers --> CustomerCreate
Invoice --> InvoicePreview
ReportsHub --> ReportsOS
ReportsHub --> ReportsOD
ReportsHub --> ReportsRS
ReportsHub --> ReportsRL
%% Optimisation pipeline
SelectOrders["Select N pending orders"]:::action
ChooseSolver{"Choose Dispatch Mode"}:::action
SolverBike["Mode 1 · Bike<br/>POST routes.workolik.com<br/>/optimization/riderassign"]:::ext
SolverAuto["Mode 2 · Auto<br/>POST routemate.workolik.com<br/>/optimization/riderassign"]:::ext
SolverManual["Mode 0 · Manual<br/>POST routes.workolik.com<br/>/optimization/createdeliveries"]:::ext
Reconcile["POST routes.workolik.com<br/>/optimization/reconcile-steps"]:::ext
FinalAssign["POST jupiter.nearle.app<br/>/deliveries/createdeliveries"]:::ext
NotifyRider["POST /utils/notifyuser (FCM)"]:::ext
Orders --> SelectOrders --> ChooseSolver
ChooseSolver -- Bike --> SolverBike
ChooseSolver -- Auto --> SolverAuto
ChooseSolver -- Manual --> SolverManual
SolverBike --> OrdersPreview
SolverAuto --> OrdersPreview
SolverManual --> OrdersPreview
OrdersPreview --> DispatchPreview
DispatchPreview -. manual edit .-> Reconcile
Reconcile --> DispatchPreview
DispatchPreview -- Assign --> FinalAssign
FinalAssign --> NotifyRider
FinalAssign -- redirect --> Deliveries
%% Deliveries actions
DChangeRider["Change Rider"]:::action
DCancel["Cancel Delivery"]:::action
DUpdate["Update Amount / Notes"]:::action
Deliveries --> DChangeRider --> NotifyRider
Deliveries --> DCancel --> NotifyRider
Deliveries --> DUpdate
%% Cross-cutting
subgraph CROSS [Cross-cutting infrastructure]
direction LR
Store["Redux: fcm · login · menu · snackbar · toast · auth"]:::state
QC["TanStack Query (cache + infinite scroll)"]:::state
Env["REACT_APP_URL · REACT_APP_URL2 · REACT_APP_GOOGLE_MAPS_API_KEY"]:::state
LS["localStorage: authname · userid · roleid · userfcmtoken · applocations"]:::state
end
Layout -. reads .-> Store
Layout -. reads .-> LS
Orders & Deliveries & Dispatch & Tenants & Pricing & Customers & Riders & Invoice -. fetches via .-> QC
QC -. base URLs from .-> Env
```
---
## 3. Optimisation pipeline (sequence)
```mermaid
sequenceDiagram
autonumber
participant U as Operator
participant O as /nearle/orders
participant S as Solver (routes/routemate.workolik.com)
participant P as /nearle/dispatch/preview
participant R as reconcile-steps
participant J as jupiter.nearle.app
participant D as /nearle/deliveries
participant F as FCM (rider device)
U->>O: Select pending orders (checkbox)
U->>O: Pick dispatch mode (Bike / Auto / Manual)
O->>S: POST riderassign or createdeliveries
S-->>O: Optimised route & assignments
O->>P: Redirect to preview
U->>P: Drag steps / swap rider (optional)
P->>R: POST reconcile-steps (after each manual edit)
R-->>P: Updated, validated sequence
U->>P: Confirm "Assign"
P->>J: POST /deliveries/createdeliveries
J-->>P: 200 OK
P->>F: POST /utils/notifyuser (per rider)
P->>D: Redirect to deliveries dashboard
```
**Hard rule:** never call `POST /deliveries/createdeliveries` after manual edits without calling `POST /optimization/reconcile-steps` first. Skipping reconcile corrupts route sequences.
---
## 4. Page-by-page API map
> Every named function below lives in `src/pages/api/api.js`. URLs use `REACT_APP_URL` unless noted otherwise (`REACT_APP_URL2`).
### 4.1 Authentication
- **Page:** `pages/nearle/login1.js`
| Endpoint | Method | Function | Purpose |
| --- | --- | --- | --- |
| `https://jupiter.nearle.app/live/api/v1/users/console/login` | `POST` | *direct axios* | Console staff auth. Requires `authname`, `password`, `configid: 9`, `userfcmtoken`. |
| `/partners/getlocations/?userid={id}` | `GET` | `fetchAppLocations` | Operational locations assigned to the operator. |
| `REACT_APP_URL2/users/update` | `PUT` | `updateUser` | First-time password setup / change password. |
### 4.2 Orders
- **Page:** `pages/nearle/orders/orders.js`
| Endpoint | Method | Function | Purpose |
| --- | --- | --- | --- |
| `/orders/getordersummary/?applocationid={appId}` | `GET` | `fetchPercentageData` / `fetchorderscount` | Status statistics (total, pending, delivered, cancelled). |
| `/orders/tenant/getorders/` | `GET` | `fetchOrders` | Infinite paginated order list. |
| `/utils/getapptypes/?tag=paymentmode` | `GET` | `fetchPaymentType` | Payment-mode dropdown options. |
| `/partners/getriders/?applocationid={appId}` | `GET` | `fetchRidersList` | Active riders for manual assignment. |
| `/tenants/gettenants/?applocationid={appId}&status=active` | `GET` | `getTenants` | Active tenants for filter. |
| `/tenants/gettenantlocations/?tenantid={appId}` | `GET` | `gettenantlocations` | Store branches for a tenant. |
| `/partners/getallriders?partnerid=64` | `GET` | `getallriders` | Full driver pool for bulk dispatch. |
| `/orders/updateorder` | `PUT` | `cancelOrder` | Cancel a single order. |
| `/orders/updatemultipleorders` | `PUT` | `cancelMultipleOrder` | Bulk cancel. |
### 4.3 AI dispatch / optimisation
- **Pages:** `orders/orders.js`, `dispatch/Preview.js`
| Endpoint | Method | Function | Mode |
| --- | --- | --- | --- |
| `https://routes.workolik.com/api/v1/optimization/createdeliveries` | `POST` | `createOptimisationDeliveries` | Mode 0 · Manual |
| `https://routes.workolik.com/api/v1/optimization/riderassign?hypertuning_params={params}` | `POST` | `createAutomationDeliveries` | Mode 1 · Bike hyper-tuning |
| `https://routemate.workolik.com/api/v1/optimization/riderassign?strategy=multi_trip` | `POST` | `createAutomationDeliveries` | Mode 2 · Auto multi-trip |
| `https://routes.workolik.com/api/v1/optimization/reconcile-steps` | `POST` | `reconcileSteps` | Validate sequence after manual edits |
| `https://jupiter.nearle.app/live/api/v1/deliveries/createdeliveries` | `POST` | `finalCreatedeliveries` | Commit assignments |
### 4.4 Deliveries
- **Page:** `pages/nearle/deliveries/deliveries.js`
| Endpoint | Method | Function | Purpose |
| --- | --- | --- | --- |
| `/deliveries/getdeliveries/` | `GET` | `fetchDeliveries` | Streams delivery records (infinite query). Client-side wave filter by `assigntime`. |
| `/deliveries/deliverysummary/` | `GET` | `fetchCountAPI` / `fetchPercentageAPI` | Lifecycle chip counts (pending/accepted/arrived/picked/active/skipped/delivered/cancelled). |
| `/orders/getorderdetails?orderheaderid={id}` | `GET` | `getorderdetails` | Items detail for invoice preview. |
| `/deliveries/updatedelivery` | `PUT` | `cancelDeliveryAPI` | Cancel with feedback. |
| `/deliveries/updatedelivery` | `PUT` | `changeRiderAPI` | In-transit rider reassignment (also resets `assigntime`). |
| `/deliveries/updatedelivery` | `PUT` | `updateDeliveryAPI` | Amount / notes update. |
| `/utils/notifyuser` | `POST` | `notifyRider` | FCM push to rider's device. Required after every rider-affecting mutation. |
### 4.5 Tenants
- **Page:** `pages/nearle/clients/Tenants.js`
| Endpoint | Method | Function | Purpose |
| --- | --- | --- | --- |
| `/tenants/getalltenants/?status={status}&applocationid={appId}&keyword={kw}&pageno={p}&pagesize={n}&moduleid=6` | `GET` | `getalltenants` | Onboarded tenants. |
| `/tenants/gettenantsummary/?moduleid=6&applocationid={appId}` | `GET` | `gettenantsummary` | Tab counts. |
| `/tenants/getpricinglist/?moduleid=6&applocationid={appId}` | `GET` | `getpricinglist` | Subscription / billing contracts. |
| `/tenants/gettenantpricing/?tenantid={id}` | `GET` | *direct axios* | Tenant base pricing config. |
| `REACT_APP_URL2/tenants/update` | `PUT` | *direct axios* | Profile / coordinates / approval. |
| `REACT_APP_URL2/tenants/update/services` | `PUT` | *direct axios* | Customised tenant service rates. |
### 4.6 Pricing
- **Page:** `pages/nearle/clientPricing/clientPricing.js`
| Endpoint | Method | Function | Purpose |
| --- | --- | --- | --- |
| `/utils/getallpricing/?applocationid={appId}` | `GET` | *direct axios* | Base pricing models for the zone. |
### 4.7 Customers
- **Page:** `pages/nearle/customers/customers.js`
| Endpoint | Method | Function | Purpose |
| --- | --- | --- | --- |
| `/customers/getcustomersummary?applocationid={appId}` | `GET` | `getcustomersummary` | Customer count summary. |
| `/customers/getallcustomers/` | `GET` | `getallcustomers` | Searchable directory (infinite query). |
| `/customers/update` | `PUT` | *direct axios* | Update customer profile + address. |
### 4.8 Riders
- **Pages:** `riders/riders.js`, `createrider.js`, `editRider.js`
| Endpoint | Method | Function | Purpose |
| --- | --- | --- | --- |
| `/partners/getallriders/?applocationid={appId}&pageno={p}&pagesize=20&keyword={kw}&status={status}` | `GET` | `fetchAllRiders` | Filtered driver list. |
| `/partners/getallridersummary/?applocationid={appId}&status={status}` | `GET` | `getallridersummary` | Crew breakdowns. |
| `/partners/getriders/?applocationid={appId}&pageno={p}&pagesize=20&keyword={kw}` | `GET` | `fetchRiders` | Active/online riders. |
| `/utils/getriderstatus` | `GET` | `getriderstatus` | Check-in history. |
| `/partners/createrider` | `POST` | *direct axios* | Onboard rider. |
| `/partners/update/rider` | `PUT` | *direct axios* | Edit rider vehicle/license/bank/status. |
### 4.9 Invoices
- **Pages:** `invoice/invoice.js`, `invoicePreview.js`
| Endpoint | Method | Function | Purpose |
| --- | --- | --- | --- |
| `/invoice/getinvoiceinsight` | `GET` | `fetchinvoiceinsight` | Global accounting summary. |
| `/invoice/getallinvoice/?billstatus={status}` | `GET` | `fetchdeliverylist` | Invoice list (Paid vs Unpaid tabs). |
### 4.10 Dispatch (live tracker)
- **Page:** `pages/nearle/dispatch/Dispatch.js`
| Endpoint | Method | Function | Purpose |
| --- | --- | --- | --- |
| `/utils/getriderperiodiclogs?userid={id}` | `GET` | `getRiderPeriodicLogs` | Rider GPS/battery/connectivity/current order — polled for live map. |
| `https://routes.workolik.com/api/v1/batch/efficiency` | `POST` | `fetchBatchEfficiency` | Per-batch solver efficiency rating. |
### 4.11 Reports / BI
- **Pages:** `reports/ordersSummary.js`, `ordersDetails.js`, `ridersSummary.js`, `ridersLogs.js`
| Endpoint | Method | Function | Purpose |
| --- | --- | --- | --- |
| `/deliveries/getreportsummary/?applocationid&tenantid&locationid&fromdate&todate` | `GET` | `getreportsummary` | Aggregated fulfilment. |
| `/deliveries/getreportlocationsummary/?...` | `GET` | `getreportlocationsummary` | Per-branch breakdown. |
| `REACT_APP_URL2/orders/getorders/?fromdate&todate&applocationid&pageno&pagesize` | `GET` | `fetchorderdetails` | Archival historical orders. |
| `/deliveries/getriderbydelivery/?applocationid&tenantid&locationid&fromdate&todate` | `GET` | `getriderbydelivery` | Per-rider delivery trace. |
| `/deliveries/deliverysummary/?applocationid&fromdate&todate` | `GET` | `fetchCount` | Volume metrics over range. |
| `/deliveries/getridersummary/?applocationid&fromdate&todate` | `GET` | `fetchRidersSummary` | Per-rider performance stats. |
| `/partners/getpartners` | `GET` | `fetchLocations` | Merchant locations for routing. |
| `REACT_APP_URL2/partners/getriderlogs/?applocationid&fromdate&todate&keyword` | `GET` | `fetchRidersLogs` | Driver login / checkout audit. |
### 4.12 Requests (expense reimbursements)
- **Page:** `pages/nearle/requests/requests.js`
| Endpoint | Method | Function | Purpose |
| --- | --- | --- | --- |
| `/payments/requests/getpaymentrequest/?partnerid={tid}&status={0 or 1}` | `GET` | `clientdetailspending` / `clientdetailsapproved` | Status 0 = Pending, 1 = Approved. |
---
## 5. Route → file map (full)
| Route | File | Lazy import name |
| --- | --- | --- |
| `/login` | `pages/nearle/login1.js` | `Login` |
| `/nearle/dispatch` | `pages/nearle/dispatch/Dispatch.js` | `Dispatch` |
| `/nearle/dispatch/preview` | `pages/nearle/dispatch/Preview.js` | `DispatchPreview` |
| `/nearle/orders` | `pages/nearle/orders/orders.js` | `Orders` |
| `/nearle/orders/preview` | `pages/nearle/orders/OrdersPreview.js` | `OrdersPreview` |
| `/nearle/orders/create` | `pages/nearle/orders/createorder1.js` | `Createorder1` |
| `/nearle/orders/createorders` | `pages/nearle/orders/multipleOrders.js` | `MultipleOrders` |
| `/nearle/orders/details` | `pages/nearle/orders/details.js` | `Details` |
| `/nearle/deliveries` | `pages/nearle/deliveries/deliveries.js` | `Deliveries` |
| `/nearle/tenants` | `pages/nearle/clients/Tenants.js` | `Tenants` |
| `/nearle/clients/create` | `pages/nearle/clients/createclient.js` | `Createclient` |
| `/nearle/pricing` | `pages/nearle/clientPricing/clientPricing.js` | `ClientsPricing` |
| `/nearle/customers` | `pages/nearle/customers/customers.js` | `Customers` |
| `/nearle/customer/create` | `pages/nearle/clients/createCustomer.js` | `CreateCustomer` |
| `/nearle/riders` | `pages/nearle/riders/riders.js` | `Riders` |
| `/nearle/riders/create` | `pages/nearle/riders/createrider.js` | `Createrider` |
| `/nearle/riders/edit` | `pages/nearle/riders/editRider.js` | `EditRider` |
| `/nearle/invoice` | `pages/nearle/invoice/invoice.js` | `Invoice` |
| `/nearle/invoice/preview` | `pages/nearle/invoice/invoicePreview.js` | `InvoicePreview` |
| `/nearle/requests` | `pages/nearle/requests/requests.js` | `Requests` |
| `/nearle/reports/orderssummary` | `pages/nearle/reports/ordersSummary.js` | `OrdersSummary` |
| `/nearle/reports/ordersdetails` | `pages/nearle/reports/ordersDetails.js` | `OrdersDetails` |
| `/nearle/reports/riderssummary` | `pages/nearle/reports/ridersSummary.js` | `RidersSummary` |
| `/nearle/reports/riderslogs` | `pages/nearle/reports/ridersLogs.js` | `RidersLogs` |
| `/viewprofile` | `pages/nearle/viewProfile.js` | `ViewProfile` |
| `/maintenance/{404,500,under-construction,coming-soon}` | `pages/maintenance/*` | — |
---
## 6. Per-page state-flow primer
```mermaid
flowchart LR
subgraph PAGE [Any operator page]
UI[React component] --> QH["useQuery / useInfiniteQuery / useMutation"]
UI --> US["useState (local UI state)"]
end
QH -- "queryKey = [name, appId, filters...]" --> Cache["TanStack Query cache"]
QH -- queryFn --> ApiLayer["pages/api/api.js"]
ApiLayer --> AxRaw["axios (raw)"]
ApiLayer -. some calls .-> AxInt["utils/axios.js (401 interceptor)"]
AxRaw --> EnvURL["process.env.REACT_APP_URL"]
AxRaw --> EnvURL2["process.env.REACT_APP_URL2"]
AxRaw --> ExtOpt["routes / routemate / jupiter (hardcoded)"]
UI -. dispatches .-> RTK["Redux store"]
UI -. emits toast .-> Notistack
UI -. reads .-> LS["localStorage"]
```
**Conventions for new pages:**
- Query keys must include every filter parameter so caching invalidates correctly.
- Use `useInfiniteQuery` for paginated rows; auto-drain with an `IntersectionObserver` on a sentinel `<div ref={loadMoreRef} />` at the bottom of the `TableContainer`. The canonical pattern is in `deliveries.js` (search for `useInfiniteQuery({` and the adjacent `IntersectionObserver` block).
- Mutations: after success, call `.refetch()` on every related query. Project does not yet use `queryClient.invalidateQueries`.
- Errors → `OpenToast(message, 'error', 2000)` from `components/third-party/OpenToast`.
---
## 7. FCM rules
- Initialised once in `App.js` (`generateToken` + `initFirebaseNotificationListener`).
- After any mutation affecting a rider (assign, cancel, change rider), call `POST /utils/notifyuser` with the target rider's `userfcmtoken`.
- The service worker (`public/firebase-messaging-sw.js`) handles background tokens and desktop notifications. Subtle bugs there cause silent delivery failures — do not edit without a clear reason.
---
## 8. Glossary
- **Zone / `applocationid`** — operator's warehouse / operational hub. `0` means "All Zones". Every list endpoint takes this.
- **Tenant** — the business / brand whose orders flow through the platform.
- **Location** — a tenant's branch within a zone.
- **Rider / Partner** — the delivery driver.
- **Batch / Wave** — a time-of-day slot (Morning 08, Afternoon 912, Evening 1619). Bucketed by `assigntime` on the deliveries page in **local** time to match dispatch's bucketing.
- **Slab** — a pricing tier (base + per-km + min-km + max-km + min-orders).
- **Solver hypertuning** — the optimiser's strategy (Balanced, Fuel Saver, Aggressive, Strict Zones).
---
## 9. Cross-references
- Project rules and conventions Claude must follow are in the root `CLAUDE.md`. Don't restate them here.
- Page-level design system tokens (the `DT` block, `pillFieldSx`, `SoftPaper`, `AccentAvatar`) are documented in `CLAUDE.md` §6 — the implementation source-of-truth is `src/pages/nearle/deliveries/deliveries.js` lines 104297.