Minimdev.CleanArchitecture.Template 1.6.0

dotnet new install Minimdev.CleanArchitecture.Template@1.6.0
                    
This package contains a .NET Template Package you can call from the shell/command line.

Clean Architecture Template Solution (.NET 10)

A comprehensive, production-ready ASP.NET Core starter template implementing Clean Architecture principles with CQRS, MediatR, JWT Authentication, and modern API documentation.

.NET 10.0 Mapster NuGet NuGet Downloads GitHub Stars License: MIT


๐Ÿ—๏ธ Project Structure

YourProject/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ Core/
โ”‚   โ”‚   โ”œโ”€โ”€ YourProject.Domain/                        # Enterprise business rules & entities
โ”‚   โ”‚   โ””โ”€โ”€ YourProject.Application/                   # Use cases, CQRS, validators, interfaces
โ”‚   โ”œโ”€โ”€ Infrastructure/
โ”‚   โ”‚   โ”œโ”€โ”€ YourProject.Infrastructure.Persistence/    # Data access (EF Core, migrations)
โ”‚   โ”‚   โ”œโ”€โ”€ YourProject.Infrastructure.Identity/       # Authentication & JWT
โ”‚   โ”‚   โ””โ”€โ”€ YourProject.Infrastructure.Shared/         # Shared services (email, datetime, etc.)
โ”‚   โ””โ”€โ”€ Presentation/
โ”‚       โ”œโ”€โ”€ YourProject.WebAPI/                        # REST API controllers, middleware, DI
โ”‚       โ””โ”€โ”€ YourProject.WebUI/                         # Blazor Server interactive frontend
โ”œโ”€โ”€ tests/
โ”‚   โ”œโ”€โ”€ YourProject.Domain.UnitTests/
โ”‚   โ”œโ”€โ”€ YourProject.Application.UnitTests/
โ”‚   โ””โ”€โ”€ YourProject.Application.IntegrationTests/
โ”œโ”€โ”€ docker-compose.yml
โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ YourProject.sln
โ””โ”€โ”€ README.md

โœจ Features

๐Ÿ›๏ธ Architecture & Patterns

  • โœ… Clean Architecture โ€” Clear layer separation with strict dependency rules
  • โœ… CQRS โ€” Command Query Responsibility Segregation via MediatR
  • โœ… Domain-Driven Design โ€” Rich domain models encapsulating business logic
  • โœ… Repository Pattern โ€” Abstracted data access layer
  • โœ… Result Pattern โ€” Consistent, explicit error handling without exceptions

โš™๏ธ Technology Stack

  • โœ… .NET 10 โ€” Latest long-term support framework
  • โœ… Blazor Server WebUI โ€” Interactive frontend with MudBlazor Material Design components
  • โœ… MediatR v12.x โ€” In-process messaging for CQRS implementation
  • โœ… Entity Framework Core 10 โ€” Code-First ORM with full migration support
  • โœ… SQL Server โ€” Separate databases for Application and Identity
  • โœ… ASP.NET Core Identity โ€” User and role management
  • โœ… JWT Bearer Authentication โ€” Stateless, secure API authentication
  • โœ… Mapster v10.x โ€” High-performance object-to-object mapping
  • โœ… FluentValidation โ€” Expressive and testable request validation
  • โœ… Scalar UI โ€” Modern API documentation with JWT support (fully offline โ€” scalar.min.js is bundled as a local static file with proxy and telemetry disabled)
  • โœ… OpenTelemetry โ€” Distributed tracing and observability (Console + OTLP exporters)
  • โœ… xUnit โ€” Unit and integration testing framework

