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.
This commit is contained in:
@@ -45,6 +45,7 @@ It is a platform runtime that must support unlimited tenants from one Angular ap
|
|||||||
- [ADR-008](adr/ADR-008-theme-engine-and-design-token-runtime.md)
|
- [ADR-008](adr/ADR-008-theme-engine-and-design-token-runtime.md)
|
||||||
- [ADR-009](adr/ADR-009-feature-flags-and-capability-guards.md)
|
- [ADR-009](adr/ADR-009-feature-flags-and-capability-guards.md)
|
||||||
- [ADR-010](adr/ADR-010-backward-compatibility-for-auth-payment-authorization.md)
|
- [ADR-010](adr/ADR-010-backward-compatibility-for-auth-payment-authorization.md)
|
||||||
|
- [ADR-011](adr/ADR-011-optional-seller-management-module.md)
|
||||||
|
|
||||||
### Engineering Rule Documents
|
### Engineering Rule Documents
|
||||||
|
|
||||||
|
|||||||
72
docs/architecture/foundation/Seller-Management-Diagrams.md
Normal file
72
docs/architecture/foundation/Seller-Management-Diagrams.md
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# Seller Management — Architecture Diagrams
|
||||||
|
|
||||||
|
Companion diagrams for [ADR-011](adr/ADR-011-optional-seller-management-module.md).
|
||||||
|
Architecture only — no UI, no backend, no business logic exists yet.
|
||||||
|
|
||||||
|
## 1. Hierarchy
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
Platform["Platform<br/>(one Angular runtime)"]
|
||||||
|
Marketplace["Marketplace (tenant)<br/>always present · backend-resolved from Host<br/>ADR-001"]
|
||||||
|
SellerA["Seller A<br/>optional, 0..N"]
|
||||||
|
SellerB["Seller B<br/>optional, 0..N"]
|
||||||
|
NoSeller["No sellers<br/>(default — most marketplaces today)"]
|
||||||
|
|
||||||
|
Platform --> Marketplace
|
||||||
|
Marketplace --> SellerA
|
||||||
|
Marketplace --> SellerB
|
||||||
|
Marketplace -.default state.-> NoSeller
|
||||||
|
```
|
||||||
|
|
||||||
|
Marketplace is the only primary tenant. Seller is a child scope of exactly
|
||||||
|
one marketplace — never a sibling tier, never resolved on its own.
|
||||||
|
|
||||||
|
## 2. Bootstrap module gate
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
Request["GET /bootstrap"] --> Backend["Backend resolves:<br/>tenant (always)<br/>seller (only if applicable)"]
|
||||||
|
Backend --> Bootstrap["BootstrapConfig"]
|
||||||
|
Bootstrap --> ModulesCheck{"modules.sellerManagement.enabled?"}
|
||||||
|
ModulesCheck -->|false / absent, default| Identical["Behavior identical to today.<br/>No new routes, menus, or API calls."]
|
||||||
|
ModulesCheck -->|true| Available["Seller-aware behavior becomes available<br/>(not built yet — future work, own ADR)"]
|
||||||
|
Bootstrap -.optional field.-> SellerField["BootstrapConfig.seller<br/>(SellerConfig, present only when<br/>backend resolved a seller scope)"]
|
||||||
|
```
|
||||||
|
|
||||||
|
The frontend performs no resolution — it reads whatever the backend already
|
||||||
|
decided into `BootstrapConfig.modules` / `BootstrapConfig.seller`, exactly
|
||||||
|
the same discipline as tenant resolution (ADR-001) and feature-flag gating
|
||||||
|
(ADR-009).
|
||||||
|
|
||||||
|
## 3. Type contracts introduced (this ADR only)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
classDiagram
|
||||||
|
class BootstrapConfig {
|
||||||
|
+TenantConfig tenant
|
||||||
|
+PlatformModulesConfig? modules
|
||||||
|
+SellerConfig? seller
|
||||||
|
...existing fields unchanged
|
||||||
|
}
|
||||||
|
class PlatformModulesConfig {
|
||||||
|
+SellerManagementModuleConfig sellerManagement
|
||||||
|
}
|
||||||
|
class SellerManagementModuleConfig {
|
||||||
|
+boolean enabled
|
||||||
|
}
|
||||||
|
class SellerConfig {
|
||||||
|
+UUID id
|
||||||
|
+UUID marketplaceId
|
||||||
|
+string slug
|
||||||
|
+string name
|
||||||
|
+string defaultLocale
|
||||||
|
+string[] supportedLocales
|
||||||
|
}
|
||||||
|
BootstrapConfig --> PlatformModulesConfig
|
||||||
|
BootstrapConfig --> SellerConfig
|
||||||
|
PlatformModulesConfig --> SellerManagementModuleConfig
|
||||||
|
```
|
||||||
|
|
||||||
|
`modules` and `seller` are both optional on `BootstrapConfig`. Every field
|
||||||
|
already on `BootstrapConfig` is untouched.
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
# 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.
|
||||||
Reference in New Issue
Block a user