BitzOrcas.Modern is an opinionated, production-first .NET 10 modular monolith template for building multi-tenant SaaS and enterprise APIs. Designed around a principle of AI-assisted development, every architectural decision—from clear module boundaries to explicit registration stages—prioritises code that is machine-readable, constraint-enforced, and safe for LLM collaborators to reason about.
You get the full source — BuildingBlocks, Platform modules, Hosts, and Tooling — wired through Minimal APIs, Mediator, and a pluggable ORM adapter layer (SqlSugar primary, EF Core optional). No black-box NuGet packages: you own and can modify everything.
Highlights
- Modular monolith, vertical slices. Each module is a bounded context with its own contracts, domain, application, infrastructure, and endpoints. Communication across modules goes through
*.Contractsprojects only — runtime projects never reference each other. Module governance is enforced byIAppModule+ ArchUnitNET tests. - AI-assisted development by design. Codebase structured for LLM comprehension: explicit four-stage DI registration, documented constraints, invariant-preserving patterns. Architecture decisions recorded as ADRs and enforced by automated tests, not just conventions.
- Multi-tenant from day one. 8-level
ITenantResolverchain withTenantEntityBasehierarchy. SqlSugar global filters, cross-tenant query patterns, and background job tenant context propagation built in. - Unified authorization. RBAC + ABAC + ReBAC + DataScope + Feature flags + AppScope — a single
IAuthorizationDecisionServicedispatches to the appropriate policy evaluator per request. - Pluggable persistence. SqlSugar (primary, trim-clean) with optional EF Core and Dapper (query-only) adapters. Swap the ORM without touching application code — the adapter pattern keeps handlers pure.
- Event-driven architecture. Domain events on aggregates + integration events via CAP + RabbitMQ with Outbox pattern (same-database). Automatic retry, dead-letter queues, and per-instance resource sync.
- 7-pipeline Mediator chain. Validation → Authorization → Idempotency → Transaction → Logging → ActivityAudit → DomainEventDispatch — each behavior is a composable, testable pipeline step.
- 7-category audit with sharding. Activity, entity-change, security, exception, request, authorization, and background-job audits. Sharded storage by month with configurable retention.
- Background jobs. Quartz.NET scheduler with
SystemJobTenantContextfor tenant-aware job execution. - Observability baked in. OpenTelemetry traces, metrics, and logs (OTLP); Serilog structured logging; health checks; business-context tags on tenant operations.
- API docs. OpenAPI + Scalar UI. Versioned routes via
Asp.Versioning.Http. - Cloud-ready.
.NET AspireAppHost brings up SQL Server and RabbitMQ locally with one command. Production deploy via Docker Compose. - Template engine. Scriban-based code generation for scaffolding new modules, features, and contracts from metadata.
- Sandbox module. Built-in Notes, Greetings, and Ping examples demonstrate the full vertical slice pattern — perfect starting points for new features.
High-level architecture
BitzOrcas.Modern/├── src/│ ├── BuildingBlocks/ Shared framework libraries│ │ ├── BitzOrcas.Domain DDD primitives, `Result<T>`, EntityBase│ │ ├── BitzOrcas.Application Mediator pipelines, auth, tenancy, sandbox│ │ ├── BitzOrcas.Infrastructure Shared infra abstractions│ │ ├── BitzOrcas.Infrastructure.SqlSugar SqlSugar adapter (primary ORM)│ │ ├── BitzOrcas.Infrastructure.EfCore EF Core adapter (optional)│ │ ├── BitzOrcas.Infrastructure.Dapper Dapper query-only adapter│ │ ├── BitzOrcas.Infrastructure.Persistence.Models Shared persistence models│ │ ├── BitzOrcas.Modularity IAppModule, AppModuleRegistry, boundary verifier│ │ ├── BitzOrcas.CodeGeneration.* Scriban template engine│ │ └── ...│ ││ ├── Platform/ Platform-level shared contracts│ │ ├── BitzOrcas.Platform.Application│ │ ├── BitzOrcas.Platform.Contracts│ │ └── BitzOrcas.SaaS.Contracts│ ││ ├── Hosts/ Application hosts│ │ ├── BitzOrcas.Api API composition root (Program.cs)│ │ ├── BitzOrcas.AppHost .NET Aspire orchestrator│ │ ├── BitzOrcas.JobHost Background job host (Quartz)│ │ └── BitzOrcas.ServiceDefaults Aspire service defaults│ ││ └── Tooling/ Development & code generation tools│ ├── BitzOrcas.SeedData.Exporter CSV seed data management│ └── BitzOrcas.Modern.Templates dotnet new templates│├── tests/ Architecture tests + per-module tests├── docs/ ADRs, context maps, roadmaps└── scripts/ Build & utility scriptsModule boundaries are enforced by ArchUnitNET rules in tests/.
Feature slice layout
Each feature is a vertical slice. The Sandbox module demonstrates the pattern:
BuildingBlocks/BitzOrcas.Application/Sandbox/Notes/ CreateNoteCommand.cs ← Command ( IRequest<TResponse> ) CreateNoteCommandHandler.cs ← Handler ( IRequestHandler<TCommand, TResponse> ) CreateNoteCommand.cs ← Mediator wiring GetNoteByIdQuery.cs ← Query GetNoteByIdQueryHandler.cs ← Query handler ISandboxDataPort.cs ← Port (abstraction for persistence)Handlers are public sealed, return ValueTask<Result<T>>, and use .ConfigureAwait(false). Endpoints are defined in the API host’s Endpoints/ directory and mapped via MapBitzOrcasEndpoints().
Composition root
src/Hosts/BitzOrcas.Api/Program.cs wires the platform in four explicit stages:
// Stage 1: Core runtime (clock, CurrentUser, audit defaults, tenant resolvers, UoW)builder.Services.AddBitzOrcasCoreRuntime(builder.Configuration);
// Stage 2: Persistence adapters (SqlSugar primary; EF Core / Dapper optional)builder.Services.AddBitzOrcasPersistenceAdapters(builder.Configuration);
// Stage 3: Authentication (JWT / HMAC / ApiKey — fail-fast key validation)builder.Services.AddBitzOrcasAuthentication(builder.Configuration, builder.Environment);
// Stage 4: API pipeline (Mediator + Mapster + JSON + OpenAPI + Scalar + RateLimiter)builder.Services.AddBitzOrcasApiPipeline(builder.Configuration);The API never mutates data at startup. Schema initialization and seed data are handled by --init-schema / --seed-demo CLI flags — the process runs schema creation, audit table sharding, and CSV-based seeding, then exits immediately without entering the web pipeline.
Stack
Runtime
| Concern | Technology |
|---|---|
| Framework | .NET 10 / C# latest |
| Solution | .slnx (XML) with central package management (Directory.Packages.props) |
| Web | Minimal APIs, Asp.Versioning.Http 10 |
| Mediator | Mediator 3.0.2 (source generator — no reflection) |
| Validation | IRequestRule (native, no FluentValidation dependency) |
| ORM (primary) | SqlSugar 5.1 (trim-clean, CodeFirst) |
| ORM (optional) | EF Core 10 (adapter pattern) |
| Query (read-only) | Dapper 2.1 |
| Database | SQL Server (Microsoft.Data.SqlClient) |
| Identity / Auth | 3-scheme: JWT + HMAC + ApiKey, ASP.NET Core authentication |
| Multitenancy | 8-level ITenantResolver chain, TenantEntityBase hierarchy |
| Authorization | Unified RBAC/ABAC/ReBAC/DataScope via IAuthorizationDecisionService |
| Caching | FusionCache (in-memory + distributed) |
| Jobs | Quartz.NET 3.13 |
| Event bus | CAP 10 + RabbitMQ (Outbox pattern, same-database) |
| Mapping | Mapster 10.0 |
| Object mapping | Vogen (strongly-typed IDs), NodaTime (date/time) |
| HTTP resilience | Microsoft.Extensions.Http.Resilience (Polly v8) |
| Logging | Serilog (structured) |
| Tracing / metrics | OpenTelemetry (OTLP exporter) |
| API docs | OpenAPI + Scalar UI |
| Errors | ProblemDetails (RFC 9457) via global exception handler |
| Code generation | Scriban 7.2 templates |
| Snowflake IDs | Yitter.IdGenerator |
| Orchestration | .NET Aspire (SQL Server + RabbitMQ + API) |
Testing
| Layer | Tools |
|---|---|
| Unit | xUnit, Shouldly, NSubstitute |
| Integration | Microsoft.AspNetCore.Mvc.Testing, Testcontainers (SQL Server / RabbitMQ) |
| Architecture | ArchUnitNET — enforces module boundaries |
Distribution
| Channel | Command |
|---|---|
| Clone the repo | git clone <repo-url> |
| dotnet new template | dotnet new install BitzOrcas.Modern.Templates && dotnet new bitzorcas-modern -n MyApp |
Design constraints
BitzOrcas.Modern is built around two key constraints:
-
AI-assisted development. The codebase is structured so that LLM collaborators can understand boundaries, registration order, and invariants without guessing. Four-stage DI registration, explicit module contracts, and ADR-enforced architecture tests make the system self-documenting.
-
Native AOT readiness. While not all dependencies currently support AOT (e.g., SqlSugar), the architecture is designed to minimise reflection usage where possible. Mediator uses source generation, validation uses native
IRequestRule, and serialization uses System.Text.Json.
Where to go next
- Prerequisites — what you need installed.
- Quick Start — run the project in 60 seconds.
- Architecture — modular monolith, VSA, module boundaries.
- Architecture Diagrams — visual system overview, module dependencies, pipeline flows.
- Modules — Identity, Tenancy, Authorization, Auditing, and more.
- Building Blocks — shared framework libraries and adapters.