๐Ÿš€ Key Capabilities

  • โœ… Refresh Token โ€” Secure token rotation with POST /api/v1/Auth/refresh and revoke via POST /api/v1/Auth/revoke
  • โœ… Integration Tests โ€” WebApplicationFactory with SQLite in-memory, no SQL Server required for testing
  • โœ… Role-Based Access Control (RBAC) โ€” Pre-configured Admin and Member roles with authorization policies
  • โœ… User Management Dashboard โ€” View users and modify roles dynamically from the UI
  • โœ… API Versioning โ€” Versioned endpoints (/api/v1/...) via URL segment & request header
  • โœ… Rate Limiting โ€” Built-in ASP.NET Core rate limiting (global & auth-specific limits)
  • โœ… Response Caching โ€” Output caching configured for GET endpoints
  • โœ… Background Jobs โ€” Hangfire integration with SQL Server storage & /hangfire dashboard
  • โœ… Message Bus (MassTransit) โ€” Async messaging with switchable transports: InMemory (default), RabbitMQ, ActiveMQ โ€” enabled via single config line
  • โœ… Resilience (Polly) โ€” Retry and circuit-breaker policies via Microsoft.Extensions.Http.Resilience
  • โœ… Email Service โ€” IEmailService abstraction with built-in SmtpEmailService implementation
  • โœ… Audit Trails โ€” Automatic tracking of CreatedAt / ModifiedAt timestamps
  • โœ… Soft Delete โ€” Global EF Core query filters for logical record deletion
  • โœ… Health Checks โ€” Database connectivity monitoring endpoint
  • โœ… Global Exception Handling โ€” Centralized middleware for consistent error responses
  • โœ… CORS Support โ€” Configurable cross-origin resource sharing
  • โœ… Docker Support โ€” Containerization-ready with Dockerfile and docker-compose.yml
  • โœ… Visual Studio 2022 & 2026 โ€” Full IDE support via the New Project dialog
  • โœ… .editorconfig โ€” Comprehensive code style and formatting rules

๐Ÿ“ฆ Using as a Template

Install from NuGet

dotnet new install Minimdev.CleanArchitecture.Template

Create a New Project

Via CLI
# Syntax: dotnet new cleanarch -n [YourProjectName] -o [OutputDirectory]
dotnet new cleanarch -n MyProject -o MyProject

What happens automatically on project creation:

Original Replaced With
CleanArchitecture.Domain MyProject.Domain
namespace CleanArchitecture.Domain namespace MyProject.Domain
src/Core/CleanArchitecture.Domain/ src/Core/MyProject.Domain/
Via Visual Studio 2022 / 2026
  1. Open Visual Studio 2022 or Visual Studio 2026
  2. Click Create a new project
  3. Search for "Clean Architecture Solution"
  4. Select the template, enter your project name โ†’ Create

The template automatically renames all projects and namespaces to match your chosen project name.

Uninstall Template

dotnet new uninstall Minimdev.CleanArchitecture.Template

๐Ÿš€ Quick Start

A. Template User (Generated Project)

After creating your project from the template (dotnet new cleanarch -n MyProject), replace MyProject with your actual project name in the steps below.

Prerequisites
  • .NET 10 SDK
  • SQL Server or SQL Server Express
  • Visual Studio 2022 / 2026, or VS Code
Setup Steps

1. Update connection strings

Edit src/Presentation/MyProject.WebAPI/appsettings.Development.json:

{
  "ConnectionStrings": {
    "DefaultConnection":  "Server=localhost;Database=MyProjectDB;Trusted_Connection=True;TrustServerCertificate=True;",
    "IdentityConnection": "Server=localhost;Database=MyProjectIdentityDB;Trusted_Connection=True;TrustServerCertificate=True;",
    "HangfireConnection": "Server=localhost;Database=MyProjectHangfireDB;Trusted_Connection=True;TrustServerCertificate=True;"
  }
}

2. Apply database migrations

# Application DB
dotnet ef database update \
  --project "src/Infrastructure/MyProject.Infrastructure.Persistence" \
  --startup-project "src/Presentation/MyProject.WebAPI" \
  --context ApplicationDbContext

# Identity DB
dotnet ef database update \
  --project "src/Infrastructure/MyProject.Infrastructure.Identity" \
  --startup-project "src/Presentation/MyProject.WebAPI" \
  --context IdentityDbContext

3. Run the application

dotnet run --project "src/Presentation/MyProject.WebAPI"

4. Access the application

