Skip to content
CAI
Software that uses CAICheck a score

DavidEggenberger/CrispyCollab

40.0

Weak · 21 September 2026

4.9k

lines of production code

C#

primary language

4

measurements over time

CAI band scale
CAI trend line
CAI lens gauges

What this system is

CrispyCollab is a multi-tenant web application built on .NET 9 that manages user identity, subscription billing, and real-time channel-based messaging. It provides a modular architecture where the TenantIdentity module handles authentication and tenant membership, while the Subscriptions module integrates with Stripe for payment processing. The system also supports collaborative communication through a Channels module that enables users to create and manage messaging channels with real-time updates.

How it got here

2022–2023 — Initial project structure and core modules

15 changes.

The project established a modular architecture for CrispyCollab, introducing foundational modules for tenant identity, channels, and landing pages. This period focused on setting up the solution structure, implementing Blazor components, and configuring Entity Framework Core contexts for data access. Additionally, shared kernel interfaces and multi-tenant authorization policies were defined to support the new modular design.

2024–2025 — Modular architecture and domain implementation

29 changes.

This period focused on establishing the application's modular architecture, introducing shared building blocks, and implementing core features for tenant identity, channels, and subscriptions. The work involved setting up the server and client entry points, configuring dependency injection, and integrating third-party services like Stripe and SignalR.

Features

Add Blazor Server landing pages and modals

Introduced a set of Blazor Server components for the landing pages module, including a main landing page, an about page, a pricing page, and sign-in/sign-up modals. The module registers the Blazored Modal service and provides the layout and routing infrastructure for these new server-side rendered pages.

Source/Modules/LandingPages · high confidence

Add Configuration infrastructure for options binding and validation

Introduces a new configuration subsystem in the Shared layer, providing a base ConfigurationObject class, an abstract ConfigurationObjectValidator for validating configuration options, and a Registrator helper to bind configuration sections to objects and register them with the dependency injection container.

Source/Shared/Features/Configuration · high confidence

Add client-side authentication and layout scaffolding

The application now includes a complete set of client-side building blocks for authentication and UI structure. This introduces an antiforgery token service and Razor component to handle CSRF protection, alongside an HTTP message handler that automatically attaches the token to outgoing requests. A new authentication state provider manages user sessions, caching user claims and handling sign-in/sign-out navigation. The UI is supported by new layout components (BaseLayout, MainLayout, TopicLayout) that define the application's grid structure, navigation bar, and sidebar menu. Additionally, cascading value wrappers are added to inject authentication state and tenant context into child components.

Source/Web/Client/BuildingBlocks · high confidence

Add configuration model and validator for tenant identity providers

A new configuration class, TenantIdentityConfiguration, has been introduced to hold client IDs and secrets for Google, Microsoft, and LinkedIn identity providers. Alongside it, a validator ensures that the Google and Microsoft client IDs and secrets are not empty, failing validation if any of these required fields are missing.

Source/Modules/TenantIdentity/Features/Modules.TenantIdentity.Features/Infrastructure/Configuration · high confidence

Added Blazor components for login display and authentication redirect

The application now includes new Blazor components for the client-side identity module. A LoginDisplayComponent has been added to handle the display of the login interface, while a RedirectToLoginComponent has been introduced to automatically redirect unauthenticated users to the login page, preserving the current URL as a return parameter. These components are part of the broader tenant identity feature, specifically providing the client-side UI and navigation logic for the login flow.

Source/Modules/TenantIdentity/Web/Client · medium confidence

Added EF Core database context for Channels module

A new ChannelsDbContext class has been introduced in the Channels module's infrastructure layer, establishing the Entity Framework Core mapping for the Channel entity. This change provides the data access layer for the Channels feature, enabling database interactions for channel-related data.

Source/Modules/Channels/Features/Infrastructure · high confidence

Added HTTP client and model validation services

Introduced a new HttpClientService for making HTTP requests with automatic JSON deserialization and error handling, alongside a new model validation system comprising an IValidationService interface, a ValidationService implementation using FluentValidation, and a ValidationServiceResult class to report validation status and errors.

