Files
daily_merchant_web/docs/BACKEND_API_REQUIREMENTS.md

323 lines
13 KiB
Markdown
Raw 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.
# Backend API Requirements — Merchant Web Console
**Audience:** Backend team.
**Purpose:** These are the endpoints the merchant web app needs before it can go to staging with
zero mock data. Every UI spot listed below currently renders an explicit
`Awaiting backend API [Rxx]` placeholder (or a known-wrong stand-in like the
`delivered × 355` revenue) until the matching endpoint ships.
## Conventions (match the existing live API)
- **Base / proxy:** Fiesta REST at `https://fiesta.nearle.app/live/api/v1/web/<group>/<action>`.
The frontend calls it through the dev proxy as `/fiesta/live/api/v1/web/...`.
- **Auth:** same as current read endpoints (no extra header required for GETs).
- **Envelope:** every response is
```json
{ "code": 200, "status": true, "message": "OK", "details": <payload> }
```
`details` is the documented payload (array or object). On failure return
`{ "code": 4xx, "status": false, "message": "<reason>" }`.
- **Types:** money = INR as a plain 2-dp number (e.g. `442800.00`), no currency symbol/string.
Dates = `YYYY-MM-DD`. Timestamps = ISO-8601 (`2026-06-06T14:21:00`). Ids = integers.
- **Tenant scope (current):** `tenantid=1087`, `applocationid=1`, primary `locationid=1097`.
- **Paging:** where listed, accept `pageno` (1-based) and `pagesize`.
## Index
| Id | Endpoint | Method | Powers (UI) | Priority |
|---|---|---|---|---|
| [R1] | `/orders/getrevenuesummary` | GET | Revenue KPIs, OTIF, leaderboard, fulfilment health | **P0** |
| [R2] | `/orders/gettimeseries` | GET | Reports main chart, 7-day ledger | **P0** |
| [R3] | `/products/getproductanalytics` | GET | Product matrix sales + per-product detail | **P0** |
| [R4] | `/imports/getimportlogs` (+ `/imports/upload`) | GET/POST | Import audit stream + validator | P1 |
| [R5] | `/products/getcatalogpresets` | GET | Inventory catalog presets (optional) | P2 |
| [R6] | `/tenants/getsettings` (+ `/tenants/updatesettings`) | GET/PUT | Settings + Brand studio | P1 |
| [R7] | `/insights/getforecast` | GET | Operations forecast tiles (optional) | P2 |
| [R8] | `/products/stocktransfer` | POST | Operations stock-transfer modal | P1 |
| [R9] | `/partners/getridertelemetry` | GET | Fleet rating, GPS, ETA | P1 |
| [R10] | `/deliveries/getdispatchbuckets` | GET | StoreDetail intraday dispatch | P1 |
| [R11] | `/customers/getcustomeranalytics` | GET | Customer CSAT/AOV/retention | P1 |
| [R12] | `/alerts/getalerts` | GET | Operational alerts feed | P1 |
| [R13] | `/reports/getschedules` (+ POST) | GET/POST | Scheduled reports (optional) | P2 |
Plus **mutation routes** already named in the endpoint sheet but not yet shape-documented — see
the last section.
---
## [R1] Revenue summary · `GET /orders/getrevenuesummary`
Real money totals. Today the app fakes revenue as `delivered × 355` — replace that.
**Request (query params)**
| param | type | required | notes |
|---|---|---|---|
| `tenantid` | int | ✓ | |
| `locationid` | int | | omit → all outlets (overall); set → store-wise |
| `fromdate` | date | ✓ | |
| `todate` | date | ✓ | |
**Response `details`** (single object)
```json
{
"tenantid": 1087,
"locationid": null,
"grossrevenue": 1248302.00,
"netrevenue": 1180500.00,
"profit": 354216.00,
"marginpct": 28.4,
"ordercount": 4921,
"deliveredcount": 4102,
"cancelledcount": 142,
"otifpct": 98.2,
"avgordervalue": 1580.00,
"prev_grossrevenue": 1090000.00,
"prev_ordercount": 4370
}
```
`prev_*` = same metric for the immediately preceding equal-length window (lets the UI show
`+14.2%` deltas without a second call). `otifpct` powers the OTIF / fulfilment-health tiles.
Frontend hook to add: `useFiestaRevenueSummary`.
---
## [R2] Orders / revenue time-series · `GET /orders/gettimeseries`
Powers the Reports main chart (Orders / Revenue / Cancelled / SKUs) and StoreDetail 7-day ledger.
**Request**
| param | type | required | notes |
|---|---|---|---|
| `tenantid` | int | ✓ | |
| `locationid` | int | | omit → overall |
| `granularity` | enum | ✓ | `day` \| `month` \| `year` |
| `fromdate` | date | ✓ | |
| `todate` | date | ✓ | |
**Response `details`** (array, one bucket per period)
```json
[
{ "label": "2026-06-01", "orders": 312, "revenue": 442800.00,
"delivered": 298, "cancelled": 9, "activeskus": 72 }
]
```
`label` = `YYYY-MM-DD` (day), `YYYY-MM` (month), or `YYYY` (year). Removes all hardcoded chart
arrays and the region-scaling multipliers (filter by `locationid` instead).
Frontend hook: `useFiestaTimeSeries`.
---
## [R3] Product sales analytics · `GET /products/getproductanalytics`
True units-sold + revenue per product, plus the per-product/per-outlet detail the matrix expands.
**Request**
| param | type | required | notes |
|---|---|---|---|
| `tenantid` | int | ✓ | |
| `locationid` | int | | omit → across all outlets |
| `subcategoryid` | int | | |
| `fromdate` / `todate` | date | | sales window (default month-to-date) |
| `keyword` | string | | |
| `pageno` / `pagesize` | int | | |
**Response `details`** (array)
```json
[
{ "productid": 88231, "productname": "Ponni Raw Rice 10kg",
"sku": "PONNI-RICE-10K", "categoryid": 2, "subcategoryname": "Rice",
"image": "https://…",
"unitssold": 12402, "revenue": 868140.00, "trend": "up",
"closingstock": 1402, "maxcapacity": 2000,
"binlocation": "BIN-C12", "lastauditdate": "2026-06-05", "verified": true,
"outlets": [ { "locationid": 1097, "locationname": "RS Puram", "stock": 840 } ] }
]
```
`trend` ∈ `up|flat|down`. `outlets[]` = real per-hub split (replaces hardcoded 60/40).
If the catalog doesn't track `binlocation`/`lastauditdate`, return `null` — the UI will hide them
rather than fake them. Frontend hook: `useFiestaProductAnalytics`.
---
## [R4] Import / sync audit log · `GET /imports/getimportlogs` + `POST /imports/upload`
Replaces the mock "Live Sync Audit Stream" and the hardcoded "14 duplicate SKUs" validator.
**GET request:** `tenantid` (✓), `pageno`, `pagesize`.
**GET `details`**
```json
[
{ "importid": 921, "batchref": "#IMP_0921_A", "type": "Inventory Sync",
"source": "ERP Export", "rows": 421, "result": "SUCCESS",
"message": "421 rows imported", "createdat": "2026-05-31T09:12:00" }
]
```
`result` ∈ `SUCCESS|FAILED|PARTIAL`.
**POST `/imports/upload`** (multipart, field `file` = CSV; plus `tenantid`) → returns the new log row
plus a validation block:
```json
{ "importid": 922, "result": "PARTIAL",
"validation": { "passed": false, "duplicateskus": ["ST-SONA-25K"],
"badcolumns": [45, 82], "headerversion": "v2.8" } }
```
Frontend hooks: `useFiestaImportLogs`, `useFiestaImportUpload` (mutation).
---
## [R5] Catalog presets *(optional)* · `GET /products/getcatalogpresets`
Inventory "Nilgiris Dairy / Coimbatore Heritage" quick-add packs.
**Request:** `tenantid` (✓). **`details`:**
```json
[ { "presetid": 3, "name": "Nilgiris Dairy Fresh Pack",
"items": [ { "name": "Ooty Butter 500g", "sku": "DY-OOT-BTR",
"subcategoryname": "Dairy", "price": 340, "image": "https://…" } ] } ]
```
> Alternative: skip this and reuse master catalog (`/products/getproducts`) filtered by subcategory.
---
## [R6] Merchant settings + branding · `GET /tenants/getsettings` + `PUT /tenants/updatesettings`
Replaces the localStorage `DEFAULTS` and the Brand Design Studio local state.
**GET request:** `tenantid` (✓). **GET `details`:**
```json
{
"tenantid": 1087,
"contactemail": "ops@ragul.com", "contactphone": "+91…",
"minordervalue": 199, "deliverycharge": 29, "prepmins": 20,
"deliverywindowmins": 45, "cancelwindowsecs": 120, "autoassignrider": true,
"defaulttaxpercent": 5, "codenabled": true, "onlinepaymentenabled": true,
"defaultregion": "Coimbatore", "defaultnewuserrole": 4,
"ordernotifications": true, "lowstockalerts": true, "dailysummaryemail": false,
"syncinterval": 15, "sandboxmode": false,
"branding": { "themename": "Kaveri Org", "primarycolor": "#16a34a",
"secondarycolor": "#f59e0b", "baglabel": "Freshly Harvested",
"ecoverified": true, "stickerpattern": "radial" }
}
```
**PUT body:** same object (partial allowed) → returns the updated object.
Frontend hooks: `useFiestaSettings`, `useFiestaUpdateSettings` (mutation).
---
## [R7] Forecast insight *(optional)* · `GET /insights/getforecast`
Operations "Forecast Efficiency 92% / ₹1.9L savings". Recommend dropping the tiles until a model
exists; if kept: **request** `tenantid` (✓), `locationid` (opt). **`details`:**
```json
{ "forecastefficiencypct": 92, "estsavingsperweek": 190000.00, "horizondays": 7 }
```
---
## [R8] Stock transfer · `POST /products/stocktransfer`
Operations transfer-stock modal.
**Body:**
```json
{ "tenantid": 1087, "productid": 88231,
"fromlocationid": 1097, "tolocationid": 1101, "quantity": 100 }
```
**`details`:** updated stock rows for both locations
```json
[ { "locationid": 1097, "productid": 88231, "closingstock": 740 },
{ "locationid": 1101, "productid": 88231, "closingstock": 360 } ]
```
---
## [R9] Rider telemetry · `GET /partners/getridertelemetry`
Replaces hardcoded rider `rating`, `battery`, `lastPing` and the fake GPS route / "9 MINS" / "1.2 km".
**Request:** `applocationid` (✓), `tenantid` (opt), `userid` (opt → single rider).
**`details`** (array)
```json
[
{ "userid": 7781, "name": "Karthikeyan R", "status": "Delivering",
"rating": 4.7, "completedtoday": 12, "battery": 84,
"lastping": "2026-06-06T14:21:00", "zone": "RS Puram",
"lat": 11.0041, "lng": 76.9612,
"activedelivery": { "deliveryid": 99213, "etamins": 9, "distancekm": 1.2,
"destlat": 11.0102, "destlng": 76.9550 } }
]
```
`status` ∈ `Delivering|Idle|Offline`. `activedelivery` = `null` when the rider is idle.
Frontend hook: `useFiestaRiderTelemetry`.
---
## [R10] Intraday dispatch buckets · `GET /deliveries/getdispatchbuckets`
Replaces StoreDetail `intervalSlots` (Morning Rush / Midday / Evening Peak computed from %).
**Request:** `tenantid` (✓), `locationid` (✓), `date` (✓, default today).
**`details`** (array, fixed buckets)
```json
[ { "bucket": "06:00-10:00", "label": "Morning Rush",
"orders": 64, "revenue": 88400.00, "status": "PEAK" } ]
```
`status` ∈ `PEAK|HIGH|NORMAL|LOW`. Frontend hook: `useFiestaDispatchBuckets`.
---
## [R11] Customer analytics · `GET /customers/getcustomeranalytics`
Replaces hardcoded CSAT 5.0 / retention 88.4% / AOV ₹1,580.
**Request:** `tenantid` (✓), `locationid` (opt), `customerid` (opt → single-customer rollup).
**`details`** (object)
```json
{
"retentionpct": 88.4, "avgordervalue": 1580.00, "csat": 4.9,
"totalcustomers": 1240,
"percustomer": { "customerid": 55012, "orderscount": 18,
"totalspent": 28450.00, "csat": 5.0, "lastorderdate": "2026-06-04" }
}
```
`percustomer` present only when `customerid` is supplied.
> Customer order **history** itself already exists: `GET /orders/getorders?customerid=` — wire that, no new API.
Frontend hook: `useFiestaCustomerAnalytics`.
---
## [R12] Operational alerts · `GET /alerts/getalerts`
Replaces the mock `operationalAlerts` (stock-critical, latency, rebalance…).
**Request:** `tenantid` (✓), `locationid` (opt), `status` (`open|all`), `pageno`, `pagesize`.
**`details`** (array)
```json
[ { "alertid": 5012, "tenantid": 1087, "locationid": 1097,
"type": "critical", "title": "Stock Critical: RS Puram",
"details": "Dairy inventory below 5%.",
"createdat": "2026-06-06T08:24:00", "acknowledged": false } ]
```
`type` ∈ `critical|warning|info`. Frontend hook: `useFiestaAlerts`.
---
## [R13] Scheduled reports *(optional)* · `GET /reports/getschedules` + `POST /reports/createschedule`
Replaces 3 hardcoded calendar events. Drop if not on the roadmap.
**GET `details`:**
```json
[ { "scheduleid": 11, "name": "Monthly Assortment Audit", "cron": "0 0 1 * *",
"nextrun": "2026-07-01T00:00:00", "format": "PDF", "recipients": ["ops@ragul.com"] } ]
```
**POST body:** `{ tenantid, name, cron, format, recipients[] }` → returns the created schedule.
---
## Mutation routes already named in the endpoint sheet (publish request/response, then we wire)
These are marked `REVIEW_REQUIRED` in `Fiesta_All_Endpoints_With_Tables_And_Params.xlsx`. We need
the exact request body + success response for each:
| Action | Suggested endpoint | Body (fields we'll send) |
|---|---|---|
| Create web order | `POST /orders/create` | tenantid, locationid, customerid, items[{productid,qty,price}], paymenttype |
| Update order status | `PUT /orders/updatestatus` | orderheaderid, status, financialflag |
| Assign rider / dispatch | `POST /deliveries/assign` | orderheaderid, tenantid, locationid, partnerid, userid |
| Update pickup / delivered | `PUT /deliveries/updatestatus` | deliveryid, status |
| Add multi-product stock | `POST /products/addstock` | tenantid, locationid, items[{productid,qty,cost}] |
| Create / update / delete product | `POST/PUT/DELETE /products/...` | product fields |
| Onboard tenant / store / location | `POST /tenants/onboard`, `POST /tenants/createlocation` | tenant + location fields |
---
## Frontend status (for reference)
- All read endpoints that **already exist** are wired (orders/deliveries/stock/customers/users/
locations/order-line-items/etc.).
- Each `[Rxx]` above corresponds to a visible `AwaitingApi` placeholder in the UI, so QA can see
exactly which screens are still blocked.
- The moment an endpoint here ships with the documented shape, wiring it is one hook + swapping the
placeholder — no redesign needed.