URL Description
https://localhost:{port}/scalar/v1 Scalar API Documentation
https://localhost:{port}/health Health Check
https://localhost:{port}/hangfire Hangfire Job Dashboard

The port number depends on how you run the application:

  • CLI (dotnet run) โ€” port is defined in Properties/launchSettings.json (default: 7253 for HTTPS, 5022 for HTTP)
  • Visual Studio 2022 / 2026 โ€” Visual Studio may assign a different port automatically based on the selected launch profile. Check the Output window or browser tab opened by VS for the actual URL.
  • To always use a fixed port, set applicationUrl explicitly in launchSettings.json.

B. Contributor (Template Source)

This section is for contributors who want to develop or modify the template itself.

1. Clone the repository

git clone https://github.com/MinimDev/dotnet-clean-architecture-template.git
cd dotnet-clean-architecture-template

2. Update connection strings

Edit src/Presentation/CleanArchitecture.WebAPI/appsettings.Development.json with your local SQL Server details.

3. Apply migrations

dotnet ef database update \
  --project "src/Infrastructure/CleanArchitecture.Infrastructure.Persistence" \
  --startup-project "src/Presentation/CleanArchitecture.WebAPI" \
  --context ApplicationDbContext

dotnet ef database update \
  --project "src/Infrastructure/CleanArchitecture.Infrastructure.Identity" \
  --startup-project "src/Presentation/CleanArchitecture.WebAPI" \
  --context IdentityDbContext

4. Run

dotnet run --project "src/Presentation/CleanArchitecture.WebAPI"

๐Ÿ“– API Endpoints

Authentication

Method Endpoint Description
POST /api/v1/Auth/register Register a new user โ€” returns accessToken + refreshToken
POST /api/v1/Auth/login Login โ€” returns accessToken + refreshToken (Rate limited: 10 req/min)
POST /api/v1/Auth/refresh Exchange a valid refresh token for new token pair
POST /api/v1/Auth/revoke Revoke refresh token (logout) (Requires Auth)

Products (Requires Authentication)

Method Endpoint Description
GET /api/v1/Products Get paginated list (Output Cached: 30s)
GET /api/v1/Products/{id} Get product by ID (Output Cached: 60s)
POST /api/v1/Products Create a new product
PUT /api/v1/Products/{id} Update an existing product
DELETE /api/v1/Products/{id} Delete a product

Background Jobs (Requires Authentication)

Method Endpoint Description
POST /api/v1/Jobs/fire-and-forget Enqueue an immediate background task
POST /api/v1/Jobs/delayed Schedule a delayed background task
POST /api/v1/Jobs/recurring Register a CRON-based recurring task
POST /api/v1/Jobs/recurring/trigger Trigger the daily recurring task immediately

Hangfire Dashboard: https://localhost:7253/hangfire

Authenticating in Scalar UI

  1. Open Scalar UI at https://localhost:{port}/scalar/v1
  2. Call POST /api/v1/Auth/login and copy the returned accessToken
  3. In Scalar UI, click Authentication โ†’ Bearer Token โ†’ paste your accessToken

Access tokens expire in 15 minutes by default. Use POST /api/v1/Auth/refresh to get a new pair without logging in again.


๐Ÿณ Docker Support

# Build and start all services (API + SQL Server)
docker-compose up -d

# Stop and remove containers
docker-compose down

The API will be available at http://localhost:8080.


๐Ÿงช Testing

# Run all tests
dotnet test

# Run with detailed output
dotnet test --logger "console;verbosity=detailed"

๐Ÿ”ง Configuration Reference

Key sections in appsettings.json:

