Skip to content

Architecture

Products Catalog is a Layer 3 host on the Base Template layering (template layering and reuse). Layer suffixes are described in solution structure.

Service contracts (five surfaces)

Code-first ServiceModel.Grpc contracts (no .proto):

Contract gRPC adapter REST controller Route prefix
IProductManagementService GrpcProductManagementService ProductsController api/products-catalog
IProductQueryService GrpcProductQueryService ProductsController same
IFeatureCatalogService GrpcFeatureCatalogService FeaturesController api/products-catalog/features
IPricingModelCatalogService GrpcPricingModelCatalogService PricingModelsController api/products-catalog/pricing-models
IBusinessModelCatalogService GrpcBusinessModelCatalogService BusinessModelsController api/products-catalog/business-models

REST endpoints on ProductsController: POST products, PUT products/{productId}, POST products/{productId}/retire, POST products/{productId}/editions, PUT editions/{editionId}, POST editions/{editionId}/features/{featureId}/activate|deactivate, GET products/{productId}, GET products, GET editions/{editionId}.

Messaging

Publish-only (ADR-0003): eight events published from DefaultProductsProcessor via IEventBus.PublishEvent; topology CatalogMassTransitTopology.ConfigureIntegrationEventPublishTopology. No consumers or sagas.

Persistence (10-table schema)

NHibernate + Fluent mappings; schema ConnectSoft.Saas.ProductsCatalog; FluentMigrator MicroserviceMigration. Tables: Products, Editions, Features, EditionFeatures, PricingModels, BusinessModels, ServiceLevelAgreements, EditionSlas, EditionPricings, EditionBusinessModels.

Key constraints: UQ_Products_TenantId_Slug (slug unique per tenant), UQ_Editions_ProductId_Code (edition code unique per product), tenant indexes. Multitenancy via shared SaasTenantFilter (tenantId) on entity maps. Repositories: IProductsRepository, IFeaturesRepository, IPricingModelsRepository, IBusinessModelsRepository (+ keyed variants).

Shipped dialect is SQL Server; docs/Testing.md references PostgreSQL for some persistence-spec tests (dialect is config-driven).

Concurrency

ProductEditorGrain keyed {tenantId}/{productId} serializes writes per product.

See also