Source/Shared/Kernel/BuildingBlocks/Services · high confidence

Added Razor page templates for Blazor hosting

The server-side Pages directory now includes \_Host.cshtml and \_ViewImports.cshtml. The \_Host.cshtml template conditionally renders the ClientApp as a WebAssembly component for authenticated users, or the LandingPagesApp as a Server-rendered component for unauthenticated users, establishing the primary entry point for the application's UI. The \_ViewImports.cshtml configures the necessary namespaces and tag helpers for these views.

Source/Web/Server/Pages · medium confidence

Added SignalR-based real-time notification hub

Introduced a new SignalR hub (NotificationHub) and associated service (NotificationHubService) to enable real-time push notifications to authenticated users. The implementation includes a custom UserIdProvider to map SignalR connections to user identities, and a Registrator to wire up the hub endpoints and dependencies.

Source/Shared/Features/SignalR · high confidence

Added Stripe checkout and success controllers

Introduced new ASP.NET Core controllers to handle Stripe payment flows. The StripeSessionController manages redirection to Stripe's checkout and billing portal, while the StripeSuccessController processes post-payment success callbacks, including user sign-in and redirection. These controllers implement the server-side endpoints for subscription management and payment confirmation.

Source/Modules/Subscriptions/Web/Server/Controllers · high confidence

Added Stripe webhook handler for subscription lifecycle events

A new StripeWebhook controller has been added to handle incoming Stripe webhooks. It processes CheckoutSessionCompleted, InvoicePaid, and InvoicePaymentFailed events to update subscription states and billing periods via the command dispatcher.

Source/Modules/Subscriptions/Web/Server/WebHooks · high confidence

Added SubscriptionsModuleStartup for DI and configuration

A new SubscriptionsModuleStartup class has been added to the Web/Server module. It registers the SubscriptionsDbContext and SubscriptionsConfiguration, and sets the Stripe API key from configuration, enabling dependency injection and configuration for the subscriptions feature.

Source/Modules/Subscriptions/Web/Server · medium confidence

Added core domain and execution context interfaces

Introduced new building block interfaces and domain enums to support the application's multi-tenant architecture. This includes the IExecutionContext interface for managing user, tenant, and hosting environment context, the IIntegrationEvent marker interface for event-driven communication, and new enums for SubscriptionPlanType (Free, Professional, Enterprise) and TenantRole (Admin, User).

Source/Shared/Kernel/BuildingBlocks · high confidence

Added domain base classes for entities and value objects

Introduced new base classes for domain modeling: an abstract Entity class providing common properties such as Id, UserId, TenantId, and audit timestamps, along with a DomainException base class and specific exception types like InvalidEntityDeleteException. Additionally, a ValueObject base class was added to enforce value-based equality and hash code generation for immutable domain types.

Source/Shared/Features/Domain · high confidence

Added initial database migration and DbUp integration

The application now uses DbUp to manage database schema changes. A new migration script (0001\_TenantIdentity\_Initial.sql) creates the initial set of tables for identity management (AspNetRoles, AspNetUsers, etc.) and tenant-related data. The Registrator class registers the DbUp migration process, which ensures the database is up-to-date with the latest schema on startup.

Source/Shared/Features/EFCore/DbUp · high confidence

Added new client-side pages for Channels, Dashboard, and Topic management

The application now includes new Blazor components for the Channels, Dashboard, and Topic areas. The Channels page allows users to view and create channels via the /channels route, fetching data from the /channel API endpoint. The Dashboard page, accessible at the root / route, retrieves team information from the /api/Team/all endpoint. The Topic page at /Topics provides a layout for topic management, currently featuring a placeholder for a diagramming interface. Each page is accompanied by its corresponding C\# code-behind and CSS styling files.

Source/Web/Client/Pages · high confidence

Added shared error handling infrastructure

Introduced a new \Shared.Kernel.Errors\ namespace containing a static \Errors\ helper class and corresponding exception classes (\NotFoundException\, \UnAuthorizedException\). This provides a centralized way to generate standard not-found and unauthorized exceptions for entities, simplifying error handling across the application.

Source/Shared/Kernel/Errors · high confidence