{
  "ConnectionStrings": {
    "DefaultConnection":  "Server=localhost;Database=CleanArchitectureDb;Trusted_Connection=True;TrustServerCertificate=True;",
    "IdentityConnection": "Server=localhost;Database=CleanArchitectureIdentityDb;Trusted_Connection=True;TrustServerCertificate=True;",
    "HangfireConnection": "Server=localhost;Database=CleanArchitectureHangfireDb;Trusted_Connection=True;TrustServerCertificate=True;"
  },
  "Jwt": {
    "Secret": "your-very-strong-secret-key-min-32-chars",
    "Issuer": "CleanArchitecture",
    "Audience": "CleanArchitectureUsers",
    "AccessTokenExpiryMinutes": 15,
    "RefreshTokenExpiryDays": 7
  },
  "Cors": {
    "AllowedOrigins": ["http://localhost:3000", "https://localhost:5001"]
  },
  "RateLimiting": {
    "WindowSeconds": 60,
    "PermitLimit": 100,
    "Auth": {
      "WindowSeconds": 60,
      "PermitLimit": 10
    }
  },
  "Email": {
    "Host": "smtp.gmail.com",
    "Port": 587,
    "EnableSsl": true,
    "UserName": "your-email@gmail.com",
    "Password": "your-app-password",
    "From": "your-email@gmail.com",
    "DisplayName": "Clean Architecture App"
  }
}

Recommended environment variables for production overrides:

ConnectionStrings__DefaultConnection
ConnectionStrings__IdentityConnection
ConnectionStrings__HangfireConnection
Jwt__Secret
Email__Password

๐Ÿ“ Adding New Features

1. Create Entity (Domain Layer)

// src/Core/CleanArchitecture.Domain/Entities/YourEntity.cs
public class YourEntity : BaseAuditableEntity, ISoftDeletable
{
    public string Name { get; private set; } = string.Empty;

    public static YourEntity Create(string name) =>
        new YourEntity { Name = name };
}

2. Add Command & Handler (Application Layer)

// Command
public record CreateYourEntityCommand(string Name) : IRequest<Result<Guid>>;

// Handler
public class CreateYourEntityCommandHandler
    : IRequestHandler<CreateYourEntityCommand, Result<Guid>>
{
    private readonly IApplicationDbContext _context;

    public CreateYourEntityCommandHandler(IApplicationDbContext context)
        => _context = context;

    public async Task<Result<Guid>> Handle(CreateYourEntityCommand request, CancellationToken ct)
    {
        var entity = YourEntity.Create(request.Name);
        _context.YourEntities.Add(entity);
        await _context.SaveChangesAsync(ct);
        return Result<Guid>.Success(entity.Id);
    }
}

3. Configure Mapping (Application Layer)

Mapster is configured to auto-scan for IRegister implementations โ€” simply create the class and it will be picked up automatically.

// src/Core/CleanArchitecture.Application/Features/YourFeature/Mappings/YourEntityMapping.cs
public class YourEntityMapping : IRegister
{
    public void Register(TypeAdapterConfig config)
    {
        config.NewConfig<YourEntity, YourEntityDto>()
            .Map(dest => dest.CustomProperty, src => src.Calculation())
            .IgnoreNullValues(true);
    }
}

4. Create Controller (Presentation Layer)

[ApiController]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("1.0")]
[Authorize]
public class YourController : ControllerBase
{
    private readonly IMediator _mediator;

    public YourController(IMediator mediator) => _mediator = mediator;

    [HttpPost]
    public async Task<IActionResult> Create([FromBody] CreateYourEntityCommand command)
    {
        var result = await _mediator.Send(command);
        return result.IsSuccess ? Ok(result) : BadRequest(result);
    }
}

5. Add MassTransit Consumer (Messaging Layer)

Contoh: react terhadap Domain Event yang dipublish secara otomatis oleh MediatR Pipeline DomainEventPublishingBehaviour setelah entitas sukses tersimpan.

// src/Infrastructure/YourProject.Infrastructure.Messaging/Consumers/YourEntityCreatedConsumer.cs
public sealed class YourEntityCreatedConsumer : IConsumer<YourEntityCreatedEvent>
{
    private readonly IBackgroundJobClient _hangfire;
    private readonly ILogger<YourEntityCreatedConsumer> _logger;

    public YourEntityCreatedConsumer(IBackgroundJobClient hangfire, ILogger<YourEntityCreatedConsumer> logger)
    {
        _hangfire = hangfire;
        _logger = logger;
    }

