- 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>
4.3 KiB
Phase 5 Backend Contract — Seller Portal
Companion to PRODUCT-PLAN-v3.1-DELIVERY-PLAN.md Phase 5 (Sprints 5.1–5.3). Depends on Phase 3 (Offer) and Phase 2 (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 OrderLines 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
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, 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(SellerConfigin bootstrap models vs.Seller/SellerBrandingin the domain layer) against this contract'sSellerOrganization/SellerUsershapes. - First-ever exercise of the
sellerManagement.enabledflag attrue— write a fixture test, since it has never been tested at its real-world-eventual value.