Added static assets for UI, styling, and client-side logic

The application now includes a set of new static files in the wwwroot directory to support the user interface and client-side behavior. This includes SVG icons for the home and settings menus, CSS stylesheets for modals, loading screens, and general layout defaults, as well as JavaScript modules for handling anti-forgery tokens and managing the navigation menu and loading screen visibility.

Source/Web/Server/wwwroot · high confidence

Centralized endpoint and configuration constants

The application now uses dedicated constant classes to define API paths and configuration values, including subscription endpoints for Stripe, tenant identity routes, a notification hub identifier, and a Tailwind CSS output path. This change consolidates these values into a shared constants layer, making it easier to manage and update these paths across the codebase.

Source/Shared/Kernel/Constants · high confidence

Configures tenant identity authentication and social login providers

The module's startup logic now registers authentication services for Google, LinkedIn, and Microsoft accounts, along with standard cookie-based authentication and ASP.NET Core Identity. This establishes the foundation for user sign-in and social authentication within the tenant identity module.

Source/Modules/TenantIdentity/Web/Server · high confidence

Initial client application bootstrap and routing setup

The client application now includes a new entry point (Program.cs) that configures essential services including HTTP clients, authentication state providers, and Blazor modal support. The main App component (ClientApp.razor) has been added to define the application's routing structure, integrating authorization checks, tenant context, and error handling wrappers. Global using directives and imports have been established to streamline namespace usage across the client project.

Source/Web/Client · high confidence

Initial implementation of Channels module for Web client and server

Added the foundational structure for the Channels module, including a new Razor component (ChannelComponent) for the client-side UI, a corresponding CSS file, and server-side infrastructure. The server includes a startup configuration (ChannelsModuleStartup) that registers the Channels DbContext and controllers, and a ChannelsController exposing endpoints for retrieving, creating, updating, and deleting channels, alongside a CreateChannelModal component for user input.

Source/Modules/Channels/Web · high confidence

Initial implementation of Stripe subscription management

Added the foundational domain models, database schema, and application logic for managing Stripe customers and subscriptions. This includes the \StripeCustomer\ and \StripeSubscription\ entities, along with the \SubscriptionsDbContext\ and initial migration to persist subscription data. The update also introduces commands and queries for creating checkout and billing portal sessions, handling subscription status updates (active, trialing, paused), and configuring subscription plans with trial periods.

Source/Modules/Subscriptions/Features/DomainFeatures, Source/Modules/Subscriptions/Features/Infrastructure · high confidence

Initial project structure and configuration for CrispyCollab

The repository is initialized with a new solution structure for the CrispyCollab application, defining a modular architecture with separate projects for Web, Modules (including TenantIdentity, Subscriptions, Channels, and LandingPages), Shared components, and Tests. The setup includes a Docker Compose configuration to provision a SQL Server instance for local development, alongside standard project files like the solution file (.sln) and .dockerignore.

(repo-wide) · high confidence

Introduce Tenant Identity server controllers

Added new ASP.NET Core controllers to handle tenant identity operations: ExternalLoginCallbackController for managing external login callbacks, IdentityOperationsController for user claims, tenant selection, and logout, TenantsController for CRUD operations on tenants and memberships, and an empty UserController. These controllers implement the web-facing API for tenant identity management.

Source/Modules/TenantIdentity/Web/Server/Controllers · high confidence

Introduce server-side building blocks for API versioning, security headers, and exception handling

The server's \BuildingBlocks\ module now provides a centralized registration and middleware pipeline for cross-cutting concerns. This includes configuring API versioning via headers, adding standard security headers (e.g., X-Frame-Options, X-Xss-Protection), setting up a global exception handler that returns structured ProblemDetails for 404, 401, and 500 errors, enabling HTTP logging, enforcing model validation with specific JSON/XML content types, and enabling response compression (Brotli/Gzip). These components are wired together in a new \Registrator\ that allows the application to enable these features with single calls.

Source/Web/Server/BuildingBlocks · high confidence

Introduced ASP.NET Core server application with modular architecture

