# 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 = "" && (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 = `. The operator's collection-confirm page then handles the rest. Use the existing `/api/v1/order-items//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 = ""`. 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: ` 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 ```js // 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.