---
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
src/index.js]):::entry
Providers["Providers wiring
Redux · QueryClient · Router · Theme · Notistack"]:::entry
App["src/App.js
localStorage('authname') gate"]:::auth
FCMInit["generateToken()
initFirebaseNotificationListener()"]:::auth
SW["public/firebase-messaging-sw.js"]:::auth
Login[/"/login
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
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
Live Map · Riders · Batches"/]:::core
Orders[/"/nearle/orders
Orders Dashboard"/]:::core
Deliveries[/"/nearle/deliveries
Dispatched Deliveries"/]:::core
Tenants[/"/nearle/tenants
Client/Tenant Management"/]:::core
Pricing[/"/nearle/pricing
Pricing Matrix (master-detail)"/]:::core
Customers[/"/nearle/customers
Customer Directory"/]:::core
Riders[/"/nearle/riders
Rider Pool"/]:::core
Invoice[/"/nearle/invoice
Billing"/]:::core
Requests[/"/nearle/requests
Expense Approvals"/]:::core
ReportsHub[/"/nearle/reports/*
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
POST routes.workolik.com
/optimization/riderassign"]:::ext
SolverAuto["Mode 2 · Auto
POST routemate.workolik.com
/optimization/riderassign"]:::ext
SolverManual["Mode 0 · Manual
POST routes.workolik.com
/optimization/createdeliveries"]:::ext
Reconcile["POST routes.workolik.com
/optimization/reconcile-steps"]:::ext
FinalAssign["POST jupiter.nearle.app
/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 `