Aggregate Roots¶
Target Architecture — Final-State Design
This page describes the final-state domain model of the Marketplace Platform. Each aggregate root is a consistency boundary owned by one microservice, persisted with NHibernate on Azure SQL / PostgreSQL, and emitting domain events in the canonical event envelope. Naming follows Naming Conventions: singular PascalCase roots, {Root}Repository repositories.
The Marketplace owns ten aggregate roots across the seven bounded contexts. Each section below specifies the aggregate's purpose, fields, child entities, value objects, invariants, domain events, repository, and persistence.
MarketplaceAsset¶
Purpose — The catalog entry for a publishable asset of one of the nine asset types. The identity and metadata anchor that all versions, reviews, and installations reference. Owned by MarketplaceCatalogService (Catalog & Search).
Fields — AssetId (identity), Name, AssetType (enum of the nine types), PublisherId, Description, Tags, Status (Draft, PendingQualityScan, Published, Deprecated, Withdrawn), LatestVersionId, PricingPlanId, LicenseRequired, AggregateRating, RatingCount, TenantId, CreatedAt, UpdatedAt.
Entities — AssetMedia (icons, screenshots), AssetTagAssignment.
Value Objects — AssetType, AssetCategory, TagSet, RatingSummary, TenantId.
Invariants — An asset must have a verified PublisherId before it can move to Published; AssetType is immutable after creation; LatestVersionId always references a released AssetVersion; a withdrawn asset cannot be installed.
Domain Events — AssetPublished, AssetCatalogued, AssetReviewed (rating projection), AssetDeprecated, AssetWithdrawn.
Repository — MarketplaceAssetRepository.
Persistence — Azure SQL / PostgreSQL via NHibernate; marketplace_asset table with a child asset_media; read model cached in Redis and projected into the search index.
AssetVersion¶
Purpose — An immutable, semantically versioned release of a MarketplaceAsset, the unit of compatibility and installation. Owned by AssetVersionService (Publishing & Versioning).
Fields — AssetVersionId (identity), AssetId, SemanticVersion, Status (PendingQualityScan, PendingSigning, Released, Yanked), PackageId, ReleaseNotes, Signed, Signature, QualityVerdict, CompatibilityProfile, ReleasedAt, TenantId.
Entities — VersionDependencyDeclaration, ReleaseNote.
Value Objects — SemanticVersion, QualityVerdict, Signature, CompatibilityProfile.
Invariants — SemanticVersion is unique per asset and immutable once Released; a version cannot be Released without a passing QualityVerdict and a valid Signature; a yanked version remains queryable but cannot be newly installed.
Domain Events — AssetVersionReleased, AssetQualityScanned, AssetVersionYanked.
Repository — AssetVersionRepository.
Persistence — Azure SQL / PostgreSQL via NHibernate; package bytes live in Azure Blob / Azure Artifacts referenced by PackageId.
AssetPackage¶
Purpose — The distributable binary artifact for an AssetVersion and its location in the distribution store. Owned by AssetVersionService (Publishing & Versioning).
Fields — AssetPackageId (identity), AssetVersionId, PackageType (Zip, NuGet, ContainerImage), StoreLocation, ContentHash, SizeBytes, Manifest, PublishedAt, TenantId.
Entities — PackageManifestEntry.
Value Objects — ContentHash, StoreLocation (blob URI / Artifacts feed / ACR ref), PackageManifest.
Invariants — ContentHash must match the stored bytes; a package is immutable after publish; StoreLocation is consistent with PackageType (NuGet → Azure Artifacts, ContainerImage → ACR, Zip → Blob).
Domain Events — AssetPackagePublished.
Repository — AssetPackageRepository.
Persistence — metadata in Azure SQL / PostgreSQL via NHibernate; bytes in Azure Blob (Zip), Azure Artifacts (NuGet), or Azure Container Registry (images). See Storage.
AssetDependency¶
Purpose — A declared dependency of an asset version on another asset (with a version range), and the resolved graph node used at install time. Owned by DependencyResolutionService (Compatibility & Dependencies).
Fields — AssetDependencyId (identity), AssetVersionId, DependsOnAssetId, VersionRange, Scope (Required, Optional), ResolvedVersion, ResolutionStatus, TenantId.
Entities — ResolvedDependencyNode (within a resolution result).
Value Objects — VersionRange, DependencyScope, ResolutionStatus.
Invariants — VersionRange must be a valid semantic-version range; resolution must produce a single ResolvedVersion satisfying all ranges or fail with a conflict; optional dependencies may remain unresolved without failing the graph.
Domain Events — DependenciesResolved, DependencyConflictDetected.
Repository — AssetDependencyRepository.
Persistence — Azure SQL / PostgreSQL via NHibernate; resolved graphs cached in Redis keyed by (assetId, version, targetHash).
AssetCompatibility¶
Purpose — The verdict of evaluating an asset version against a target environment (runtime, project, installed assets). Owned by AssetCompatibilityService (Compatibility & Dependencies).
Fields — AssetCompatibilityId (identity), AssetVersionId, TargetDescriptor, Verdict (Compatible, Incompatible, CompatibleWithWarnings), Findings, EvaluatedAt, EvaluatorVersion, TenantId.
Entities — CompatibilityFinding.
Value Objects — TargetDescriptor (runtime, projectId, installed assets), CompatibilityVerdict, Finding (kind, severity, message).
Invariants — A verdict references an existing released AssetVersion; an Incompatible verdict must carry at least one blocking finding; verdicts are cached and invalidated when the version or evaluator changes.
Domain Events — CompatibilityEvaluated.
Repository — AssetCompatibilityRepository.
Persistence — Azure SQL / PostgreSQL via NHibernate; verdicts cached in Redis with version-keyed invalidation.
AssetInstallation¶
Purpose — A record of installing an asset version into a target project/tenant, with provenance, status, and rollback information. Owned by AssetInstallationService (Installation).
Fields — InstallationId (identity), AssetId, AssetVersionId, Target (projectId, environment), Status (Requested, Resolving, Evaluating, LicenseCheck, Applying, Installed, Failed, RolledBack), ResolvedDependencies, LicenseId, RequestedBy, InstalledAt, RollbackToken, TenantId.
Entities — InstallationStep, InstalledArtifactRef.
Value Objects — InstallationTarget, InstallationStatus, RollbackToken.
Invariants — Installation cannot reach Applying without a Compatible/CompatibleWithWarnings verdict, resolved required dependencies, and a valid License for paid assets; a failed installation must roll back to a clean state; each (assetId, version, target) has at most one active installation.
Domain Events — AssetInstalled, AssetInstallationFailed.
Repository — AssetInstallationRepository.
Persistence — Azure SQL / PostgreSQL via NHibernate; saga state persisted alongside the aggregate. See the state machine in Workflows.
Publisher¶
Purpose — An identity that publishes assets, with verification status, trust tier, and portfolio. Owned by PublisherPortalService (Publisher).
Fields — PublisherId (identity), DisplayName, Kind (Internal, Partner, Community), VerificationStatus (Unverified, Pending, Verified, Suspended), TrustTier (T0–T3), ContactEmail, SigningKeyRef, ReputationScore, TenantId, CreatedAt.
Entities — PublisherContact, PublisherSigningKey.
Value Objects — TrustTier, VerificationStatus, ReputationScore, SigningKeyRef.
Invariants — Only a Verified publisher may release signed versions; SigningKeyRef must reference a key in the secret store; a Suspended publisher's assets cannot be installed; trust tier governs whether quality gates can be auto-approved.
Domain Events — PublisherRegistered, PublisherVerified, PublisherSuspended.
Repository — PublisherRepository.
Persistence — Azure SQL / PostgreSQL via NHibernate; signing keys referenced (not stored) via Azure Key Vault. See Security.
License¶
Purpose — A tenant's entitlement to install and use an asset under a pricing plan. Owned by LicenseService (Commerce); integrates ConnectSoft.Extensions.Saas.Billing through an anti-corruption layer.
Fields — LicenseId (identity), AssetId, TenantId, PricingPlanId, EntitlementRef, Status (Active, Expired, Revoked), GrantedAt, ExpiresAt, Seats, BillingSubscriptionRef.
Entities — LicenseSeatAssignment.
Value Objects — EntitlementRef, LicenseStatus, SeatCount, BillingSubscriptionRef.
Invariants — A license is bound to a single (assetId, tenantId); an Active license requires a valid billing entitlement; seat assignments cannot exceed Seats; an expired or revoked license blocks new installs but does not retroactively uninstall.
Domain Events — LicenseGranted, LicenseRevoked, LicenseExpired.
Repository — LicenseRepository.
Persistence — Azure SQL / PostgreSQL via NHibernate; entitlement truth federated from billing via the ACL.
PricingPlan¶
Purpose — The pricing definition attached to an asset (free, flat, per-seat, usage-based). Owned by PricingService (Commerce).
Fields — PricingPlanId (identity), AssetId, Name, Model (Free, Flat, PerSeat, Usage), Currency, Amount, MeteredDimensions, BillingPeriod, Status (Draft, Published, Retired), TenantScope, CreatedAt.
Entities — PriceTier, MeteredDimension.
Value Objects — PricingModel, Money, BillingPeriod, MeteredDimension.
Invariants — A published plan is immutable (changes create a new plan version); Usage plans must declare at least one MeteredDimension; Currency and Amount are consistent with Model; only one Published plan is the default per asset.
Domain Events — PricingPlanPublished, PriceQuoted, PricingPlanRetired.
Repository — PricingPlanRepository.
Persistence — Azure SQL / PostgreSQL via NHibernate; metering dimensions reconciled with ConnectSoft.Extensions.Saas.Metering.
AssetReview¶
Purpose — A user's rating and review of an asset, feeding ranking and publisher reputation. Owned by ReviewRatingService (Reviews).
Fields — AssetReviewId (identity), AssetId, AssetVersionId, ReviewerId, Rating (1–5), Title, Body, Status (Published, Flagged, Removed), HelpfulCount, CreatedAt, TenantId.
Entities — ReviewVote, ReviewModerationNote.
Value Objects — Rating, ReviewStatus.
Invariants — A reviewer may hold at most one active review per asset; Rating is between 1 and 5; only a reviewer who has installed the asset (verified install) may publish a review; removed reviews are excluded from aggregate rating.
Domain Events — AssetReviewed, RatingAggregated, ReviewFlagged.
Repository — AssetReviewRepository.
Persistence — Azure SQL / PostgreSQL via NHibernate; aggregate ratings projected onto MarketplaceAsset via AssetReviewed.
Consistency and ownership¶
Each aggregate is a transactional consistency boundary owned by exactly one service; cross-aggregate consistency is eventual, achieved through domain/integration events. For example, AssetReviewed updates AssetReview transactionally, then projects an aggregate rating onto MarketplaceAsset asynchronously. This keeps publishing, commerce, and installation independently scalable while preserving end-to-end traceability through the event envelope.
Continue to Data Model, Storage, and Workflows.