Initial commit: nick docs

This commit is contained in:
moojttaba
2026-05-23 20:35:34 +03:30
commit 0da235ae27
90 changed files with 18268 additions and 0 deletions

View File

@@ -0,0 +1,127 @@
---
title: Delivery Confirmation Flow
tags: [flow, delivery, escrow-release, code]
related_models: ["[[PurchaseRequest]]", "[[Payment]]"]
related_apis: ["POST /api/marketplace/purchase-requests/:id/delivery-code", "POST /api/marketplace/purchase-requests/:id/verify-delivery"]
---
# Delivery Confirmation Flow
After the escrow is funded ([[Payment Flow - SHKeeper]] / [[Payment Flow - DePay & Web3]]) and the seller has prepared the item, the seller **marks shipped**, the buyer **enters a delivery code** to confirm receipt, and the escrow becomes eligible for release ([[Payout Flow]]).
## Actors
- **Seller** — marks the order shipped and presents the delivery code to the buyer at hand-off.
- **Buyer** — confirms by entering the code in the dashboard.
- **Backend** — `DeliveryService` (`backend/src/services/delivery/DeliveryService.ts`), exposed through the marketplace routes (`backend/src/services/marketplace/routes.ts`).
- **MongoDB** — `purchaserequests.deliveryInfo` subdocument fields.
- **Socket.IO** — `delivery-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`.
2. **Delivery code generation** — when the order transitions to `delivery`, `DeliveryService.generateDeliveryCode(requestId)` is invoked. It:
- 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}`.
- Sends a notification to the buyer with the code (in-app, and via email if configured).
3. **Buyer entry** — buyer meets the courier / picks up the item, enters the code in `frontend/src/sections/request/components/seller-steps/delivery-code-verification.tsx` (also surfaced on the buyer side via `step-5-receive-goods.tsx`).
4. **Verification**`POST /api/marketplace/purchase-requests/:id/verify-delivery` with `{ code }`:
- 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`).
5. **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]].
6. **Manual fast-track** — the buyer can also tap "Confirm I received it" to skip the code (used when the code path fails — e.g. lost in transit) which patches `status` to `delivered`. This relies on admin trust.
## Sequence diagram
```mermaid
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"
BE->>BE: DeliveryService.generateDeliveryCode
BE->>DB: deliveryInfo.deliveryCode=XXXXXX\nexpires=+7d
BE->>IO: emit request-{id} 'delivery-code-generated'
BE->>B: notification w/ code (in-app/email)
S->>B: At hand-off, share the 6-digit code (verbally)
B->>FE: Enter code in dashboard
FE->>BE: POST /api/marketplace/purchase-requests/{id}/verify-delivery {code}
BE->>DB: match code, expires>now, !used
BE->>DB: deliveryCodeUsed=true; status="delivered"
BE->>IO: emit request-{id} 'purchase-request-update' status-changed
BE->>B,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 |
| `POST` | `/api/marketplace/purchase-requests/:id/delivery-code` | Manual code regeneration (admin) |
| `POST` | `/api/marketplace/purchase-requests/:id/verify-delivery` | Buyer confirms with code |
| `PATCH` | `/api/marketplace/purchase-requests/:id/confirm-delivery` | Buyer fast-track confirm (no code) |
## Database writes
- **`purchaserequests.deliveryInfo`** — `deliveryCode`, `deliveryCodeGeneratedAt`, `deliveryCodeExpiresAt`, `deliveryCodeUsed`, `deliveryCodeUsedAt`.
- **`purchaserequests.status`** — `delivery``delivered` → (eventually `seller_paid``completed`).
- **`notifications`** — generated for both parties.
## Socket events emitted
- **`delivery-code-generated`** → `request-{id}` (with code, expiresAt).
- **`delivery-update`** → `request-{id}` (`type: 'code-generated'`).
- **`purchase-request-update`** `status-changed` on `delivery → delivered`.
- **`new-notification`** → `user-{buyerId}` with the code.
## Side effects
- Code is **emitted via socket and in-app notification**. If a malicious actor has access to the buyer's notifications, they could intercept and confirm delivery prematurely. Treat the code as confidential at the UI layer.
- Triggers the path that eventually frees up the escrow (manual today via [[Payout Flow]], auto in the future).
## Error / edge cases
- **Wrong code** → `400 Invalid delivery code`.
- **Expired code** (>7 days) → `400 Code expired`. Admin can regenerate via the manual endpoint.
- **Already used code** → `400 Code already used`.
- **Buyer never 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 code** → `POST /:id/delivery-code` regenerates a new 6-digit value, invalidates the old one, and re-notifies. Restrict to admin/seller to avoid abuse.
> [!tip] Use the code as proof-of-handover
> The seller should ask the courier or the buyer at the door for the code before leaving the item. If the buyer disputes "never received", an unused code is strong circumstantial evidence; a used code = buyer confirmed.
## Linked flows
- [[Payment Flow - SHKeeper]] / [[Payment Flow - DePay & Web3]] — funding precondition.
- [[Escrow Flow]] — state transitions triggered by confirmation.
- [[Payout Flow]] — fires after confirmation (manual today).
- [[Dispute Flow]] — escape hatch.
- [[Notification Flow]] — channel for the code.
## 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`