Skip to content
bitzorcas
EN

Guide

Introduction

What BitzOrcas.Modern is, what it ships with, and how it's put together.

Last updated

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 *.Contracts projects only — runtime projects never reference each other. Module governance is enforced by IAppModule + 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 ITenantResolver chain with TenantEntityBase hierarchy. 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 IAuthorizationDecisionService dispatches 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 SystemJobTenantContext for 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 Aspire AppHost 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 scripts

Module 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

ConcernTechnology
Framework.NET 10 / C# latest
Solution.slnx (XML) with central package management (Directory.Packages.props)
WebMinimal APIs, Asp.Versioning.Http 10
MediatorMediator 3.0.2 (source generator — no reflection)
ValidationIRequestRule (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
DatabaseSQL Server (Microsoft.Data.SqlClient)
Identity / Auth3-scheme: JWT + HMAC + ApiKey, ASP.NET Core authentication
Multitenancy8-level ITenantResolver chain, TenantEntityBase hierarchy
AuthorizationUnified RBAC/ABAC/ReBAC/DataScope via IAuthorizationDecisionService
CachingFusionCache (in-memory + distributed)
JobsQuartz.NET 3.13
Event busCAP 10 + RabbitMQ (Outbox pattern, same-database)
MappingMapster 10.0
Object mappingVogen (strongly-typed IDs), NodaTime (date/time)
HTTP resilienceMicrosoft.Extensions.Http.Resilience (Polly v8)
LoggingSerilog (structured)
Tracing / metricsOpenTelemetry (OTLP exporter)
API docsOpenAPI + Scalar UI
ErrorsProblemDetails (RFC 9457) via global exception handler
Code generationScriban 7.2 templates
Snowflake IDsYitter.IdGenerator
Orchestration.NET Aspire (SQL Server + RabbitMQ + API)

Testing

LayerTools
UnitxUnit, Shouldly, NSubstitute
IntegrationMicrosoft.AspNetCore.Mvc.Testing, Testcontainers (SQL Server / RabbitMQ)
ArchitectureArchUnitNET — enforces module boundaries

Distribution

ChannelCommand
Clone the repogit clone <repo-url>
dotnet new templatedotnet new install BitzOrcas.Modern.Templates && dotnet new bitzorcas-modern -n MyApp

Design constraints

BitzOrcas.Modern is built around two key constraints:

  1. 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.

  2. 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