A production-ready .NET 10 + Next.js 16 Clean Architecture template, orchestrated by .NET Aspire and ready to deploy to Azure with azd. It ships with a Minimal API, an admin dashboard, dual authentication providers, and PostgreSQL β all wired up out of the box.
- π― Clean Architecture β strict layer boundaries enforced by architecture tests
- β‘ .NET 10 Minimal API β versioned endpoints, output caching,
Result<T>pattern - π§© CQRS via the Mediator source generator (no MediatR runtime cost)
- π Next.js 16 Admin Panel β App Router BFF with i18n (en / fa / ar + RTL)
- π Pluggable Authentication β switch between Keycloak and Microsoft Entra ID via config
- π Scalar API Reference β interactive OpenAPI UI with implicit OAuth flow (no client secret needed)
- π οΈ Orval-generated API client β typed React hooks regenerated from the OpenAPI spec
- π PostgreSQL via EF Core 10 with auto-applied migrations
- βοΈ .NET Aspire β orchestrates all services locally and provisions Azure infrastructure
- π§ͺ Robust Testing β Domain unit tests, architecture tests, and Aspire-based integration tests
- π‘οΈ Polly β retries, circuit breakers, fallbacks for outbound calls
Domain β Application β Infrastructure / Infrastructure.Persistence β Presentation
| Layer | Responsibility |
|---|---|
| Domain | Entities, Value Objects, Specifications, Domain Events |
| Application | CQRS commands/queries, validators, Result<T> |
| Infrastructure | External integrations (email, etc.) with Polly resilience |
| Infrastructure.Persistence | EF Core DbContext, Postgres, migrations, interceptors |
| Presentation/API | Minimal API, versioned at /api/v1/..., Scalar UI |
| Presentation/admin | Next.js admin dashboard (BFF + NextAuth.js) |
| Aspire AppHost | Orchestrates the full stack and Azure deployment |
- π¦ .NET 10 SDK
- π³ Docker Desktop (for Postgres, Keycloak, PgAdmin containers)
- π’ Node.js 20+ and pnpm
- π©οΈ (Optional) Azure CLI + Azure Developer CLI (
azd) for cloud deployment
# 1. Clone
git clone https://github.com/iPazooki/CleanArchitecture.git
cd CleanArchitecture
# 2. Restore .NET dependencies
dotnet restore
# 3. Install admin panel dependencies
cd CleanArchitecture.Presentation/admin && pnpm install && cd ../..
# 4. Run the full stack with Aspire
dotnet run --project CleanArchitecture.Aspire/CleanArchitecture.AppHost/CleanArchitecture.AppHost.csprojAspire will spin up everything you need:
| Service | What it does |
|---|---|
| π΅ API | .NET Minimal API |
| π£ Admin | Next.js dashboard |
| π Postgres + PgAdmin | Database & UI |
| π Keycloak | Local identity provider (realm auto-imported) |
The Aspire dashboard prints the URLs for every resource (API, Scalar UI, admin, Keycloak, PgAdmin).
The app supports two providers and switches between them via configuration.
| Environment | Default Provider | Why |
|---|---|---|
| π οΈ Development | Keycloak | Runs as a local container, realm auto-imported, no cloud setup needed |
| βοΈ Production | Microsoft Entra ID | Managed identity, no secrets to rotate for the API |
In CleanArchitecture.Aspire/CleanArchitecture.AppHost/appsettings.*.json:
The AppHost wires the right environment variables (Authentication__Provider, issuer URLs, audiences, NextAuth client config) into the API and admin projects automatically.
π Scalar uses the OAuth 2.0 implicit flow, so no client secret is needed for the API reference UI. Just sign in from the Scalar page.
Once running, open the Scalar UI from the Aspire dashboard's API resource. It renders the OpenAPI spec at /openapi/v1.json and lets you authenticate and call endpoints interactively.
The admin dashboard lives in CleanArchitecture.Presentation/admin (Next.js 16, App Router, Tailwind, NextAuth.js, TanStack Query).
cd CleanArchitecture.Presentation/admin
pnpm dev # dev server (Aspire normally runs this for you)
pnpm build # production build
pnpm lint # ESLint with --max-warnings=0
pnpm generate # regenerate the typed API client from the live OpenAPI specThe React Query hooks and TypeScript DTOs under src/lib/api/ are generated by Orval from the API's OpenAPI document. Never edit them by hand. After changing an endpoint or DTO, run:
pnpm generate(Make sure the API is running on http://localhost:5049 so Orval can fetch the spec.)
- Engine: PostgreSQL
- ORM: EF Core 10 (
Npgsql.EntityFrameworkCore.PostgreSQL) - Migrations: live in
CleanArchitecture.Infrastructure.Persistence - Auto-apply: the dedicated
CleanArchitecture.DbMigratorproject runs migrations at startup before the API boots
dotnet ef migrations add <MigrationName> \
--project CleanArchitecture.Infrastructure.Persistence \
--startup-project CleanArchitecture.Presentation/APIπ‘ An
ApplicationDbContextFactoryprovides a design-time connection string so EF tools work without Aspire running.
The Aspire AppHost provisions everything for you:
- π’ Azure Container Apps β API, admin, (optionally Keycloak)
- π Azure Database for PostgreSQL Flexible Server
- π Azure Key Vault β all secrets stored here automatically
- π Azure Application Insights
azd upazd only prompts for values it cannot derive automatically. Public URLs (adminPublicUrl, apiPublicUrl, authPublicUrl) are derived from Container Apps endpoints β you don't need to enter them.
nextAuthSecret
EntraAPIInstance
EntraAPIPrimaryDomain
EntraAPIClientId
EntraAPIAudienceId
EntraTenantId
EntraAdminClientId
EntraAdminClientSecret
EntraAdminScope
EntraAdminOpenIdURL
keycloakClientId
keycloakClientSecret
keycloakRealm
keycloakAdminUsername
keycloakAdminPassword
keycloakDbUsername
keycloakDbPassword
π All secret parameters (
*Secret,*Password,nextAuthSecret) are written to Azure Key Vault automatically β they never live in plain text in your container apps.
dotnet test --configuration Release- 𧬠Domain unit tests β
Tests/Domain.UnitTests - ποΈ Architecture tests β enforce layer dependencies
- π Integration tests β use
DistributedApplicationTestingBuilderagainst a real Aspire fixture
The Testing environment uses an ephemeral Postgres and a TestAuthHandler that grants all roles, so no Keycloak or Entra setup is required.
Pull requests are welcome! For major changes, please open an issue first to discuss what you'd like to change.
β If you find this template useful, please star the repo β it really helps!
MIT β use it freely as a foundation for your own projects.
{ "UseKeycloak": true // false β Entra }