The Web.Server project has been added, providing the main entry point and configuration for the server-side application. This includes a new Dockerfile for containerization, a Program.cs entry point using Serilog for logging, and a Startup.cs that configures controllers, Razor Pages, Blazor, and registers modular services for Channels, Landing Pages, Subscriptions, and Tenant Identity. Configuration files (appsettings.json) define logging levels, SQL Server connection strings, and external provider settings for subscriptions and tenant identity.

Source/Web/Server · high confidence

Introduced TenantIdentityDbContext for EF Core data access

Added a new Entity Framework Core DbContext, TenantIdentityDbContext, which manages the persistence of tenant-related entities such as Users, Tenants, TenantInvitations, TenantMemberships, and TenantSubscriptions. The context is configured to use SQL Server, applies default schema and entity configurations from the assembly, and provides specific query methods for retrieving tenant and user data.

Source/Modules/TenantIdentity/Features/Modules.TenantIdentity.Features/Infrastructure/EFCore · high confidence

Introduced TenantIdentityModule for feature registration

A new TenantIdentityModule class has been added to the TenantIdentity.Features module. This module implements the IModule interface, exposing the tenant identity configuration and database context, which allows the application to properly register and initialize the tenant identity feature during startup.

Source/Modules/TenantIdentity/Features/Modules.TenantIdentity.Features · high confidence

Introduced domain features for channel management and messaging

Added new domain features for the Channels module, including the ChannelsModule registration, the Channel and Message domain models, and a set of command and query handlers for creating, deleting, and modifying channels and messages. This includes specific handlers for AddMessageToChannel, ChangeChannelName, CreateChannel, DeleteChannel, DeleteMessageFromChannel, and queries for retrieving channels and messages.

Source/Modules/Channels/Features/DomainFeatures · high confidence

Introduces a new messaging infrastructure for commands, queries, and integration events

The application now includes a new messaging feature in the Shared module, providing a structured way to handle commands, queries, and integration events. This includes base classes for commands and queries, along with dedicated dispatchers (CommandDispatcher, QueryDispatcher, IntegrationEventDispatcher) and their corresponding interfaces. The system uses dependency injection to automatically register handlers for commands, queries, and integration events via a Registrator that scans assemblies for implementations of ICommandHandler, IQueryHandler, and IIntegrationEventHandler. This change adds new capabilities for managing message flow and event handling within the application.

Source/Shared/Features/Messaging · high confidence

New claims principal and string extension utilities

Added new extension methods for ClaimsPrincipal to retrieve user, tenant, and role claims, along with corresponding exception classes for missing or invalid claims. Also added a string extension to convert strings to Guids.

Source/Shared/Kernel/Extensions · high confidence

New shared kernel interfaces for entity modeling

Added four new interfaces in the Shared.Kernel.Interfaces namespace to standardize entity definitions: IAuditable (for tracking creation and update timestamps), IConcurrent (for optimistic concurrency via RowVersion), IIdentifiable (for unique IDs), and ITenantIdentifiable (for multi-tenancy). These interfaces provide a consistent contract for domain models across the application.

Source/Shared/Kernel/Interfaces · high confidence

New tenant and user domain features for identity management

The TenantIdentity module now includes a comprehensive set of domain features for managing tenants and users. This includes commands to add, remove, and update user roles within a tenant, as well as queries to retrieve tenant details, memberships, and user claims. The update also introduces the \ApplicationUser\ entity with tracking for open tabs and selected tenant, alongside new exception types for tenant membership errors.

Source/Modules/TenantIdentity/Features/Modules.TenantIdentity.Features/DomainFeatures · high confidence

Public API surface expanded with new DTOs and integration events

The public interfaces for the Channels, Subscriptions, and TenantIdentity modules have been updated to expose new data transfer objects and integration events. Specifically, the Channels module now exposes ChannelDTO and MessageDTO for channel data, while the TenantIdentity module introduces a broader set of DTOs for tenant and user management, including CreateTenantDTO, TenantDTO, TenantDetailDTO, TenantMembershipDTO, UserDTO, BFFUserInfoDTO, and ClaimValueDTO. Additionally, new integration events have been added: TenantCreatedIntegrationEvent and UserEmailUpdatedIntegrationEvent in the TenantIdentity module, and TenantSubscriptionPlanUpdatedIntegrationEvent in the Subscriptions module.

