Remaining docs updated to match code (the docs that the first pass had not covered):
- Flows: Chat, Referral, Rating, Registration, Google OAuth, Negotiation, Payout,
Trezor Safekeeping — corrected endpoints, socket events, status enums, auth gaps
- API Reference: User API, Trezor API — admin route prefix/verb/status corrections,
added undocumented endpoints (ton-proof challenge, profile email verify,
GET /trezor/account, POST /trezor/verify-operation)
- Data Models: Chat, Notification, Payment, PointTransaction, User — corrected
enums (PaymentProvider, escrowState, PointTransaction.type, User.status),
90-day notification TTL, soft-delete semantics, wallet fields
Trezor "zero frontend" finding (audit C31/C32) corrected as STALE:
- Verified current code HAS a full frontend Trezor implementation (admin/trezor
page, TrezorSettingsView, trezorConnector via @trezor/connect-web,
TrezorSignDialog, actions/trezor.ts building the {message,signature} object)
- Fixed Trezor Safekeeping Flow doc (removed false "no frontend" warnings)
- Reclassified ISSUE-012 as invalid/superseded with explanation
Issue set reconciled to a single canonical numbering (ISSUE-001..054):
- Adopted the comprehensive 51-issue set (long-slug, fully indexed)
- Removed 35 superseded short-slug duplicates from the first pass
- Removed a duplicate ISSUE-046 file
- Added 3 issues the 51-set lacked: ISSUE-052 (completed-not-counted-in-stats),
ISSUE-053 (axios 401-only interceptor), ISSUE-054 (rate limiter counts all attempts)
- Regenerated Issues Index: 53 open (14 critical, 39 major) + 1 invalid
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Backend — DeliveryService (backend/src/services/delivery/DeliveryService.ts), exposed through the marketplace routes (backend/src/services/marketplace/routes.ts).
PurchaseRequest.status is payment, processing, or delivery.
Payment.escrowState === 'funded'.
Step-by-step narrative
Seller marks shipped — from the seller step frontend/src/sections/request/components/seller-steps/step-3-ship-goods.tsx, clicks "Mark as shipped". The frontend action updateDelivery calls PUT /api/marketplace/purchase-requests/:id/delivery. The controller's updateDeliveryInfo sets shippedAt and advances status to delivery. No code is generated at this point.
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)).
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.
Buyer reads code to seller — at hand-off the buyer reads the 6-digit code out loud (or shows it) to the seller.
Seller enters code — seller types the code into frontend/src/sections/request/components/seller-steps/delivery-code-verification.tsx.
Verification — POST /api/marketplace/purchase-requests/:id/delivery-code/verify with { code } (selectedOffer.sellerId is enforced server-side). Handled by DeliveryService.verifyDeliveryCode (lines 180-212):
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-updatestatus-changed.
Sends delivery-confirmed notifications to both buyer and seller directly within DeliveryService.verifyDeliveryCode.
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). This endpoint emits only purchase-request-update with status-changed — it does not send delivery-specific notifications to either party. ⚠️ Authorization gap: this endpoint currently has no authorization check; any authenticated user can call it.
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: PUT /api/marketplace/purchase-requests/{id}/delivery
BE->>DB: PurchaseRequest.shippedAt=now, 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' {code, expiresAt}
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 (DeliveryService.verifyDeliveryCode)
BE->>S: notifyDeliveryConfirmed (DeliveryService.verifyDeliveryCode)
Note over BE: Auto-release timer (planned) → seller_paid → payout
API calls
Method
Endpoint
Purpose
PUT
/api/marketplace/purchase-requests/:id/delivery
Seller marks shipped (sets shippedAt, advances to delivery)
Buyer fast-track confirm (no code) — ⚠️ no auth check, no delivery notifications
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
Code path — seller calls POST .../delivery-code/verify with the correct, unexpired code → status becomes delivered. Both buyer and seller receive delivery-confirmed notifications (sent by DeliveryService.verifyDeliveryCode).
Fast-track path — buyer calls PATCH .../confirm-delivery (no code required) → also becomes delivered. ⚠️ Currently no authorization check on this endpoint, and no delivery-specific notifications are sent to either party.
notifications — generated for both parties (code path only).
Socket events emitted
delivery-code-generated → request-{id} room (payload: { requestId, code, expiresAt, timestamp }). ⚠️ Security note: the full 6-digit code is included in the payload and broadcast to all subscribers in the room, including the seller. The buyer dashboard displays the code; the seller receives it via socket as well.
purchase-request-updatestatus-changed on delivery → delivered.
Side effects
The code is displayed to the buyer in their dashboard. The buyer verbally shares it with the seller at hand-off. Note that the delivery-code-generated socket event also broadcasts the raw code to the entire request room (including the seller — see socket events section above).
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. Buyer can generate a new code via POST .../delivery-code/generate (the regenerateDeliveryCode frontend action also falls through to this endpoint).
Already used code → 400 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.