SaaStacked/saastack
53.1
Adequate · 21 September 2026
88.6k
lines of production code
C#
with TypeScript
4
measurements over time
What this system is
This system is a .NET 8-based SaaS platform framework built on Domain-Driven Design principles, providing foundational infrastructure for multi-tenant applications. It implements event-sourcing capabilities, hierarchical authorization, and robust validation, while offering a booking service for managing car reservations and ancillary services like email and SMS delivery. The codebase includes extensive tooling for API scaffolding, testing, and external service simulation to support rapid development and reliable integration.
Features
Added fake external service adapters for testing
The \Infrastructure.External.TestingOnly\ project now includes example adapters for a fake feature flag provider, a fake OAuth2 service, and a fake SSO authentication provider. These components allow developers to simulate third-party integrations during testing, with the feature flag client always returning enabled flags and the OAuth2/SSO services providing hard-coded tokens and user information.
src/ExternalAdapters/Infrastructure.External.TestingOnly · high confidence
Added in-memory and local JSON file persistence stores for testing
The \Infrastructure.External.Persistence.TestingOnly\ package now provides concrete implementations of the persistence interfaces (\IBlobStore\, \IDataStore\, \IEventStore\, \IMessageBusStore\, and \IQueueStore\) using two backends: an in-process in-memory store (\InProcessInMemStore\) and a local machine JSON file store (\LocalMachineJsonFileStore\). These implementations allow developers to run applications and tests without external infrastructure dependencies, with the file store adding concurrency controls for event streams and the queue store supporting delayed message visibility.
src/ExternalAdapters/Infrastructure.External.Persistence.TestingOnly · high confidence
Added message bus and queue ID factories with validation resources
The Domain.Common framework now includes factories for generating unique identifiers for message bus topics and message queues, ensuring names are validated against defined constraints (such as maximum prefix length) and formatted consistently. This change also introduces localized resource strings to provide clear error messages when topic or queue names are invalid, supporting better debugging and user feedback for messaging configuration issues.
src/Framework/Domain/Domain.Common · high confidence
Added validation framework and localized error messages
The validation layer in the domain interfaces now includes a new \Validation\ class that supports both regular expression patterns and custom predicate functions, along with length constraints. A comprehensive set of pre-defined validators has been added for common data types, including email addresses, URLs, phone numbers, passwords (with loose and strict policies), and identifiers. Additionally, localized error messages for these validation failures are now available through the new \CommonValidationResources\ resource files, ensuring users receive clear, translated feedback when input is invalid.
src/Framework/Domain/Domain.Interfaces/Validations · high confidence
Addition of common framework utilities and domain models
The src/Framework/Common directory now includes a comprehensive set of foundational libraries, introducing domain models for CountryCodes, CurrencyCodes, and DatacenterLocations, alongside utility classes for CallContext and configuration settings. The update also adds a suite of extension methods for collections, dates, dictionaries, and enums, as well as a custom error handling system (Error struct) and JetBrains annotations to improve code analysis and developer experience.
src/Framework/Common · high confidence
Initial SaaStack .NET 8 solution structure and build configuration
The \src\ directory now contains the foundational structure for the SaaStack .NET 8 codebase template. This includes the \SaaStack.sln\ solution file defining the project hierarchy (Framework, Subdomains, Hosts, etc.), \global.json\ pinning the SDK to version 8.0.413, and \Directory.Build.props\ configuring shared build properties such as implicit usings, nullable reference types, and Roslyn analyzer targets. Additionally, \.gitattributes\ and \.gitignore\ files are added to standardize line endings and exclude IDE/build artifacts.
src · high confidence
Introduce car booking capability with reservation, cancellation, and search operations
This change adds the core Bookings subdomain, enabling users to reserve a car for a specific time window, cancel an existing reservation (which releases the car's availability), and search for all bookings within an organization. The implementation includes the application service layer for orchestrating these workflows, a domain model enforcing booking invariants (such as minimum/maximum duration and required car assignment), persistence interfaces for storing and retrieving booking data, and API request validators to ensure input correctness. Unit and integration tests are provided to verify the booking lifecycle and API contract.
src/Subdomains/Core · high confidence
Introduces hierarchical authorization model for platform and tenant roles/features
This change adds the core domain interfaces and implementations for a new hierarchical authorization system in the \Domain.Interfaces.Authorization\ namespace. It introduces \HierarchicalLevelBase\, \FeatureLevel\, and \RoleLevel\ classes that support parent-child relationships, where a parent automatically grants access to child levels. It also defines static registries for platform-scoped and tenant-scoped roles and features (e.g., \PlatformRoles\, \TenantFeatures\), including lookup methods like \FindRoleByName\ and \IsPlatformAssignableRole\. This provides the foundational abstractions for managing access control hierarchies across the platform.
src/Framework/Domain/Domain.Interfaces/Authorization · high confidence
Introduction of EntityBase with invariant validation and event handling
The domain framework now includes an EntityBase class that standardizes entity behavior by handling domain event propagation, automatic invariant validation upon state changes, and state persistence through dehydration and rehydration methods.
src/Framework/Domain/Domain.Common/Entities · high confidence
Introduction of core Domain-Driven Design abstractions and event-sourcing infrastructure
This change introduces the foundational building blocks for the domain layer, including the \AggregateRootBase\ implementation, \DomainEvent\ and \TombstoneDomainEvent\ classes, and the \EventStream\ value object for versioning. It also defines the necessary interfaces in \Domain.Interfaces.Entities\ (such as \IAggregateRoot\, \IEventingAggregateRoot\, and \IDomainEvent\) to support event sourcing, allowing aggregates to produce and consume change events while managing their state through hydration and dehydration.
Domain, src/Framework/Domain/Domain.Interfaces/Entities · high confidence
Introduction of domain interfaces and CSRF protection middleware
This change introduces several new domain interfaces within the \Domain.Interfaces\ project, including \IDependencyContainer\ for service resolution, \ITenantSettingService\ for encrypted tenant configuration, and a hierarchy of value object interfaces (\IValueObject\, \ISingleValueObject\, \IDehyatableValueObject\) along with a \SkipImmutabilityCheckAttribute\ to support strict immutability patterns. Additionally, it adds \HierarchicalLevelExtensions\ to manage the normalization and denormalization of hierarchical level sets. On the infrastructure side, a new \CSRFMiddleware\ is implemented in \Infrastructure.Web.Hosting.Common\ to protect against Cross-Site Request Forgery attacks by verifying CSRF cookies and headers against trusted origins, while ignoring specific HTTP methods and routes.
(repo-wide) · high confidence
New DDD value object base classes with comparison, equality, and serialization support
The framework introduces new base classes for Domain-Driven Design value objects: \ValueObjectBase\ and \SingleValueObjectBase\. These classes provide built-in support for equality checks (including dictionary-based value objects), comparison operators (\>, \<, \>=, \<=), and serialization via JSON-based dehydration/rehydration. Utility extensions for identifiers and value object checks are also added.
src/Framework/Domain/Domain.Common/ValueObjects · high confidence
New Web API assembly visitor for service operation discovery
The Tools component now includes a new WebApiAssemblyVisitor that scans assemblies to identify and register service operations. It detects classes implementing IWebApiService, extracts their methods based on request DTOs derived from IWebRequest, and processes route and authorization attributes to generate API service registrations.
Tools · high confidence
New domain extension methods for event serialization, hydration, validation, and optional types
The framework introduces four new extension classes in the Domain.Common.Extensions namespace to support core domain operations. DomainEventExtensions provides methods to serialize domain events to and from JSON and to wrap them into versioned EventSourcedChangeEvent objects for persistence. HydrationPropertiesExtensions adds utilities to safely retrieve typed values from hydration property bags, handling optional types and default values. ObjectExtensions introduces parameter validation helpers that check values against validation rules and return or throw errors when preconditions are violated. Finally, OptionalExtensions offers conversion methods to transform Optional strings into nullable types or other optional types using custom converters.
src/Framework/Domain/Domain.Common/Extensions · high confidence
New domain interfaces and constants for identity, hydration, and OAuth2
The Domain.Interfaces assembly now includes several new abstractions and constants to support domain logic and security. CallerConstants defines specific user IDs for anonymous, external webhook, maintenance, and service client accounts, along with helper methods to identify them. HydrationProperties and related interfaces (IRehydratableObject, IDomainFactory, and factory delegates) provide a structured way to rehydrate domain objects from persisted state. Additionally, OAuth2Constants and OpenIdConnectConstants centralize standard OAuth2 and OpenID Connect values such as grant types, scopes, endpoints, and error codes, while new interfaces (IMessageBusTopicMessageIdFactory, IMessageQueueMessageIdFactory) define factories for generating message identifiers.
src/Framework/Domain/Domain.Interfaces · high confidence
New domain models for bookings, cars, and ancillary services
This change introduces the core domain entities for the Bookings, Cars, and Ancillary subdomains. For bookings, it adds the BookingRoot aggregate (managing reservations, trips, and cancellations) and the Trip entity. For cars, it adds the CarRoot aggregate (handling manufacturer, ownership, registration, and unavailability slots) along with supporting value objects like LicensePlate, Jurisdiction, and TimeSlot. For ancillary services, it adds roots for tracking email and SMS delivery attempts and statuses, as well as an AuditRoot for recording system events.
Subdomains · high confidence
New identifier factory abstractions for domain entities
The framework now includes a new \IIdentifierFactory\ interface and several concrete implementations within the \Domain.Common.Identity\ namespace to standardize how entity identifiers are created and validated. This includes \AggregateNamePrefixedIdentifierFactory\ for generating prefixed, base64-encoded GUIDs, \FixedIdentifierFactory\ for returning a static identifier, and \EmptyIdentifierFactory\ for generating empty identifiers, providing a consistent abstraction for identifier management across the domain layer.
src/Framework/Domain/Domain.Common/Identity · high confidence
New infrastructure components and unit tests for domain rehydration and encryption
This change introduces the \DomainFactory\ class, which enables the automatic registration and rehydration of domain aggregates, entities, and value objects from assemblies, supported by a comprehensive suite of unit tests in \DomainFactorySpec.cs\. It also adds an \AesEncryptionService\ for data encryption/decryption, a \TenantSettingService\ to manage tenant-specific encrypted settings, and a set of 'NoOp' reporter stubs (audit, crash, metric, usage) to allow recording services to be disabled in non-production environments. Additionally, it includes \RecorderOptions\ to configure these reporting behaviors per environment and \ConsoleConstants\ to handle colored output safely when console output is redirected.
src/Framework/Infrastructure · high confidence
New source generators and analyzer tooling for API and authorization scaffolding
This change introduces new tooling components within the framework to automate code generation and static analysis. It adds a \FeatureFlagGenerator\ that converts \.resx\ resource files into strongly-typed \Flag\ class instances, and an \AuthorizationAttributeGenerator\ that produces \Roles\ and \Features\ enums along with mapping functions based on \PlatformRoles\ and \TenantFeatures\. Additionally, a \MinimalApiGenerator\ is provided to scaffold route registrations for Web API services, supported by a new \Tools.Analyzers.Common\ library containing constants and extension methods for diagnostic reporting and syntax analysis. Unit tests are included to verify the output of these generators.
src/Framework/Tools · high confidence
Shared persistence abstractions and message models
This change introduces a new shared persistence layer within the Subdomains/Shared area, defining the core interfaces and data models for asynchronous communication and delivery services. It adds repository interfaces for various message queues (email, SMS, audit, provisioning, usage, and domain events) alongside service contracts for email and SMS delivery, provisioning notifications, and usage tracking. The diff also includes the corresponding read-model classes for these messages, extension methods for handling queued messages and converting domain events for bus transport, and resource models for identity, organizations, and subscriptions, establishing the foundational contracts for the system's background processing and notification infrastructure.
src/Subdomains/Shared · high confidence
Test coverage
Added integration testing infrastructure for Web API; Added integration testing infrastructure for the Website component; Added integration tests and health/statistics endpoints for ApiHost1; Added stub implementations for integration testing; Added test constants for code analysis configuration; Added unit tests and test utilities for domain authorization and hydration; Added unit tests for Domain.Common framework components; Added unit tests for FakeSSOAuthenticationProvider; Added unit tests for application framework caller context and extension logic; Added unit tests for common framework utilities; Unit tests added for AncillaryApplication messaging and feature flags.
Dependencies
Framework projects migrated to .NET 8 and updated dependencies
The .NET project files in the Framework and ExternalAdapters directories have been updated to target .NET 8.0. This change includes upgrading core Microsoft.Extensions packages (such as DependencyInjection, Logging, and Configuration) to version 8.0.x, updating authentication libraries (JwtBearer, IdentityModel) to 8.14.0, and refreshing third-party dependencies like FluentValidation, Polly, and Swashbuckle.AspNetCore. Additionally, the test infrastructure has been standardized with Microsoft.NET.Test.Sdk version 18.4.0 across multiple unit test projects.
(dependencies) · high confidence
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
How this codebase got here
Score
- CAI 54 → 53 (-1.2)
- Rubric changed (rubric-2026.08.19 → rubric-2026.09.15) — scores are not directly comparable.
Lenses
- Code Health 86 → 72 (-13.6)
- Architecture 66 → 69 (+2.4)
- Maturity 66 → 71 (+4.6)
- Readiness 44 → 43 (-1.0)
- Security 68 → 65 (-3.4)
- Domain Modelling 73 → 69 (-3.7)
- Accessibility 61 → 58 (-3.2)
- Performance 60 → 60 (+0.0)
Resolved (87)
- Bounded contexts not declared
- Change coupling: NoOpEmailDeliveryService.cs ↔ NoOpUsageDeliveryService.cs (src/Subdomains/Generic/AncillaryInfrastructure/ApplicationServices/NoOpEmailDeliveryService.cs)
- Context/problem and consequences/trade-offs are absent; only 'How they work' and a partial test section appear (docs/design-principles/0210-javascript-forms.md)
- Coverage not measured — analyzer environment
- Critical CVE: [GHSA redacted] (src/Hosts/WebsiteHost/ClientApp/package-lock.json)
- Critical CVE: [GHSA redacted] (src/Hosts/WebsiteHost/ClientApp/package-lock.json)
- Duplicated block (10 lines × 2) (src/Framework/Infrastructure/Infrastructure.Persistence.Common/MessageBusTopicStore.cs)
- Duplicated block (10 lines × 2) (src/Subdomains/Generic/IdentityDomain/AuthTokensRoot.cs)
- Duplicated block (10 lines × 2) (src/Subdomains/Generic/OrganizationsInfrastructure/Api/Organizations/AssignRolesToOrganizationRequestValidator.cs)
- Duplicated block (11 lines × 2) (src/Hosts/ApiHost1/Api/TestingOnly/ValidationsValidatedGetTestingOnlyRequestValidator.cs)
- Duplicated block (11 lines × 2) (src/Subdomains/Generic/AncillaryInfrastructure/Persistence/ReadModels/EmailDeliveryProjection.cs)
- Duplicated block (11 lines × 2) (src/Subdomains/Generic/IdentityInfrastructure/Api/MFA/AssociatePasswordMfaAuthenticatorForCallerRequestValidator.cs)
- Duplicated block (11 lines × 2) (src/Subdomains/Generic/IdentityInfrastructure/Api/MFA/ConfirmPasswordMfaAuthenticatorForCallerRequestValidator.cs)
- Duplicated block (12 lines × 2) (src/ExternalAdapters/Infrastructure.External.Persistence.TestingOnly/ApplicationServices/InProcessInMemStore.IEventStore.cs)
- Duplicated block (14 lines × 2) (src/Framework/Infrastructure/Infrastructure.Web.Api.Common/RequestTenantDetective.cs)
- Duplicated block (14 lines × 2) (src/Subdomains/Core/BookingsDomain/BookingRoot.cs)
- Duplicated block (14 lines × 2) (src/Subdomains/Core/CarsApplication/CarsApplication.cs)
- Duplicated block (14 lines × 2) (src/Subdomains/Generic/OrganizationsApplication/OrganizationsApplication.DomainEventHandlers.cs)
- Duplicated block (14 lines × 3) (src/Subdomains/Generic/OrganizationsApplication/OrganizationsApplication.SubscriptionOwningEntity.cs)
- Duplicated block (15 lines × 2) (src/Subdomains/Generic/AncillaryDomain/EmailDeliveryRoot.cs)
- …and 67 more
New (360)
- ActionCommand.useActionCommand (cognitive 28) (src/Hosts/WebsiteHost/ClientApp/src/framework/actions/ActionCommand.ts)
- ActionCommand.useActionCommand (cyclomatic 21) (src/Hosts/WebsiteHost/ClientApp/src/framework/actions/ActionCommand.ts)
- BrowserRecorder.trace (cognitive 25) (src/Hosts/WebsiteHost/ClientApp/src/framework/recorders/browserRecorder.ts)
- Context/problem and consequences/trade-offs are absent from the visible text (only design principles/practices are listed) (docs/design-principles/0020-api-framework.md)
- Context/problem is thin: only one sentence ('## How they work - TBD') in the body plus no consequences/trade-offs (docs/design-principles/0210-javascript-forms.md)
- CoverageExclusion (src/ExternalAdapters/Infrastructure.External.Persistence.TestingOnly/ApplicationServices/InProcessInMemStore.cs)
- CoverageExclusion (src/ExternalAdapters/Infrastructure.External.Persistence.TestingOnly/ApplicationServices/LocalMachineJsonFileStore.cs)
- CoverageExclusion (src/Framework/Common/Recording/NoOpRecorder.cs)
- CoverageExclusion (src/Framework/Infrastructure/Infrastructure.Common/Recording/NoOpAuditReporter.cs)
- CoverageExclusion (src/Framework/Infrastructure/Infrastructure.Common/Recording/NoOpCrashReporter.cs)
- CoverageExclusion (src/Framework/Infrastructure/Infrastructure.Common/Recording/NoOpMetricReporter.cs)
- CoverageExclusion (src/Framework/Infrastructure/Infrastructure.Common/Recording/NoOpUsageReporter.cs)
- CoverageExclusion (src/Framework/Infrastructure/Infrastructure.Persistence.Common/ApplicationServices/NoOpStore.cs)
- CoverageExclusion (src/Framework/Infrastructure/Infrastructure.Web.Api.Common/Clients/ApiServiceClient.cs)
- CoverageExclusion (src/Framework/Infrastructure/Infrastructure.Web.Api.Common/Clients/InterHostServiceClient.cs)
- CoverageExclusion (src/Framework/Infrastructure/Infrastructure.Web.Api.Common/Clients/JsonClient.cs)
- CoverageExclusion (src/Framework/Infrastructure/Infrastructure.Web.Api.Common/Extensions/HandlerExtensions.cs)
- CoverageExclusion (src/Framework/Infrastructure/Infrastructure.Web.Api.Common/Pipeline/XmlHttpResult.cs)
- Critical CVE: [GHSA redacted] (src/Hosts/WebsiteHost/ClientApp/package-lock.json)
- Critical CVE: [GHSA redacted] (src/Hosts/WebsiteHost/ClientApp/package-lock.json)
- …and 340 more
Changes since last survey
- 3 commits — 0 feature/other, 3 fixes
By area
- src/Subdomains — 2 commits
- src/Hosts — 1 commit
Notable commits
- fix: fix: Added UnTenantedGetRequest/TenantedGetRequest
- fix: fix: Added the ability to refresh cached responses from actions, and updated cachekeys
- fix: fix: Fix issue with SearchOptions plus custom Ordering
API surface
- Unchanged — 1 HTTP endpoints
Architecture
- Unchanged — 3 containers · 4 contexts · 4 edges
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
Survey your own repository
SaaStacked/saastack was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.
About this page
- The score is its most recent published measurement, taken on 21 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
- Measured at commit b6001f05e7b3b15cfe1d7aa3e205cc04a9d5cef0 — the exact code this score is about.
- Scored under rubric-2026.09.15 — the same rubric and the same method as every other entry in this index.
- Measured by watchdog.canine.dev using codehealth-analyzer preprod-28e75b8e3254.