docs: sync from backend 19f7eb9, frontend 60ee6fb — Task #10 AML screening

This commit is contained in:
Siavash Sameni
2026-05-28 20:35:38 +04:00
parent fd2aa71ef4
commit ddc0434819
34 changed files with 709 additions and 453 deletions

View File

@@ -7,7 +7,7 @@ related_apis: ["POST /api/marketplace/offers", "GET /api/marketplace/offers/requ
# Seller Offer Flow
A **seller** browses open purchase requests and submits an offer with a price, delivery time, and notes. The buyer is notified in real time and can accept (which moves the request to [[Payment Flow - SHKeeper]]) or reject.
A **seller** browses open purchase requests and submits an offer with a price, delivery time, and notes. The buyer is notified in real time and can accept (which moves the request to [[PRD - Request Network In-House Checkout]]) or reject.
## Actors
@@ -34,7 +34,7 @@ stateDiagram-v2
pending --> active: (optional — manual seller activation)
pending --> withdrawn: seller withdraws (only while pending)
pending --> rejected: another offer accepted\nor buyer rejects this one
pending --> accepted: acceptOffer()\nor SHKeeper PAID webhook
pending --> accepted: acceptOffer()\nor payment confirmed
accepted --> [*]
rejected --> [*]
withdrawn --> [*]
@@ -79,14 +79,14 @@ The active enum values are `pending | accepted | rejected | withdrawn` (`SellerO
### Accept → Payment
14. The buyer's "Pay this offer" button kicks off [[Payment Flow - SHKeeper]] with `purchaseRequestId` and `sellerOfferId`. The offer is **not** immediately marked `accepted`; the SHKeeper webhook does that atomically when the on-chain payment is confirmed.
15. On `PAID`/`OVERPAID` webhook (see `backend/src/services/payment/shkeeper/shkeeperWebhook.ts:573-714`):
14. The buyer's "Pay this offer" button kicks off [[PRD - Request Network In-House Checkout]] with `purchaseRequestId` and `sellerOfferId`. The offer is **not** immediately marked `accepted`; payment confirmation does that atomically when the on-chain payment is confirmed.
15. On Request Network payment confirmation:
- The selected offer's `status``accepted`.
- All other offers on the same request → `rejected` via `SellerOffer.updateMany`.
- The purchase request: `status = "payment"`, `selectedOfferId = sellerOfferId`.
- A direct chat is created (see [[Chat Flow]]).
- Notifications: `notifyOfferAccepted` to the winning seller, generic rejection notifications to the others (`SellerOfferService.acceptOffer` does the same in the manual path).
- Socket events: `seller-offer-update` `payment-completed` to the winner, `seller-offer-update` `offer-rejected` to losers (`shkeeperWebhook.ts:679-705`).
- Socket events notify the winner and reject/close competing offers.
### Withdrawal
@@ -127,7 +127,7 @@ sequenceDiagram
BE-->>FE_B: offers
alt
B->>FE_B: Click pay to finish selected offer
B->>FE_B: SHKeeper webhook handles payment result
B->>FE_B: Request Network payment confirms
else
B->>FE_B: Open chat to negotiate
end
@@ -171,7 +171,7 @@ sequenceDiagram
- **Price = 0 or negative** → Mongoose validator on `SellerOffer.price.amount` rejects (`SellerOfferService.ts:55-60` logs the validation state).
- **Seller withdraws an `accepted` offer** → blocked by the `{ status: 'pending' }` filter; returns `null`.
- **`validUntil` in the past at creation** → schema-level validator should reject; otherwise the next `markExpiredOffersAsWithdrawn` cron run flips it to `withdrawn`.
- **Race condition: two payments to two different offers** → unlikely (frontend disables payment buttons once one is chosen); even if both arrive, the SHKeeper webhook coordinator (`PaymentCoordinator`) is idempotent and the first PAID wins.
- **Race condition: two payments to two different offers** → unlikely (frontend disables payment buttons once one is chosen); even if both arrive, `PaymentCoordinator` and provider idempotency decide which confirmed payment wins.
- **Offer for a deleted request** → orphan; the webhook handler logs `"Purchase request not found"` and continues. Periodic cleanup should remove orphans.
> [!tip] Real-time UX
@@ -181,7 +181,7 @@ sequenceDiagram
- [[Purchase Request Flow]] — produces the requests sellers offer on.
- [[Negotiation Flow]] — counter-offer in `in_negotiation`.
- [[Payment Flow - SHKeeper]] — locks in the accepted offer.
- [[PRD - Request Network In-House Checkout]] — locks in the accepted offer.
- [[Chat Flow]] — direct chat opened after payment.
- [[Notification Flow]] — channels for offer events.
- [[Rating Flow]] — seller's average rating displayed in the offer card.
@@ -191,7 +191,7 @@ sequenceDiagram
- Backend: `backend/src/services/marketplace/SellerOfferService.ts`
- Backend: `backend/src/services/marketplace/marketplaceController.ts`
- Backend: `backend/src/models/SellerOffer.ts`
- Backend: `backend/src/services/payment/shkeeper/shkeeperWebhook.ts:573-714` (acceptance via webhook)
- Backend: `backend/src/services/payment/paymentCoordinator.ts` (payment-state cascade)
- Frontend: `frontend/src/sections/request/components/seller-steps/step-1-send-proposal.tsx`
- Frontend: `frontend/src/sections/request/components/buyer-steps/step-3-select-and-pay.tsx`
- Frontend: `frontend/src/app/dashboard/seller/marketplace/`