Source/Modules/Channels/Public, Source/Modules/Subscriptions/Public, Source/Modules/TenantIdentity/Public · high confidence

Behavioural changes

Added UserClaimsPrincipalFactory for custom claim generation

A new UserClaimsPrincipalFactory has been introduced to handle the creation of ClaimsPrincipal objects for users. This implementation leverages the existing IQueryDispatcher to fetch user claims asynchronously, allowing for dynamic claim population based on user data rather than static configuration.

Source/Modules/TenantIdentity/Features/Modules.TenantIdentity.Features/Infrastructure · medium confidence

Introduced SubscriptionsModule for dependency injection

A new SubscriptionsModule class has been added to the Subscriptions module, providing a central point for registering the subscription configuration and EF Core database context. This change enables the application to properly initialize and manage the subscription-related services and database connections.

Source/Modules/Subscriptions/Features · low confidence

Introduces foundational client-side components and infrastructure

The client application now includes a base component for shared injection of HTTP, validation, and navigation services, alongside a custom error boundary that suppresses error reporting in non-development environments. Additionally, the codebase adds scaffolding for diagramming features (user and contact node components, ports) and a default modal configuration for deletion workflows.

Source/Shared/Client · medium confidence

New server-side execution context and base controllers for request handling

The server layer now introduces a dedicated execution context that captures tenant, user, and authentication details from the HTTP context via a new middleware. This context is injected into new base classes—BaseController and ServerExecutionBase—which provide access to command, query, and integration event dispatchers, as well as validation services. This change restructures how server-side features access shared infrastructure, moving away from previous patterns (such as direct Redis dependencies) toward a more explicit dependency injection model for request-scoped data.

Source/Shared/Features/Server · medium confidence

New tenant-based authorization policies and role claims

The system now enforces tenant-scoped access control through new authorization policies and claim types. Users are authenticated via tenant-specific roles (User, Admin) and subscription plans (Free, Professional, Enterprise), with dedicated attributes (\[AuthorizeTenantAdminAttribute\], \[AuthorizeTenantUserAttribute\]) and a DI registration that configures policies for tenant members, admins, and subscription tiers. A CreatorPolicyHandler and requirement also allow resource ownership checks for auditable entities.

Source/Shared/Kernel/BuildingBlocks/Auth · medium confidence

Refactored EF Core infrastructure and added email sending capability

The EF Core infrastructure was refactored into a new BaseDbContext that enforces multi-tenant isolation by automatically setting the TenantId on new entities and validating that all changes in a single save operation belong to the same tenant. This includes new configuration classes for SQL Server connection strings, an execution context interceptor, and a transaction scope middleware. Additionally, a new email sending feature was added, introducing an IEmailSender interface and a SendGrid-based implementation to handle outgoing emails.

Source/Shared/Features/EFCore · medium confidence

Test coverage

Added empty architecture test scaffolding; Added initial test scaffolding for the Channel module.

Dependencies

Upgrade to .NET 9 and update core dependencies

The project has been upgraded to target .NET 9.0 across most modules, including the Web Server, Web Client, and shared feature/dependency projects. This upgrade is accompanied by updates to key libraries such as Microsoft.EntityFrameworkCore, Microsoft.AspNetCore.Components, and Microsoft.AspNetCore.Identity to version 9.0.0. Additionally, several third-party packages have been updated or added, including AutoMapper (13.0.1), Blazored.Modal (7.3.1), and Stripe.net (47.1.0).

