Files
nick-doc/04 - Flows/Delivery Confirmation Flow.md
Siavash Sameni a1f056e6a5 docs: align flow docs with code reality + create 35 implementation issue files
Flow docs updated (11 files):
- Delivery Confirmation: reversed actor roles (buyer generates, seller verifies),
  fixed endpoint paths (/delivery-code/generate, /delivery-code/verify)
- Passkey (WebAuthn): removed stub/simulated-key claims; real @simplewebauthn/server
  attestation is implemented; refresh tokens are persisted
- Dispute: corrected resolve schema (action enum), removed non-existent statuses,
  documented security gaps (no role guards on status/resolve/assign), route shadowing,
  all socket events are TODO stubs
- Seller Offer: corrected all endpoint paths, removed 'active' status, documented
  withdraw dead code, missing seller history page, select-offer notification gap
- Notification: corrected mark-all-read method+path, fixed GET /:id broken lookup,
  added unread-count-update socket event
- Authentication: corrected rate limiter (counts all attempts), axios 403 not handled,
  deleteAccount wrong endpoint bug, changePassword no UI
- Password Reset: corrected 6-digit code (not 8), documented no-complexity gap on
  reset-with-code vs token reset
- Payment Flow DePay: /create→/save, removed phantom sub-routes, SIM_ bypass risk,
  PaymentProvider type gap, getProviderIntentEndpoint routing bug
- Payment Flow SHKeeper: removed phantom polling endpoint, fixed release/refund paths
- Purchase Request: added pending_payment/active statuses, fixed sellers/attachments
  endpoints, corrected socket events, PUT→PATCH bug
- Escrow: documented dispute resolve does not touch escrow, route shadowing, confirm-delivery auth gap

Issues created (35 files in Issues/):
- 9 security issues (critical) including: dispute privilege escalation ×4,
  unauthenticated payment/scanner endpoints ×2, SIM_ production bypass,
  confirm-delivery ownership gap
- 26 additional major/critical bugs covering broken endpoints, missing features,
  data integrity gaps, and frontend-backend mismatches

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 14:47:49 +04:00

9.3 KiB

title, tags, related_models, related_apis
title tags related_models related_apis
Delivery Confirmation Flow
flow
delivery
escrow-release
code
PurchaseRequest
Payment
POST /api/marketplace/purchase-requests/:id/delivery-code/generate
POST /api/marketplace/purchase-requests/:id/delivery-code/verify

Delivery Confirmation Flow

Last updated: 2026-05-29 — aligned with code (see Doc vs Code Audit Report)

After the escrow is funded (PRD - Request Network In-House Checkout / Escrow Flow) and the seller has prepared the item, the seller marks shipped, the buyer generates and reads out the delivery code, the seller verifies the code to confirm receipt, and the escrow becomes eligible for release (Payout Flow).

Actors

  • Buyer — after the order reaches delivery status, explicitly generates the delivery code and reads it out to the seller at hand-off.
  • Seller — types the code into their dashboard to confirm delivery.
  • BackendDeliveryService (backend/src/services/delivery/DeliveryService.ts), exposed through the marketplace routes (backend/src/services/marketplace/routes.ts).
  • MongoDBpurchaserequests.deliveryInfo subdocument fields.
  • Socket.IOdelivery-code-generated, delivery-update.

Preconditions

  • PurchaseRequest.status is payment, processing, or delivery.
  • Payment.escrowState === 'funded'.

Step-by-step narrative

  1. Seller marks shipped — from the seller step frontend/src/sections/request/components/seller-steps/step-3-ship-goods.tsx, clicks "Mark as shipped". This patches the request status to delivery. No code is generated at this point.
  2. Buyer generates the delivery code — once status is delivery, the buyer explicitly triggers POST /api/marketplace/purchase-requests/:id/delivery-code/generate (buyerId is enforced server-side). DeliveryService.generateDeliveryCode(requestId):
    • Generates a 6-digit code (Math.floor(100000 + Math.random()*900000)).
    • Sets deliveryInfo.deliveryCode, deliveryCodeGeneratedAt = now, deliveryCodeExpiresAt = now + 7d, deliveryCodeUsed = false.
    • Emits delivery-code-generated and delivery-update to request-{requestId}.
    • The code is displayed to the buyer in frontend/src/sections/request/components/buyer-steps/step-5-receive-goods.tsx.
  3. Buyer reads code to seller — at hand-off the buyer reads the 6-digit code out loud (or shows it) to the seller.
  4. Seller enters code — seller types the code into frontend/src/sections/request/components/seller-steps/delivery-code-verification.tsx.
  5. VerificationPOST /api/marketplace/purchase-requests/:id/delivery-code/verify with { code } (selectedOffer.sellerId is enforced server-side):
    • Matches code against deliveryInfo.deliveryCode.
    • Checks deliveryCodeExpiresAt > now and deliveryCodeUsed === false.
    • On success: deliveryInfo.deliveryCodeUsed = true; deliveryCodeUsedAt = now. Status flips delivery → delivered.
    • Emits purchase-request-update status-changed.
    • Triggers buyer/seller notifications via notifyDeliveryConfirmed (see PurchaseRequestService.ts:631-641).
  6. Alternative path — buyer fast-track — the buyer can also call PATCH .../confirm-delivery to set status to delivered without any code (used when the code path fails, e.g. code expired or lost). ⚠️ Authorization gap: this endpoint currently has no authorization check; any authenticated user can call it.
  7. Optional auto-release timer — once status === 'delivered', a scheduled job can flip the request to confirming and then to seller_paid after a grace period (e.g. 48h). The auto-release worker is not yet implemented; today an admin completes the chain via Payout Flow.