    public Task Consume(ConsumeContext<YourEntityCreatedEvent> context)
    {
        _logger.LogInformation("Received: {Id}", context.Message.EntityId);

        // Handoff ke Hangfire untuk proses berat (retry-able, persistent)
        // _hangfire.Enqueue<INotificationService>(s =>
        //     s.SendCreatedNotificationAsync(context.Message.EntityId, CancellationToken.None));

        return Task.CompletedTask;
    }
}

Auto-discovery: MassTransit akan otomatis menemukan semua class IConsumer<T> di project Infrastructure.Messaging โ€” tidak perlu register manual. Dan setiap entitas yang didaftarkan event-nya via AddDomainEvent() akan dipublish otomatis tanpa kode tambahan di Handler Anda!

6. Switch Message Transport

Ubah satu baris di appsettings.json:

{
  "MassTransit": {
    "Transport": "RabbitMQ"  // InMemory | RabbitMQ | ActiveMQ
  }
}

Atau via environment variable:

MassTransit__Transport=RabbitMQ
MassTransit__RabbitMQ__Host=my-rabbit-server

๐Ÿ”’ Security Checklist (Before Production)

โš ๏ธ Do not deploy with default development settings.

  • Change JWT Secret โ€” Use a cryptographically strong secret (min 32 characters)
  • Update Connection Strings โ€” Use secure, dedicated production database credentials
  • Enable HTTPS โ€” Ensure TLS is properly configured and enforce HTTPS redirection
  • Restrict CORS Origins โ€” Allow only known, trusted origins
  • Review Password Policies โ€” Customize in Infrastructure.Identity/DependencyInjection.cs
  • Secure Hangfire Dashboard โ€” Restrict access to authenticated admin users only
  • Rotate Secrets Regularly โ€” Implement a secrets management strategy (e.g., Azure Key Vault)

๐Ÿ“š Architecture Overview

Layer Project Suffix Responsibility
Domain *.Domain Entities, value objects, domain events, business rules
Application *.Application Use cases, CQRS handlers, validators, interfaces, message contracts
Persistence *.Infrastructure.Persistence EF Core, DbContext, migrations, repositories
Identity *.Infrastructure.Identity ASP.NET Core Identity, JWT token service
Shared *.Infrastructure.Shared Cross-cutting services (email, datetime, background queue)
Messaging *.Infrastructure.Messaging MassTransit bus, consumers, transport configuration
WebAPI *.WebAPI REST controllers, middleware pipeline, DI configuration
WebUI *.WebUI Blazor Server interactive frontend

๐Ÿค Contributing

Contributions are very welcome! Please follow the steps below:

  1. Fork the repository
  2. Create your feature branch: git checkout -b feature/AmazingFeature
  3. Commit your changes: git commit -m 'feat: add amazing feature'
  4. Push to the branch: git push origin feature/AmazingFeature
  5. Open a Pull Request on GitHub

๐Ÿ“„ License

This project is licensed under the MIT License. See LICENSE for details.


๐Ÿ™ Acknowledgments


Built with โค๏ธ by MinimDev

  • net10.0

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

Version Downloads Last Updated
1.6.0 171 8/13/2026
1.5.3 285 5/26/2026
1.5.2 285 4/29/2026
1.5.1 398 4/17/2026
1.4.0 314 4/6/2026
1.3.1 312 4/1/2026
1.3.0 347 2/23/2026
1.2.0 337 2/20/2026
1.1.4 343 2/19/2026
1.1.3 342 2/19/2026
1.1.1 352 2/19/2026
1.1.0 332 2/19/2026
1.0.9 345 2/19/2026
1.0.8 348 2/18/2026
1.0.7 335 2/18/2026
1.0.6 335 2/18/2026
1.0.5 339 2/18/2026
1.0.4 337 2/18/2026
1.0.3 342 2/18/2026
1.0.2 332 2/18/2026
Loading failed

v1.6.0: Added MassTransit Message Bus with Auto-Publish MediatR Behaviour, transport switching (InMemory, RabbitMQ, ActiveMQ), and patched critical transitive vulnerabilities.