ModularMonolith.Solution.Template
2.1.0
dotnet new install ModularMonolith.Solution.Template@2.1.0
StarterKit — Modular Monolith Core for ASP.NET Core
The core of the StarterKit Modular Monolith template: the reusable C#/.NET framework building blocks (built on the private "Light" framework family — Lightsoft.* packages), a composition-root host with a .NET Aspire app host for local development, and two business modules — Identity (the reference module) and Notifications — with their tests. Client apps are not part of the .NET solution; the repository carries one, the clients/admin admin console. Meant to be cloned, forked, or installed as a dotnet new template as the starting point for new projects.
Getting Started
Backend
dotnet build StarterKit.slnx
dotnet run --project src/StarterKit.AppHost # API + Redis + RabbitMQ + Aspire dashboard
dotnet run --project src/StarterKit.WebApi/StarterKit.WebApi.csproj # or the API on its own (in-memory cache, no-op bus)
dotnet test --solution StarterKit.slnx
Database provider and schema setup, configuration, test filters, and migrations: docs/conventions/development-guide.md.
Client (clients/admin)
cd clients/admin
pnpm install
cp .env.example .env.local # then fill in the vars listed in .env.example
pnpm dev
The required environment variables are described in clients/admin/docs/conventions/development-guide.md. All env vars are server-only (never NEXT_PUBLIC_). The backend must be running and reachable at the configured API base URLs for auth and data pages to work, and its CORS policy must allow the admin app's origin for the SignalR notification hub to connect directly from the browser. Under the Aspire app host (StarterKit.AppHost), the admin client is started alongside the API.
Install as a template
The repository packs into one NuGet template package, ModularMonolith.Solution.Template. Pack it from the repo root, install it, and generate from it:
nuget pack ModularMonolith.nuspec -NoDefaultExcludes # -NoDefaultExcludes keeps the dot-folders (.template.config) in the package
dotnet new install ./ModularMonolith.Solution.Template.<version>.nupkg
dotnet new mm-sln -n MyApp # a whole solution; "StarterKit" is renamed to MyApp
dotnet new mm -n Billing # a single-project module (Billing + Billing.Contracts)
dotnet new ca-mm -n Billing # a Clean Architecture module (Domain, Application, Infrastructure, Contracts)
Run dotnet new mm / ca-mm inside the new solution's src/ folder so the generated project references (..\Shared, ..\Infrastructure, …) resolve, then add the projects to the solution and register the module in StarterKit.WebApi. Uninstall with dotnet new uninstall ModularMonolith.Solution.Template. Pack from a clean working tree: the package contains whatever files are on disk, including local appsettings.json edits.
Status — what's built
| Piece | Status |
|---|---|
src/Shared, src/Infrastructure, src/Persistence, src/EventBusMassTransitRabbitMQ (framework building blocks) |
✅ built |
src/Identity + src/Identity.Contracts — users, roles, claims, self-issued JWT/refresh/session/hub tokens, Active Directory, permission catalog |
✅ built, tested |
src/Identity.Web — Razor Pages login, Microsoft Entra ID (OIDC) external login with a PKCE authorization-code relay for separate-origin clients, and admin pages for users, roles, and permissions — co-hosted in StarterKit.WebApi or standalone |
✅ built |
src/Notifications + src/Notifications.Contracts — notification storage, SignalR push, SMTP mail, welcome-mail consumer of Identity's integration event |
✅ built, tested |
src/Migrations/{MSSQL,PostgreSQL,Sqlite} — per-provider EF Core migrations and migrate-and-seed console apps |
✅ built — see docs/conventions/migrations.md |
src/StarterKit.WebApi (composition-root host), src/StarterKit.AppHost + src/StarterKit.ServiceDefaults (.NET Aspire local orchestration) |
✅ built — runnable API |
tests/Framework.Tests, tests/Identity.Tests, tests/Notifications.Tests (xUnit v3) |
✅ built |
clients/admin (Next.js admin console) — real auth (password or Microsoft), permission-gated admin screens over Identity and Notifications, real-time notifications — see clients/admin/CLAUDE.md |
✅ built |
dotnet new templates — solution (mm-sln) and module projects (mm, ca-mm) packed by ModularMonolith.nuspec |
✅ built — see Install as a template |
Further business modules and additional clients/* apps |
❌ not part of this branch |
Structure
Projects, grouped by solution folder in StarterKit.slnx:
StarterKit.slnx
├── /src/_framework/
│ ├── src/Shared (shared kernel)
│ ├── src/Infrastructure (ASP.NET Core hosting building blocks)
│ ├── src/Persistence (EF Core building blocks)
│ └── src/EventBusMassTransitRabbitMQ (integration-event bus)
├── /src/
│ ├── src/StarterKit.WebApi (composition root, the only deployable)
│ ├── src/StarterKit.AppHost (.NET Aspire app host — local orchestration, Redis/RabbitMQ containers, dashboard)
│ └── src/StarterKit.ServiceDefaults (.NET Aspire service defaults — telemetry, service discovery, resilience)
├── /src/identity-module/
│ ├── src/Identity.Contracts (the module's cross-module seam)
│ ├── src/Identity (module implementation — JSON API, token issuance, persistence)
│ └── src/Identity.Web (Razor Pages login, Microsoft login relay, and admin pages — co-hosted or standalone)
├── /src/notifications-module/
│ ├── src/Notifications.Contracts (the module's cross-module seam)
│ └── src/Notifications (module implementation — notification storage, SignalR push, SMTP mail)
├── /src/_migrations/
│ ├── src/Migrations/MSSQL (EF migrations + migrate-and-seed console app, SQL Server)
│ ├── src/Migrations/PostgreSQL (same, PostgreSQL)
│ └── src/Migrations/Sqlite (same, Sqlite)
└── /tests/
├── tests/Framework.Tests (framework projects)
├── tests/Identity.Tests (Identity module)
└── tests/Notifications.Tests (Notifications module)
Outside the solution:
clients/
└── admin/ (Next.js admin console — consumes the Identity and Notifications APIs over HTTP)
.template.config/ (`dotnet new` solution template `mm-sln` — the whole repository)
templates/
├── module/ (`dotnet new mm` — single-project module + Contracts)
└── ca-module/ (`dotnet new ca-mm` — Clean Architecture module: Domain, Application, Infrastructure, Contracts)
ModularMonolith.nuspec (packs the above as one NuGet template package)
Project responsibilities and the dependency rules are in CLAUDE.md; the exact project references are in docs/architecture/dependency-graph.md. The admin client is documented in clients/admin/CLAUDE.md, and the backend ↔ client boundary in docs/integration.md.
Architecture Diagram
graph TD
Client["Separate-origin client"]
AppHost["StarterKit.AppHost<br/>Aspire (local dev)"]
WebApi["StarterKit.WebApi<br/>composition root"]
SD["StarterKit.ServiceDefaults"]
Migrators["src/Migrations/*<br/>migrate + seed"]
subgraph IdentityModule["Identity module"]
IdW["Identity.Web<br/>Razor Pages"]
Id["Identity<br/>implementation"]
IdC["Identity.Contracts<br/>seam"]
end
subgraph NotificationsModule["Notifications module"]
Nt["Notifications<br/>implementation"]
NtC["Notifications.Contracts<br/>seam"]
end
subgraph Framework["Framework"]
Infra["Infrastructure"]
Persistence["Persistence"]
Bus["EventBusMassTransitRabbitMQ"]
Shared["Shared<br/>(leaf)"]
end
Client -. HTTP/JSON, SignalR .-> WebApi
AppHost -. runs .-> WebApi
WebApi --> SD
WebApi --> IdentityModule
WebApi --> NotificationsModule
WebApi --> Framework
Migrators --> IdentityModule
Migrators -- MSSQL only --> NotificationsModule
Migrators --> Framework
IdW --> Id
Id --> IdC
IdentityModule --> Infra & Persistence
Nt --> NtC
Nt --> IdC
Nt --> Infra & Persistence & Bus
IdC --> Shared
NtC --> Shared
Infra & Persistence & Bus --> Shared
classDef leaf fill:#2f6f4f,stroke:#1e4a34,color:#fff;
class Shared leaf;
Login Flow (client ↔ server)
A separate-origin client has two sign-in paths that both end with the client holding the same token pair (access + refresh token). See Identity for the module's mechanics — this is the shape, not the detail.
sequenceDiagram
actor U as Browser
participant C as Client
participant W as Identity.Web (in WebApi)
participant I as Identity module (in WebApi)
participant M as Microsoft Entra ID
rect rgb(235, 245, 255)
note over U,I: Password login
U->>C: submit credentials
C->>I: POST api/v1/auth/token/get
I-->>C: TokenDto
C-->>U: client stores the token pair
end
rect rgb(240, 255, 240)
note over U,M: Microsoft login (PKCE authorization-code relay)
U->>C: start Microsoft sign-in
C-->>U: 302 → Identity.Web (state, PKCE code_challenge, client keeps the verifier)
U->>W: GET /Account/ExternalLoginStart
W-->>U: 302 → Microsoft sign-in
U->>M: authenticate
M-->>U: 302 → Identity.Web (/signin-oidc)
U->>W: OIDC callback (/Account/ExternalLoginRelay)
W->>I: resolve user, mint token (in-process, same module)
W-->>U: 302 → client redirectUri?code=...&state=...
U->>C: GET redirectUri?code=...
C->>I: POST api/v1/auth/token/external {code, codeVerifier}
I-->>C: TokenDto (code now consumed, single-use)
C-->>U: client stores the token pair
end
Access tokens are renewed through POST api/v1/auth/token/refresh. The client's redirectUri must be allow-listed in ExternalLoginRelay:AllowedRedirectUris.
Tech Stack
| Layer | Stack |
|---|---|
| Runtime | ASP.NET Core (C#), net10.0 |
| Architecture | Modular Monolith — see Structure |
| Data access | EF Core — provider-configurable via DbProvider (InMemory / PostgreSQL / MSSQL / Sqlite) |
| Authentication | ASP.NET Core Identity; self-issued JWT (Bearer) for the API; cookie for the Razor Pages; optional Microsoft Entra ID (OIDC) external login |
| Messaging | MassTransit over RabbitMQ for integration events; a no-op bus when disabled |
| Real-time / mail | SignalR hub for real-time notification push; SMTP mail (Lightsoft.SmtpMail) |
| Observability / local orchestration | Serilog; OpenTelemetry via .NET Aspire service defaults; Aspire app host and dashboard for local development, also running Redis and RabbitMQ containers |
| Vendor framework | Lightsoft.* package family (mediator, Result/Paged contracts, domain base types, ASP.NET Core authorization/modularity helpers, caching, Serilog, event bus, Active Directory, SMTP mail) |
| Validation / mapping | FluentValidation, Mapster |
| Testing | xUnit v3 + Moq (via tests/ModuleTests.props) on Microsoft.Testing.Platform (selected by the root global.json) |
| Client | clients/admin/ — Next.js 16 (App Router), React 19, TypeScript, Tailwind CSS v4, pnpm. Encrypted-cookie sessions (password or Microsoft login, proactive token refresh); real-time notifications over SignalR. Currently the only client app |
Package versions are managed centrally in Directory.Packages.props.
Documentation
- CLAUDE.md — repository-wide entry point (project map, dependency direction, framework conventions, AI operating rules).
- docs/ — generated project documentation; start at docs/architecture/architecture.md (layering, runtime flows, and links to each project's overview).
- docs/conventions/ — coding conventions, development guide, migrations, and local Docker infrastructure.
- docs/integration.md — the backend ↔ client integration boundary.
- clients/admin/CLAUDE.md / clients/admin/docs/ — admin client architecture and conventions.
- .claude/ — reusable Claude development infrastructure (agents, skills, workflows), not project documentation.
License
MIT — see LICENSE.
Last synced: 2026-10-13
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
* Solution template mm-sln: framework, host, Identity and Notifications modules, Next.js admin client
* Module templates: mm (single project + Contracts) and ca-mm (Domain/Application/Infrastructure + Contracts)
* Module templates now follow the real module layout: StarterKit.Modules.ModuleName namespaces, AppModule/AppModuleConsumer scaffolding, AddModuleNameServices registration
* Fixed the corrupted ca-mm Domain project file