(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

This is the PUBLIC form of this artifact. Findings are listed in full, but the details of SECURITY findings — which rule fired, in which file, on which line, and how to fix it — are deliberately withheld, and any secret-scanner results are excluded entirely. Where detail is absent here it was REMOVED FOR PUBLICATION; it is not missing from the analysis. The complete artifact is available from the repository owner.

Score

  • CAI 42 → 40 (-1.7)
  • Rubric changed (rubric-2026.08.18 → rubric-2026.09.15) — scores are not directly comparable.

Lenses

  • Code Health 60 → 58 (-1.3)
  • Architecture 69 → 69 (+0.0)
  • Maturity 52 → 52 (+0.0)
  • Readiness 30 → 30 (-0.2)
  • Security 67 → 64 (-2.3)
  • Event-Driven 100 → 100 (+0.0)
  • Accessibility 42 → 36 (-5.8)

Resolved (9)

  • Inconsistent naming for command handler: 'DeleteChannel' is a command type, but its handler is named 'DeleteChannelCommandCommandHandler' (redundant 'Command' in name), whereas 'ChangeChannelName' uses 'ChangeChannelName' for the command and presumably a consistent handler naming elsewhere.
  • Inconsistent use of 'ByID' vs 'ById' in query/DTO names. Some use 'ByID' (e.g., GetTenantByID), while others use 'ById' (e.g., GetTenantByIdQueryHandler).
  • LLM evaluation failed
  • No exposed public API
  • The README links only to ModularMonolith.SaaS.Template for architecture and provides no guidance about how to run the CrispyCollab project independently of the template repo. (README.md)
  • Typo in namespace: 'Aplication' instead of 'Application'.
  • Typo in type name: 'RemoveUserFromTenantommandHandler' contains an extra 'o' in 'ommand'.
  • XML-doc coverage: Modules.TenantIdentity.Web.Client (Source/Modules/TenantIdentity/Web/Client/Modules.TenantIdentity.Web.Client.csproj)
  • dormant codebase — no living knowledge left to concentrate

New (36)

  • CommentedOutCode (Source/Modules/Channels/Web/Client/Modals/CreateChannelModal.razor.cs)
  • CommentedOutCode (Source/Modules/Channels/Web/Server/Controllers/ChannelsController.cs)
  • CommentedOutCode (Source/Web/Client/BuildingBlocks/Wrappers/SignalRWrapper.razor)
  • Documentation: no installation or build instructions (README.md)
  • Documentation: no usage examples (README.md)
  • Duplicated block (19 lines × 2) (Source/Shared/Kernel/BuildingBlocks/Services/Http/HttpClientService.cs)
  • Duplicated block (7 lines × 2) (Source/Shared/Features/Server/BaseController.cs)
  • End-of-life runtime: .NET net6.0
  • End-of-life runtime: .NET net9.0
  • High IaC: WD-COMPOSE-0002 (docker-compose.yml)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • Inconsistent naming pattern for command handler: 'DeleteChannelCommandCommandHandler' repeats 'Command' twice, whereas other handlers in the codebase (e.g., 'ChangeChannelName', 'UpdateTenantMembership') follow the pattern '<CommandName>CommandHandler' or '<CommandName>Handler'. The command type is 'DeleteChannel', so the handler should likely be 'DeleteChannelCommandHandler' or 'DeleteChannelHandler'.
  • Inconsistent property naming for the same concept (User ID) in different query result DTOs/properties. One uses 'UserId' in 'GetAllTenantMembershipsOfUser', the other uses 'UserId' in 'GetTenantByID'. While both are 'UserId', the context suggests they might be part of different DTOs. However, looking closer, 'GetTenantByID' is a query, and 'UserId' is a property. 'GetAllTenantMembershipsOfUser' also has 'UserId'. This is actually consistent. Let's look for a real inconsistency.

Re-evaluating: 'GetTenantByID' vs 'GetTenantById'. Type: public Modules.TenantIdentity.Features.DomainFeatures.Tenants.Application.Queries.GetTenantByID Type: public Modules.TenantIdentity.Features.DomainFeatures.Tenants.Application.Queries.GetTenantByIdQueryHandler

The query type is 'GetTenantByID' (uppercase ID), but the handler is 'GetTenantByIdQueryHandler' (lowercase id). This is a casing inconsistency for the same concept.

  • …and 16 more

API surface

  • Unchanged — 22 HTTP endpoints

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

Survey your own repository

DavidEggenberger/CrispyCollab 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 ddfa327d102f911c96782a05ea5205d81ceec7a2 — 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.