Canonical · reviewed 2026-09-01

Seller product access

How Party and Merchant Profile become Account, Enrollment, and Storefront for a product instance, and which layer owns each step.

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

ObjectOwnerMeaning
PartyParty serviceLegal person or organization
Merchant ProfileMerchant serviceReusable public identity, including globally unique @handle
AccountMerchant serviceProfile × host organization
EnrollmentMerchant serviceAccount × product instance
Storefront / ListingMerchant / ListingCommerce 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)

  1. Core tag with the Merchant access RPC and SellerJourney proto removal
  2. Merchant pin + image
  3. frontend-sdk
  4. Fiton backend, then Fiton frontend (so /@brand and Selling as ship together)
  5. Docs regenerate (npm run docs:generate)
  6. GitOps image pins

Do not commit or deploy this rewrite until that sequence is approved.