---
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
---

> **⚠️ STALE as of the api.doormile.com migration.** Every `REACT_APP_URL` / `REACT_APP_URL2` endpoint below (jupiter.nearle.app) has been retired from the codebase. The console now calls `api.doormile.com` (`REACT_APP_DOORMILE_URL`) via `src/utils/doormileAxios.js` / `src/pages/api/doormileApi.js` — see `express-console-api.md` at the repo root for the current endpoint reference, and `src/pages/api/CLAUDE.md` for what the new backend has no equivalent for (zones/`applocationid`, live rider GPS logs, `/substitutions`, invoices, expense requests, several report breakdowns). The AI dispatch optimiser (routes.workolik.com / routemate.workolik.com) and the final-delivery-commit call are the one exception — they're unchanged, still hardcoded exactly as described below. The architecture/navigation/FCM sections below are still broadly accurate; only the API base and per-endpoint table are obsolete.

# 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: `#C01227` (NearlExpress red)** — 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 `#C01227 → #D25463`. 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 `/doormile/*` 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[/"/doormile/dispatch<br/>Live Map · Riders · Batches"/]:::core
    Orders[/"/doormile/orders<br/>Orders Dashboard"/]:::core
    Deliveries[/"/doormile/deliveries<br/>Dispatched Deliveries"/]:::core
    Tenants[/"/doormile/tenants<br/>Client/Tenant Management"/]:::core
    Pricing[/"/doormile/pricing<br/>Pricing Matrix (master-detail)"/]:::core
    Customers[/"/doormile/customers<br/>Customer Directory"/]:::core
    Riders[/"/doormile/riders<br/>Rider Pool"/]:::core
    Invoice[/"/doormile/invoice<br/>Billing"/]:::core
    Requests[/"/doormile/requests<br/>Expense Approvals"/]:::core
    ReportsHub[/"/doormile/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"]:::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 /doormile/orders
    participant S as Solver (routes/routemate.workolik.com)
    participant P as /doormile/dispatch/preview
    participant R as reconcile-steps
    participant J as jupiter.nearle.app
    participant D as /doormile/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` |
| `/doormile/dispatch` | `pages/nearle/dispatch/Dispatch.js` | `Dispatch` |
| `/doormile/dispatch/preview` | `pages/nearle/dispatch/Preview.js` | `DispatchPreview` |
| `/doormile/orders` | `pages/nearle/orders/orders.js` | `Orders` |
| `/doormile/orders/preview` | `pages/nearle/orders/OrdersPreview.js` | `OrdersPreview` |
| `/doormile/orders/create` | `pages/nearle/orders/createorder1.js` | `Createorder1` |
| `/doormile/orders/createorders` | `pages/nearle/orders/multipleOrders.js` | `MultipleOrders` |
| `/doormile/orders/details` | `pages/nearle/orders/details.js` | `Details` |
| `/doormile/deliveries` | `pages/nearle/deliveries/deliveries.js` | `Deliveries` |
| `/doormile/tenants` | `pages/nearle/clients/Tenants.js` | `Tenants` |
| `/doormile/clients/create` | `pages/nearle/clients/createclient.js` | `Createclient` |
| `/doormile/pricing` | `pages/nearle/clientPricing/clientPricing.js` | `ClientsPricing` |
| `/doormile/customers` | `pages/nearle/customers/customers.js` | `Customers` |
| `/doormile/customer/create` | `pages/nearle/clients/createCustomer.js` | `CreateCustomer` |
| `/doormile/riders` | `pages/nearle/riders/riders.js` | `Riders` |
| `/doormile/riders/create` | `pages/nearle/riders/createrider.js` | `Createrider` |
| `/doormile/riders/edit` | `pages/nearle/riders/editRider.js` | `EditRider` |
| `/doormile/invoice` | `pages/nearle/invoice/invoice.js` | `Invoice` |
| `/doormile/invoice/preview` | `pages/nearle/invoice/invoicePreview.js` | `InvoicePreview` |
| `/doormile/requests` | `pages/nearle/requests/requests.js` | `Requests` |
| `/doormile/reports/orderssummary` | `pages/nearle/reports/ordersSummary.js` | `OrdersSummary` |
| `/doormile/reports/ordersdetails` | `pages/nearle/reports/ordersDetails.js` | `OrdersDetails` |
| `/doormile/reports/riderssummary` | `pages/nearle/reports/ridersSummary.js` | `RidersSummary` |
| `/doormile/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 0–8, Afternoon 9–12, Evening 16–19). 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 104–297.
