docs: complete code-reality alignment for remaining docs + reconcile issue set
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>
This commit is contained in:
@@ -2,11 +2,13 @@
|
||||
title: Payment Flow - SHKeeper
|
||||
tags: [flow, payment, shkeeper, crypto, escrow, webhook]
|
||||
related_models: ["[[Payment]]", "[[PurchaseRequest]]", "[[SellerOffer]]"]
|
||||
related_apis: ["POST /api/payment/shkeeper/create", "POST /api/payment/shkeeper/webhook", "POST /api/payment/:id/release", "POST /api/payment/:id/refund"]
|
||||
related_apis: ["POST /api/payment/shkeeper/intents", "POST /api/payment/shkeeper/webhook", "POST /api/payment/:id/release", "POST /api/payment/:id/refund"]
|
||||
---
|
||||
|
||||
> **Last updated:** 2026-05-29 — aligned with code (see Doc vs Code Audit Report)
|
||||
|
||||
> [!caution] Audit — 2026-05-29
|
||||
> This document was reviewed against the live codebase. **2 corrections applied**: the non-existent HTTP polling endpoint has been removed (status updates arrive via socket only), and the release/refund/confirm paths have been corrected to remove the erroneous `/shkeeper/` segment.
|
||||
> This document was reviewed against the live codebase. **3 corrections applied**: (1) the non-existent HTTP polling endpoint has been removed (status updates arrive via socket only), (2) the release/refund/confirm paths have been corrected to remove the erroneous `/shkeeper/` segment, and (3) the intent-creation endpoint corrected from `/shkeeper/create` to `/shkeeper/intents` and parallel stats/export paths documented.
|
||||
|
||||
# Payment Flow — SHKeeper (Crypto Pay-In)
|
||||
|
||||
@@ -66,7 +68,7 @@ stateDiagram-v2
|
||||
### Phase 1 — Create intent
|
||||
|
||||
1. Buyer clicks "Pay" on the chosen offer (`/dashboard/buyer/requests/{id}` → step-3-select-and-pay).
|
||||
2. Frontend POSTs `POST /api/payment/shkeeper/create` with `{ purchaseRequestId, sellerOfferId, amount, token?, network? }`.
|
||||
2. Frontend POSTs `POST /api/payment/shkeeper/intents` with `{ purchaseRequestId, sellerOfferId, amount, token?, network? }`.
|
||||
3. Backend `createPayInIntent`:
|
||||
- Validates ObjectIds (`shkeeperService.ts:55-71`). Special path for **template checkout** (string IDs starting with `template-checkout-`).
|
||||
- **Duplicate-guard #1** (`:75-116`): if there is already an active `Payment` (`status ∈ {pending, processing}`) for the same `{purchaseRequestId, sellerOfferId, buyerId}`, the existing record is reused — same `paymentUrl`, no new wallet allocation.
|
||||
@@ -127,7 +129,7 @@ stateDiagram-v2
|
||||
|
||||
21. The buyer's checkout page subscribes to socket events (`payment-update`, `template-checkout-payment-confirmed`). When the status flips to `completed`, the UI transitions to "Payment received" and unlocks the next buyer step (await delivery).
|
||||
|
||||
> [!warning] ⚠️ No HTTP polling endpoint — socket events only
|
||||
> [!warning] No HTTP polling endpoint — socket events only
|
||||
> `GET /api/payment/shkeeper/status/:paymentId` **does not exist** — there is no polling route in `shkeeperRoutes.ts`. Status transitions must be observed via Socket.IO events (`payment-update`, `template-checkout-payment-confirmed`). Any frontend code path that polls this URL will always receive 404. Remove HTTP polling and rely solely on the socket subscription.
|
||||
|
||||
22. The seller's dashboard receives `seller-offer-update` `payment-completed` and surfaces the green "Order paid — start preparing" banner.
|
||||
@@ -148,7 +150,7 @@ sequenceDiagram
|
||||
actor S as Seller
|
||||
|
||||
B->>FE: Choose offer, click "Pay"
|
||||
FE->>BE: POST /api/payment/shkeeper/create
|
||||
FE->>BE: POST /api/payment/shkeeper/intents
|
||||
BE->>DB: dedupe / upsert Payment(status:"pending")
|
||||
BE->>R: getCachedWallet(amount, token, network, requestId)
|
||||
alt cache hit
|
||||
@@ -183,18 +185,26 @@ sequenceDiagram
|
||||
|
||||
## API calls
|
||||
|
||||
| Method | Endpoint | Purpose | Source |
|
||||
|---|---|---|---|
|
||||
| `POST` | `/api/payment/shkeeper/create` | Create pay-in intent | `shkeeperRoutes.ts` → `shkeeperService.createPayInIntent` |
|
||||
| `POST` | `/api/payment/shkeeper/webhook` | Receive SHKeeper webhook | `shkeeperWebhook.handleShkeeperWebhook` |
|
||||
| `POST` | `/api/payment/:id/release` | Release escrow to seller | `paymentRoutes.ts` |
|
||||
| `POST` | `/api/payment/:id/release/confirm` | Confirm escrow release | `paymentRoutes.ts` |
|
||||
| `POST` | `/api/payment/:id/refund` | Refund to buyer | `paymentRoutes.ts` |
|
||||
| `POST` | `/api/payment/:id/refund/confirm` | Confirm buyer refund | `paymentRoutes.ts` |
|
||||
| `POST` | `/api/payment/payments/:id/fetch-tx` | Manual transaction lookup | `paymentRoutes.ts` |
|
||||
| ~~`GET /api/payment/shkeeper/status/:paymentId`~~ | | ⚠️ **404 — does not exist.** Use socket events instead. | — |
|
||||
| Method | Endpoint | Purpose | Auth | Source |
|
||||
|---|---|---|---|---|
|
||||
| `POST` | `/api/payment/shkeeper/intents` | Create pay-in intent | Bearer JWT (buyer) | `shkeeperRoutes.ts` → `shkeeperService.createPayInIntent` |
|
||||
| `POST` | `/api/payment/shkeeper/webhook` | Receive SHKeeper webhook | HMAC / API key | `shkeeperWebhook.handleShkeeperWebhook` |
|
||||
| `POST` | `/api/payment/:id/release` | Release escrow to seller | Bearer JWT | `paymentRoutes.ts` |
|
||||
| `POST` | `/api/payment/:id/release/confirm` | Confirm escrow release | Bearer JWT | `paymentRoutes.ts` |
|
||||
| `POST` | `/api/payment/:id/refund` | Refund to buyer | Bearer JWT | `paymentRoutes.ts` |
|
||||
| `POST` | `/api/payment/:id/refund/confirm` | Confirm buyer refund | Bearer JWT | `paymentRoutes.ts` |
|
||||
| `POST` | `/api/payment/payments/:id/fetch-tx` | Manual transaction lookup | Bearer JWT | `paymentRoutes.ts` |
|
||||
| `GET` | `/api/payment/payments/stats` | Payment statistics (admin-gated strict) | Bearer JWT + admin role | `paymentRoutes.ts` |
|
||||
| `GET` | `/api/payment/stats` | Payment statistics (no admin guard) | Bearer JWT | `paymentRoutes.ts` |
|
||||
| ~~`GET /api/payment/shkeeper/status/:paymentId`~~ | | **404 — does not exist.** Use socket events instead. | — | — |
|
||||
|
||||
> [!warning] ⚠️ Release/refund path correction
|
||||
> [!note] Two parallel stats paths
|
||||
> Two separate stats endpoints exist with different auth levels:
|
||||
> - `GET /api/payment/payments/stats` — admin-gated (strict role check); intended for admin dashboard.
|
||||
> - `GET /api/payment/stats` — authenticated but no admin guard; accessible to any logged-in user.
|
||||
> Similarly, export endpoints exist at two paths with different auth levels. Confirm which is appropriate for each consumer before wiring the frontend.
|
||||
|
||||
> [!warning] Release/refund path correction
|
||||
> Previously documented paths included a `/shkeeper/` segment that does **not** exist in the router:
|
||||
> - ~~`POST /api/payment/shkeeper/:id/release`~~ → correct: `POST /api/payment/:id/release`
|
||||
> - ~~`POST /api/payment/shkeeper/:id/release/confirm`~~ → correct: `POST /api/payment/:id/release/confirm`
|
||||
|
||||
Reference in New Issue
Block a user