Files

23 KiB
Raw Permalink Blame History

name, description, metadata
name description metadata
nearlexpress-docs 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.
  • 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

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)

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

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.