Seller identity is platform-owned. Product apps do not keep a parallel onboarding database, wizard contract, or journey flag.
Canonical chain
Party → Merchant Profile (@handle) → Account → Enrollment → Storefront / Listing
| Object | Owner | Meaning |
|---|---|---|
| Party | Party service | Legal person or organization |
| Merchant Profile | Merchant service | Reusable public identity, including globally unique @handle |
| Account | Merchant service | Profile × host organization |
| Enrollment | Merchant service | Account × product instance |
| Storefront / Listing | Merchant / Listing | Commerce inside that enrollment |
NIC, KYC, bank, and payout are not part of this chain. They belong to Merchant payments / payouts capability activation and Payment, after the seller can already catalog and take orders.
Core → SDK → product → edge
packages/core
Party + Merchant protobufs
RequestProductMerchantAccess (atomic Account + Enrollment + required Storefront)
ListMyMerchantSellingContexts (product-access state/action)
GetSellerIdentityEligibility
ResolvePublicBrandHandle (Fiton /@brand and /@brand/{shop})
packages/frontend-sdk
SellerService
ProductAccessSelector (Party-grouped seller identities; Theme from the host app)
products/fiton
Hub: create/rename Party; create/edit Profile display name + @handle
Policy-disabled Profile types remain visible but cannot be created
Access: ProductAccessSelector → POST /api/v2/seller/contexts/{profileId}/access
Studio: /seller/e/{enrollmentId}/… listings, orders, shop, inventory
Public: /@brand and /@brand/{shop}
products/console
Does not run Selling as
My Zinorel reads the same Party → Profile → Account → Enrollment chain
Admin GrantProductAccess is org ↔ product grants, not seller setup
platform/gateway
Public: GET /public/v1/brands/{brand}[/{shop}][ /listings]
Member: Fiton /api/v2/seller/… and authenticated brand reads
Resolves product instance from origin; does not store seller journeys
platform/authz
SpiceDB on party, merchant_profile, merchant_account, merchant_enrollment, storefront
request_account / join_product_instances / access_product remain platform relations
No Fiton-local journey tuples
Ads and later apps reuse the same Core RPCs and ProductAccessSelector. They do not copy Fiton’s studio routes.
Seller identity hub
The product groups Merchant Profiles beneath their legal Party. A user has at most one Personal Party and may create multiple Organization Parties. A Personal Party offers Personal and Brand Profiles; an Organization Party offers Business and Brand Profiles.
All four valid Party/Profile combinations stay visible. The Product Instance eligibility policy configured in Console enables or disables creation for the current app; disabled choices are explained, not hidden. The product backend rechecks the same policy before creating a Profile. Directly shared Profiles remain visible under a read-only Party group even when the user does not manage that Party.
Party rename changes only the Party display name. Profile edit changes the
public display name and globally unique @handle; it never silently renames
the legal Party.
Atomic setup command
MerchantService.RequestProductMerchantAccess(merchant_profile_id, idempotency_key) uses the trusted product-instance scope from Gateway. One idempotent mutation ensures Account (if missing), Enrollment, and the required default Storefront, then returns MerchantSellingContext.
Fiton is a BFF over that command. It does not write seller-access rows of its own.
Release order (after approval)
- Core tag with the Merchant access RPC and SellerJourney proto removal
- Merchant pin + image
- frontend-sdk
- Fiton backend, then Fiton frontend (so
/@brandand Selling as ship together) - Docs regenerate (
npm run docs:generate) - GitOps image pins
Do not commit or deploy this rewrite until that sequence is approved.