Files
marketplaces/docs/architecture/foundation/adr/ADR-011-optional-seller-management-module.md
sdarbinyan 6029acc2d4 docs(architecture): ADR-011 - optional Seller Management module
Documents the decision behind the typed contracts added in the
previous commit: Seller Management is an optional platform capability
module (Platform -> Marketplace -> Seller, 0..N per marketplace), not
a second tenancy tier. Backend resolves seller scope the same way it
already resolves tenant (ADR-001); frontend never resolves it itself.
Gated by one typed flag (modules.sellerManagement.enabled), same
capability-guard discipline as ADR-009, defaulting to disabled/absent
so existing marketplaces are byte-identical.

Explicitly scopes out UI, backend, and business logic as future work
requiring its own ADR/implementation pass once the module is actually
built out.

Added companion diagrams (Seller-Management-Diagrams.md): hierarchy,
bootstrap module-gate flow, and the type-contract class diagram.
Registered ADR-011 in the foundation README's ADR index.
2026-07-26 20:15:40 +04:00

5.5 KiB

ADR-011: Optional Seller Management Module

Status: Accepted Date: 2026-07-26

Context

The platform today has a two-level hierarchy: Platform → Marketplace (tenant), per ADR-001. Some marketplaces will eventually need a third, optional level: individual Sellers operating storefronts within one marketplace (a marketplace-of-marketplaces / multi-vendor model). Not every marketplace needs this — most tenants today have none.

Seller Management must not become a second tenancy model. ADR-001 already established that tenant identity is backend-resolved from request Host and the frontend never passes or resolves tenant identity itself. Introducing sellers must not weaken that discipline or introduce a second, parallel resolution mechanism the frontend has to reason about.

Decision

Seller Management is an optional platform capability module, not a new tenancy tier equal to Marketplace:

Platform
  └── Marketplace (tenant)      — always present, resolved by backend (ADR-001)
        └── Seller (optional)   — 0..N per marketplace, resolved by backend
  • Marketplace remains the sole primary tenant. A seller is a child scope of exactly one marketplace, never a sibling of Marketplace and never resolved independently of it.
  • The frontend never resolves seller identity itself — same rule as tenant resolution (ADR-001). The backend decides whether the current request scope is marketplace-level or seller-level and reflects that decision in the bootstrap response.
  • The frontend consumes bootstrap only. No new endpoint, header, or client-side resolution logic is introduced by this ADR. If a seller scope applies, BootstrapConfig.seller (see SellerConfig) is present; if not, it's absent. There is no other channel.
  • Gated by a module flag, not scattered conditionals. The capability is controlled by one typed flag — BootstrapConfig.modules.sellerManagement. enabled (see PlatformModulesConfig) — checked in one place if/when seller-aware behavior is built, never as ad hoc if (tenant.id === 'x') or similar marketplace-specific conditionals anywhere in feature code. This follows the same capability-guard discipline ADR-009 already established for feature flags.

Backward Compatibility (non-negotiable)

  • modules and seller are both optional fields on BootstrapConfig. Existing marketplaces whose bootstrap response never includes them are unaffected — untyped-absent is not a special case to handle, it's the default.
  • DEFAULT_PLATFORM_MODULES_CONFIG defaults sellerManagement.enabled to false. A marketplace that has never heard of this feature, and a marketplace where the backend explicitly disables it, behave identically: no new routes, no new menu entries, no new API calls, no visual change.
  • No existing BootstrapConfig field, route, guard, or component changes as a result of this ADR. This ADR adds types; it changes nothing that already runs.

Scope of this ADR

This ADR and its accompanying typed contracts (PlatformModulesConfig, SellerManagementModuleConfig, SellerConfig) are architecture only:

  • No UI is introduced — no seller-facing pages, no admin seller-management screens, no navigation entries.
  • No backend is implemented — no endpoints, no seller data model, no resolution logic.
  • No business logic is introduced — no seller CRUD, no seller-scoped permissions, no seller onboarding flow.

Those are all future work, gated behind modules.sellerManagement.enabled, and each will need its own ADR/implementation pass once the module is actually being built out (routing strategy under a seller scope, admin UI, backend data model and resolution, permission model for seller-level roles). This ADR exists so that future work has a typed foundation to build on without retrofitting the platform/marketplace hierarchy after the fact.

Consequences

Positive:

  • Marketplaces that don't need multi-vendor support pay zero cost — no new code path executes, no new field is even present in their bootstrap response.
  • Future Seller Management work has a settled hierarchy and typed contract to build against instead of ad hoc per-feature decisions about where "seller" fits.
  • Consistent with the platform's existing capability-guard discipline (ADR-009) — one flag, checked in one place, not scattered conditionals.

Negative:

  • Adds two optional fields to BootstrapConfig that most of the codebase will never populate — acceptable, matches the existing pattern of several other optional bootstrap fields (header?, catalog?, layout?, etc.).
  • Defers real design decisions (seller-scoped routing, seller admin permissions, seller data ownership) to whenever the module is actually implemented — intentional; this ADR does not pre-invent that design.

Compliance Requirements

  • No component, facade, or service may branch on marketplace identity or seller identity directly. All seller-aware behavior, once built, must check modules.sellerManagement.enabled (or a capability-guard built on top of it) as the single gate.
  • No frontend code may attempt to resolve which seller is active by itself (URL parsing, local storage, guessed convention, etc.) — that information only ever comes from BootstrapConfig.seller, backend-resolved, exactly like tenant resolution today.
  • Any future work that adds seller-facing routes, UI, or backend calls must keep all of it inert and unreachable while modules.sellerManagement. enabled is false, with no exception.