From 4464fed88aac6ceb710d532d813e8ead8968e819 Mon Sep 17 00:00:00 2001 From: sdarbinyan Date: Sun, 26 Jul 2026 20:13:56 +0400 Subject: [PATCH] feat(platform): add typed contracts for optional Seller Management module Architectural foundation only - no UI, no backend, no business logic. Per ADR-001 (Platform -> Marketplace -> Seller hierarchy) and ADR-009 (feature flags / capability guards): Seller is an optional child scope beneath a marketplace, not another tenant. New: - PlatformModulesConfig / SellerManagementModuleConfig (shared/models/config/platform-modules.model.ts) - the modules.sellerManagement.enabled contract, defaults to disabled (DEFAULT_PLATFORM_MODULES_CONFIG). - SellerConfig (shared/models/config/seller.model.ts) - typed shape for the resolved seller scope, mirroring TenantConfig's fields at the subset a seller needs. Frontend never resolves this itself; it only reads what the backend already decided (same convention as tenant resolution, ADR-001). Changed: - BootstrapConfig gained two optional fields: modules?, seller?. Both absent by default - every existing marketplace's bootstrap response is untouched, TypeScript-checked backward compatible (all new fields optional, no existing field types changed). tsc --noEmit clean. No component, facade, service, or route touched - this commit is pure type contracts. --- .../models/config/bootstrap-config.model.ts | 16 ++++++++++++++ src/app/shared/models/config/index.ts | 2 ++ .../models/config/platform-modules.model.ts | 22 +++++++++++++++++++ src/app/shared/models/config/seller.model.ts | 20 +++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 src/app/shared/models/config/platform-modules.model.ts create mode 100644 src/app/shared/models/config/seller.model.ts diff --git a/src/app/shared/models/config/bootstrap-config.model.ts b/src/app/shared/models/config/bootstrap-config.model.ts index 46aeee8..b1cfcbe 100644 --- a/src/app/shared/models/config/bootstrap-config.model.ts +++ b/src/app/shared/models/config/bootstrap-config.model.ts @@ -11,7 +11,9 @@ import { LocalizationConfig } from './localization.model'; import { NavigationConfig } from './navigation.model'; import { PageConfig } from './page.model'; import { PermissionsConfig } from './permissions.model'; +import { PlatformModulesConfig } from './platform-modules.model'; import { ProductPageConfig } from './product-page-config.model'; +import { SellerConfig } from './seller.model'; import { SeoConfig } from './seo.model'; import { StaticPagesConfig } from './static-page.model'; import { TenantConfig } from './tenant.model'; @@ -42,4 +44,18 @@ export interface BootstrapConfig { pages: PageConfig[]; staticPages?: StaticPagesConfig; widgetRegistry?: WidgetRegistryConfig; + /** + * Optional platform capability modules (e.g. Seller Management). Absent or + * `undefined` means every module is disabled - existing marketplaces that + * never send this field continue to behave exactly as today. See ADR-011. + */ + modules?: PlatformModulesConfig; + /** + * Present only when `modules.sellerManagement.enabled` is true and the + * resolved request scope is beneath a specific seller. Absent for every + * marketplace-level request, including all existing marketplaces. The + * frontend never resolves this itself (ADR-001, ADR-011) - it only reads + * whatever the backend already decided. + */ + seller?: SellerConfig; } diff --git a/src/app/shared/models/config/index.ts b/src/app/shared/models/config/index.ts index ef203c7..b94f466 100644 --- a/src/app/shared/models/config/index.ts +++ b/src/app/shared/models/config/index.ts @@ -12,8 +12,10 @@ export * from './localization.model'; export * from './navigation.model'; export * from './page.model'; export * from './permissions.model'; +export * from './platform-modules.model'; export * from './product-page-config.model'; export * from './section.model'; +export * from './seller.model'; export * from './seo.model'; export * from './static-page.model'; export * from './tenant.model'; diff --git a/src/app/shared/models/config/platform-modules.model.ts b/src/app/shared/models/config/platform-modules.model.ts new file mode 100644 index 0000000..8af64b3 --- /dev/null +++ b/src/app/shared/models/config/platform-modules.model.ts @@ -0,0 +1,22 @@ +/** + * Optional platform-level capability modules - distinct from + * `FeatureFlagsConfig`/`MarketplaceFeaturesConfig` (per-marketplace feature + * toggles). A module gates an entire optional capability that introduces a + * new scope beneath a marketplace (see ADR-011), not a simple on/off switch + * within the existing marketplace scope. + * + * Every module defaults to disabled. A disabled module must leave current + * behavior byte-identical: no new routes, no new menu entries, no new API + * calls, for every marketplace that doesn't opt in. + */ +export interface SellerManagementModuleConfig { + enabled: boolean; +} + +export interface PlatformModulesConfig { + sellerManagement: SellerManagementModuleConfig; +} + +export const DEFAULT_PLATFORM_MODULES_CONFIG: Required = { + sellerManagement: { enabled: false }, +}; diff --git a/src/app/shared/models/config/seller.model.ts b/src/app/shared/models/config/seller.model.ts new file mode 100644 index 0000000..d8d72bc --- /dev/null +++ b/src/app/shared/models/config/seller.model.ts @@ -0,0 +1,20 @@ +import { UUID } from '../../types/primitive.types'; + +/** + * Optional child scope beneath a marketplace (tenant). Mirrors `TenantConfig`'s + * shape at the fields a seller scope genuinely needs, not a copy of every + * tenant field - a seller is not a tenant (see ADR-011). + * + * The frontend never resolves which seller is active; the backend resolves it + * (same as tenant resolution, ADR-001) and includes it in the bootstrap + * response only when `modules.sellerManagement.enabled` is true and a seller + * scope actually applies to the current request. + */ +export interface SellerConfig { + id: UUID; + marketplaceId: UUID; + slug: string; + name: string; + defaultLocale: string; + supportedLocales: string[]; +}