WFDASH-WEBAPP/docs/driver-app-data-source.md
SJCoetz 7df7a8850f feat(item-history): add getItemHistory service with 5 PB queries
Co-authored-by: Orca <help@stably.ai>
2026-07-29 14:51:58 +02:00

12 KiB
Raw Permalink Blame History

Driver App — Data Source & Integration Notes

Audience: the agent building the driver-facing app. Author context: WFDash is the operator app (Next.js + PocketBase). This doc describes how the driver app should read the same data so the operator's "Assign driver" action on /collection-map shows up on the driver's phone in real time.


TL;DR

A driver's stop list = every order_items row where drv_id == currentDriver.id and item_status == "assigned", regardless of the ready_for_collection flag. Show ready rows one colour, not-yet-ready rows another colour. Do not filter ready_for_collection server-side — that flag controls whether the operator may assign the row, not whether the driver should see it once assigned.

Worked example

"Bright Packaging" supplier, assigned to Driver A. The supplier has 6 items on the same PO:

id item_status drv_id ready_for_collection what driver sees
1 assigned A true blue pill — "Ready"
2 assigned A true blue pill — "Ready"
3 assigned A true blue pill — "Ready"
4 assigned A false amber pill — "Waiting — ask supplier"
5 assigned A false amber pill — "Waiting — ask supplier"
6 assigned A false amber pill — "Waiting — ask supplier"

The driver app should show all 6 under one supplier card. The driver picks up the 3 ready items and asks the supplier about the other 3 — that's the whole point of surfacing both states.


1. Topology

┌──────────────┐    HTTPS    ┌─────────────────────┐
│ Driver App   │ ──────────► │ WFDash Next.js API  │  (recommended)
│ (mobile)     │             │ /api/v1/...         │
└──────────────┘             └──────────┬──────────┘
                                       │ admin client
                                       ▼
                              ┌─────────────────────┐
                              │ PocketBase          │
                              │   - order_items     │
                              │   - suppliers       │
                              │   - users (drivers) │
                              └─────────────────────┘

Two reasonable shapes:

  1. Through the WFDash API — easier to evolve, single auth surface, but WFDash already does its own UI-side loading; no dedicated driver endpoint exists yet. You'll need to either add one or call an existing route.
  2. Direct PocketBase — driver app talks to PB with its own auth. Faster, but you re-implement filters, expansions, and auth yourself.

Recommendation: start direct-to-PocketBase for the read path. The schema is small and the filters are simple. Add a WFDash proxy only if you need server-side validation (e.g., before letting the driver mark something collected).


2. Source collection: order_items

This is the canonical row. The operator's "Assign driver" modal on /collection-map flips these fields:

