Skip to content
CAI
Software that uses CAICheck a score

SaaStacked/saastack

53.1

Adequate · 21 September 2026

88.6k

lines of production code

C#

with TypeScript

4

measurements over time

CAI band scale
CAI trend line
CAI lens gauges

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.