Orders Live
Order tracking + history — for both consumers (their orders) and sellers (orders to fulfill).
1. Overview
Once a checkout creates a StoreOrder, both sides get a view: consumer sees status updates as the seller progresses (pending → accepted → preparing → ready / out_for_delivery → delivered), seller sees a kanban-style list with action buttons (Accept, Decline, Start Preparing, etc.).
Cancellation is supported on both sides with optional reason capture (added 2026-04-17 for the offline-launch flow where sellers verify orders by phone first).
2. User journey
Consumer
- Profile → My Orders OR direct deep link from order confirmation email
- See unified chronological list (store + eats orders, both sources merged)
- Tap an order → status timeline + items + delivery address
- If still
pending→ Cancel button available
Seller
- Seller dashboard → Orders tab
- See live kanban (pending / accepted / preparing / ready / out for delivery / delivered / cancelled)
- Pending orders show customer phone as
tel:link with "Call to Confirm" badge - Decline → prompt for optional cancellation reason (max 500 chars, persisted to DB)
3. Web ↔ Mobile parity
| Capability | Web | Mobile |
|---|---|---|
| Consumer order list | ✅ /orders (unified store + eats) | ✅ orders.tsx (store-orders only) |
| Order detail | ✅ /orders/[id] | ✅ order/[id].tsx |
| Cancel own order | ✅ pending only | ✅ pending only |
| Seller order kanban | ✅ /seller/stores/[id] Orders tab | ❌ Seller is web-only |
| Tel: link + Call to Confirm | ✅ | — |
| Cancellation reason capture | ✅ window.prompt | — |
4. Key components
- Web consumer:
src/app/(consumer)/orders/page.tsx,src/app/(consumer)/orders/[id]/page.tsx - Web seller:
src/app/seller/stores/[id]/page.tsx(Orders tab section) - Mobile consumer:
mobile/app/orders.tsx,mobile/app/order/[id].tsx - Status helpers:
src/lib/fulfillment.ts—getValidStatusTransitions,getStatusLabel,canAcceptOrders,validatePickupTime
5. APIs
| Endpoint | Method | Purpose |
|---|---|---|
/api/store-orders | GET | List own orders (consumer) |
/api/store-orders/[id] | GET | Single order detail with items |
/api/store-orders/[id]/cancel | PATCH | Consumer cancel (only if pending) |
/api/seller/stores/[id]/orders | GET, PATCH | Seller list + status updates (accepts cancellationReason on cancel) |
/api/orders/consumer | GET | Unified store + eats list (web only) |
/api/orders/[id]/status | PATCH | Eats status update (legacy, eats archived) |
6. Database touchpoints
StoreOrder— primary entity. Status, payment, fulfillment, timestamps for every status (acceptedAt,preparingAt, etc.)StoreOrderItem— line items with frozen price + name (so historical orders survive product edits)Order(eats) — historical eats orders preserved (not creating new ones)Notification(consumer) +SellerNotification— push channel rowsEmailLog— order confirmation send tracked
7. Business logic
Status flow (StoreOrder)
- Delivery:
pending → accepted → preparing → ready → out_for_delivery → delivered → completed - Pickup:
pending → accepted → preparing → ready_for_pickup → completed - Either:
* → cancelled(only frompending/acceptedfor consumer; any non-terminal state for seller) - Each transition is enforced by
getValidStatusTransitions(currentStatus, fulfillmentType)
Status timestamps (analytics gold)
Every transition records a timestamp (acceptedAt, preparingAt, readyAt, etc.). These power per-store delivery time analytics, prep-time accuracy, etc.
Cancellation reason capture
- On
status='cancelled', the API accepts an optionalcancellationReasonstring (max 500 chars) - Persisted to
StoreOrder.cancellationReason - Surfaced in admin views + seller dashboard
Auto-assign delivery partner
- For
deliveryorders that aren'tselfDelivery, onstatus='accepted'or'preparing'the system firesassignDeliveryPartner()(non-blocking) - Algorithm: Haversine + smart scoring (distance + load + rating) — see
src/lib/delivery-engine.ts
Reel attribution on order completion
- If the order came from a tagged reel (within 24h click-to-purchase window), the linked
ReelEarningrow is confirmed ondeliveredand reversed oncancelled
8. Feature flags / env vars
None directly. PAYMENTS_ONLINE_ENABLED indirectly affects orders (online payments create orders via a different code path).
9. Tests
tests/build-integrity.test.ts— order status transitions, status timestampstests/store-product-flow.test.ts— checkout → order creationtests/offline-only-launch.test.ts— cancellation reason capture
10. Known gotchas
- Mobile orders screen lists store-orders ONLY — eats are tracked via the live restaurant order screen, not the orders list. Web shows both because eats orders are historical.
- Status transitions are server-enforced — client can't push an invalid transition. Returns 400 with helpful error.
- Customer phone is shown to seller as
tel:link — tap-to-call directly from the order card. Crucial for the offline-launch verification flow. - Cancellation reason is OPTIONAL but recommended. Browser
window.promptis the simplest UX; can be upgraded to a custom modal post-launch. - Auto-cancel on payment timeout: online orders that don't complete within 5 min (
PAYMENT_TIMEOUT_MS) are auto-cancelled by/api/payments/cleanupcron.
11. Related
- Cart · Checkout
- Notifications (push fires on every status update)
- Email Infrastructure (order confirmation)