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