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>
This commit is contained in:
88
docs/backend/PHASE-5-SELLER-PORTAL-CONTRACT.md
Normal file
88
docs/backend/PHASE-5-SELLER-PORTAL-CONTRACT.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# 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.1–5.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.
|
||||
Reference in New Issue
Block a user