field type meaning
item_status select One of pending, processed, po_generated, collection_pool, assigned, collected, stock_verified, picking, ready_delivery, delivered, cancelled. For driver app purposes, you care about assigned (in your list) and collected (you've picked it up — drop from list or move to history).
drv_id relation → users The driver this row is assigned to. Filter on this.
drv_status select Operator-side mirror of item_status for drivers — unassigned, assigned, en_route, collected, failed. You can ignore this; item_status is the truth.
drv_assigned_at date When the operator hit "Assign". Sort by this if you want a "newest first" list.
ready_for_collection bool Operator-side gate. Set to true by /collection-pool "Mark ready". Do not filter on this — surface it as a colour.
notes text Operator note (often set alongside ready_for_collection=true, e.g. "Boxes at back loading dock"). Show this prominently when set.
supplier relation → suppliers Expand to get suppliername, email, coordinates (semicolon-separated "lat;lng" string in WFDash), phone, etc.
description text Item description.
quantity number Quantity ordered for this line.
po_description text PO-level description if different from the item line.
order relation → orders Expand to get order_number.
purchase_order relation → purchase_orders Expand to get po_number.

Other fields you can ignore (for now)

cost_price, selling_price, markup, markup_percent, qty_*, problem_flag, problem_type, problem_notes, legacy_order_item_id, in_stock, driver_status, delivery_status, invoice_status, delivered_at, drv_collected_at.


3. The driver-stop query

PocketBase filter syntax

collection: order_items
filter: drv_id = "<driverId>" && (item_status = "assigned" || item_status = "collected")
sort: -drv_assigned_at
expand: supplier, purchase_order, order
  • drv_id is a relation, so in PocketBase filter syntax you compare against the relation's record id.
  • item_status — include assigned (active work) and optionally collected (just-picked-up, before the operator flips it forward). Do not include collection_pool (operator hasn't picked a driver), delivered/cancelled (terminal), or anything else.
  • Expand keeps you off N+1 lookups. PB will inline supplier / PO / order objects.

Important: do NOT add ready_for_collection=true to the filter

The operator-side gate that prevents assignment does not mean the driver should be blind to unready items. The whole point is for the driver to nudge the supplier ("by the way, I see you have a few more items on the PO — are they ready too?"). Server-side filtering on ready_for_collection defeats the purpose.


4. UI — colour and grouping

Match WFDash's existing palette so when an operator looks over the driver's shoulder it lines up:

State Pill label Colour (Tailwind)
item_status == "collected" "Collected" emerald — bg-emerald-100 text-emerald-900 border-emerald-300
ready_for_collection == true (not collected) "Ready" blue — bg-blue-100 text-blue-900 border-blue-300
ready_for_collection == false (not collected) "Waiting — ask supplier" amber — bg-amber-100 text-amber-900 border-amber-300

Counts strip per driver (header)

6 stops · 🟢 0 collected · 🔵 3 ready · 🟠 3 waiting

Hide segments that are zero (omit "0 collected" if nothing's collected yet). This mirrors /collection-map's right-sidebar driver cards exactly.

Grouping

Group rows by supplier.id. Within a supplier, sort however you like. The supplier card header should show the supplier name + the counts strip for that supplier's items:

┌─ Bright Packaging ─────────────────────────┐
│ 6 items · 🔵 3 ready · 🟠 3 waiting        │
│  • 100× Cardboard boxes        [Ready]     │
│  • 50× Bubble wrap rolls        [Ready]     │
│  • 20× Tape dispensers          [Ready]     │
│  • 10× Pallet wrap              [Waiting]   │
│  • 5× Strapping rolls           [Waiting]   │
│  • 2× Stretch film              [Waiting]   │
│                                [Open in maps]│
└────────────────────────────────────────────┘

Notes

If notes is set on a row, surface it inline (the operator often writes "back loading dock", "ask for John", "ring bell"). WFDash renders these as a hover tooltip; in a phone UI a chevron expand or bottom-sheet works fine.


5. "What should the driver be able to do?"

Out of scope for this doc, but: the only writes the operator expects from the driver app today are:

  • Mark collected — flip item_status from assigned → collected and set drv_status = "collected", drv_collected_at = <now>. The operator's collection-confirm page then handles the rest. Use the existing /api/v1/order-items/<id>/status route (Bearer AGENT_API_KEY) if going through WFDash, or hit PB directly.
  • Report a problem — set problem_flag = true, problem_type = "supplier", problem_notes = "<text>". The operator surfaces these on /collection-confirm.

Do not let the driver flip ready_for_collection or reassign themselves — those are operator-only actions.


6. Auth

Drivers are PB users records. They log in with email/password (PB's built-in users collection, _pb_users_auth_). The driver app stores the PB auth token after login and passes it as Authorization: <token> on every API call. PB enforces row-level listRule / viewRule (@request.auth.id != '') — drivers will see only what they're allowed to read, which today is all order_items. You'll likely want to tighten that to drv_id = @request.auth.id via PB rule, but that's a schema change — confirm with the WFDash maintainer first.


7. What changes you'll need from WFDash

If you go the direct-PB route, you can ship without any WFDash changes — just consume the existing schema and filter.

If you go the WFDash-API route, you'll need one of:

  • A new endpoint GET /api/v1/drivers/me/stops that runs the filter above through the admin PB client and returns shaped JSON, or
  • A small wrapper around the existing /api/v1/order-items list route (if you want to reuse pagination/auth shape).

Either way, the filter logic is identical to section 3.


8. Quick reference — the canonical filter

// PocketBase JS SDK
const stops = await pb.collection("order_items").getList(1, 200, {
  filter: 'drv_id = "' + driverId + '" && (item_status = "assigned" || item_status = "collected")',
  sort: "-drv_assigned_at",
  expand: "supplier,purchase_order,order",
});

Each row in stops.items carries everything section 2 lists. Use expand.supplier.suppliername, expand.supplier.coordinates, etc. for display.


9. Open questions for the operator (WFDash maintainer)

  • Should drv_status ever diverge from item_status for the driver? (Today they mirror — pick item_status as truth.)
  • Should the driver see historical collected items from today, or only active assigned? (collected rows have already moved past the driver's hand — usually safe to drop from the live list, but the operator may want a "today's history" pane.)
  • Are PO numbers (po_number) surfaced on the supplier card, or only on drill-in? Operator's map shows po_number; safe default = show on card.