Files
marketplaces/docs/backend/PHASE-5-SELLER-PORTAL-CONTRACT.md
sdarbinyan 707db6d43c docs: backend contracts for Phases 5-7 (seller portal, server cart, reconciliation)
- Phase 5: Seller Portal from scratch (zero backend bytes exist today) -
  SellerOrganization/SellerUser/SellerMarketplaceMembership, all endpoints
  scoped server-side to the unified-orders Fulfillment model from Phase 2.
- Phase 6: server-owned Cart/CartLine/CheckoutSession, extending Phase 1's
  server-authoritative-amount contract into the cart itself. Replaces
  localStorage/Telegram-CloudStorage cart persistence.
- Phase 7: Refund and ReconciliationRecord entities, settlement contract.
  Flags additional payment providers (wallets/BNPL) as still an open
  business decision - not blocking, schema is provider-agnostic already.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 23:04:11 +04:00

89 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 5 Backend Contract — Seller Portal
Companion to [PRODUCT-PLAN-v3.1-DELIVERY-PLAN.md](../PRODUCT-PLAN-v3.1-DELIVERY-PLAN.md) Phase 5 (Sprints 5.15.3). Depends on [Phase 3](PHASE-3-CATALOG-OFFER-FULFILLMENT-CONTRACT.md) (Offer) and [Phase 2](PHASE-2-ORDERS-NOTIFICATIONS-CONTRACT.md) (unified Order + Fulfillment).
**Status: ready to build behind the launch gate.** Frontend note: Seller Management is currently a static placeholder, feature-flagged off by default, with **zero backend bytes and zero `HttpClient` reference** — this contract is a from-scratch build, not a gateway swap.
---
## 1. Multi-seller model reminder
Per the Phase 2 unified-orders decision: a seller never owns a separate `Order`. They see the `Fulfillment` group(s) that belong to them within shared orders, and the `OrderLine`s scoped to their `sellerId`. All endpoints below are pre-filtered server-side to the authenticated seller — never trust a frontend-supplied `sellerId` filter.
## 2. Entities
```ts
interface SellerOrganization {
id: string;
marketplaceId: string;
legalName: string;
status: 'pending' | 'approved' | 'suspended' | 'rejected';
bankDetailsRef: string; // pointer into secret storage, never raw account numbers over the wire
createdAt: string;
}
interface SellerUser {
id: string;
sellerOrganizationId: string;
role: 'SELLER_OWNER' | 'SELLER_CATALOG_MANAGER' | 'SELLER_ORDER_MANAGER' | 'SELLER_FINANCE_VIEWER' | 'SELLER_VIEWER';
email: string;
status: 'active' | 'invited' | 'suspended';
}
interface SellerMarketplaceMembership {
sellerOrganizationId: string;
marketplaceId: string;
status: 'pending' | 'approved' | 'suspended';
}
interface SellerIntegration {
sellerOrganizationId: string;
apiCredentialRef: string;
webhookUrl?: string;
lastSyncAt?: string;
lastSyncError?: string;
}
```
## 3. Endpoints (all scoped server-side to the authenticated seller's org)
```
POST /api/seller/v1/onboarding { legalName, contacts, marketplaceId }
GET /api/seller/v1/profile
GET /api/seller/v1/offers?status=&page=
POST /api/seller/v1/offers
PATCH /api/seller/v1/offers/{id}
POST /api/seller/v1/offers/bulk-price-update -- mass price/stock edit, see Phase 3 §6 for the shared bulk-import pattern
GET /api/seller/v1/orders?fulfillmentStatus=
PATCH /api/seller/v1/orders/{orderId}/fulfillment/{fulfillmentId} { status, evidence }
GET /api/seller/v1/finance/accruals
GET /api/seller/v1/finance/settlements
POST /api/seller/v1/finance/bank-details -- step-up auth + audit event required, see §5
GET /api/seller/v1/team
POST /api/seller/v1/team/invite { email, role }
GET /api/seller/v1/integrations
```
## 4. Roles (fixed set, enforced backend-side)
```
SELLER_OWNER - full access within the org
SELLER_CATALOG_MANAGER - offers/catalog only
SELLER_ORDER_MANAGER - orders/fulfillment only
SELLER_FINANCE_VIEWER - read-only finance
SELLER_VIEWER - read-only everything
```
No UI-only gating. Every endpoint above checks `SellerUser.role` server-side regardless of what the frontend renders — this is the same principle as [Track S](TRACK-S-SECURITY-RBAC-CONTRACT.md), scoped to the seller domain specifically.
## 5. Sensitive-action rules
- Bank/payment detail changes (`POST .../finance/bank-details`) require step-up authentication, produce an audit event, and — if maker/checker mode is enabled for the tenant — require a second approver before taking effect.
- A seller can never query, by any endpoint or parameter manipulation, another seller's products, orders, customers, finance data, or API keys. This must be enforced at the query layer (implicit `WHERE sellerOrganizationId = :authenticatedSeller`), not left to the frontend to "not ask for it."
## 6. What the frontend will start doing once this ships
- Replace the static Seller Management placeholder with real screens: Onboarding, Catalog, Prices & Stock, Orders, Finance, Team, Integrations (per plan §2.2).
- Resolve the two competing seller type shapes flagged in `GAPS-AND-IMPROVEMENTS.md` (`SellerConfig` in bootstrap models vs. `Seller`/`SellerBranding` in the domain layer) against this contract's `SellerOrganization`/`SellerUser` shapes.
- First-ever exercise of the `sellerManagement.enabled` flag at `true` — write a fixture test, since it has never been tested at its real-world-eventual value.