Sequence diagram

sequenceDiagram
    autonumber
    actor S as Seller
    actor B as Buyer
    participant FE as Frontend
    participant BE as Backend
    participant DB as MongoDB
    participant IO as Socket.IO

    S->>FE: Click "Mark as shipped"
    FE->>BE: PATCH /api/marketplace/purchase-requests/{id} {status:"delivery"}
    BE->>DB: PurchaseRequest.status="delivery"
    Note over BE,DB: No code generated here

    B->>FE: View delivery code in step-5-receive-goods
    FE->>BE: POST /api/marketplace/purchase-requests/{id}/delivery-code/generate
    BE->>DB: deliveryInfo.deliveryCode=XXXXXX\nexpires=+7d
    BE->>IO: emit request-{id} 'delivery-code-generated'
    FE->>B: Display 6-digit code

    B->>S: At hand-off, read the 6-digit code aloud
    S->>FE: Enter code in delivery-code-verification
    FE->>BE: POST /api/marketplace/purchase-requests/{id}/delivery-code/verify {code}
    BE->>DB: match code, expires>now, !used
    BE->>DB: set deliveryCodeUsed = true
    BE->>DB: set status = "delivered"
    BE->>IO: emit request-{id} 'purchase-request-update' status-changed
    BE->>B: notifyDeliveryConfirmed
    BE->>S: notifyDeliveryConfirmed
    Note over BE: Auto-release timer (planned) → seller_paid → payout

API calls

Method Endpoint Purpose
PATCH /api/marketplace/purchase-requests/:id {status:"delivery"} Seller marks shipped
GET /api/marketplace/purchase-requests/:id/delivery-code Retrieve current code (buyer + seller)
POST /api/marketplace/purchase-requests/:id/delivery-code/generate Buyer generates delivery code (buyer only)
POST /api/marketplace/purchase-requests/:id/delivery-code/verify Seller verifies code (seller only)
GET /api/marketplace/purchase-requests/:id/delivery-code/status Check code status (buyer + seller)
PATCH /api/marketplace/purchase-requests/:id/confirm-delivery Buyer fast-track confirm (no code) — ⚠️ no auth check

Phantom frontend actions (routes do NOT exist on backend)

These Redux/API actions exist in the frontend but call endpoints that return 404:

Frontend action Called path Behaviour
regenerateDeliveryCode /delivery-code/regenerate 404s; frontend falls back to /delivery-code/generate
getDeliveryAttempts /delivery-code/attempts 404s — feature not implemented
getDeliveryStats /delivery/stats 404s — feature not implemented

Two paths to delivered status

  1. Code path — seller calls POST .../delivery-code/verify with the correct, unexpired code → status becomes delivered.
  2. Fast-track path — buyer calls PATCH .../confirm-delivery (no code required) → also becomes delivered. ⚠️ Currently no authorization check on this endpoint.

Database writes

  • purchaserequests.deliveryInfodeliveryCode, deliveryCodeGeneratedAt, deliveryCodeExpiresAt, deliveryCodeUsed, deliveryCodeUsedAt.
  • purchaserequests.statusdeliverydelivered → (eventually seller_paidcompleted).
  • notifications — generated for both parties.

Socket events emitted

  • delivery-code-generatedrequest-{id} (with code, expiresAt).
  • delivery-updaterequest-{id} (type: 'code-generated').
  • purchase-request-update status-changed on delivery → delivered.

Side effects

  • The code is shown only to the buyer in their dashboard. The buyer verbally shares it with the seller — there is no backend push of the code to the seller.
  • Triggers the path that eventually frees up the escrow (manual today via Payout Flow, auto in the future).

Error / edge cases

  • Wrong code400 Invalid delivery code.
  • Expired code (>7 days) → 400 Code expired. Buyer can generate a new code via POST .../delivery-code/generate (the regenerateDeliveryCode frontend action also falls through to this endpoint).
  • Already used code400 Code already used.
  • Buyer never generates / confirms → status remains delivery. Auto-release timer (not yet built) should trigger delivered after N days. Until then, admin intervention.
  • Seller delivers but never marks shipped → buyer can dispute via Dispute Flow; the dispute resolution will release the escrow regardless.
  • Lost / expired code → buyer re-triggers POST .../delivery-code/generate to get a fresh code, invalidating the old one.

[!tip] The buyer holds the code, not the seller The seller should ask the buyer for the code at hand-off. If the buyer disputes "never received", an unused code is strong circumstantial evidence that delivery has not been confirmed; a used code = seller confirmed receipt.

Linked flows

Source files

  • Backend: backend/src/services/delivery/DeliveryService.ts
  • Backend: backend/src/services/marketplace/routes.ts (delivery endpoints)
  • Backend: backend/src/services/marketplace/PurchaseRequestService.ts:631-641 (confirmation notifications)
  • Frontend: frontend/src/sections/request/components/seller-steps/step-3-ship-goods.tsx
  • Frontend: frontend/src/sections/request/components/seller-steps/delivery-code-verification.tsx
  • Frontend: frontend/src/sections/request/components/buyer-steps/step-5-receive-goods.tsx