TechSpherex.CleanArchitecture.Template
2.0.4
dotnet new install TechSpherex.CleanArchitecture.Template@2.0.4
ποΈ TechSpherex Clean Architecture Template
A production-ready Clean Architecture starter template for .NET 10. Ship features from day one β not boilerplate.
.NET 10 | Docker Ready | Native AOT Supported | MIT License
β¨ What's Included
- ποΈ Clean Architecture: 4-layer separation with enforced dependency rules.
- β‘ Native AOT: ~35 MB images, ~50ms startup.
- π’ Multi-Tenancy: Shared-table with auto query filters.
- π€ Skill Agents (AI): Pluggable LLM orchestrator pattern.
- π Full Observability: ELK Stack + Grafana Stack (Loki, Tempo, Prometheus).
- π HybridCache: L1 in-memory + L2 Redis with stampede protection.
π Quick Start
To use this template, install it via NuGet:
# 1. Install template
dotnet new install TechSpherex.CleanArchitecture.Template
# 2. Create new project
dotnet new ts-clean-arch -n MyProjectName
π οΈ Tech Stack
| Layer | Technology |
|---|---|
| Architecture | Clean Architecture (Domain β Application β Infrastructure β Api) |
| Runtime | .NET 10 / C# 14 |
| API | Minimal APIs with TypedResults |
| CQRS | Manual handlers β zero dependencies, zero licensing risk |
| Validation | FluentValidation 12 + Result pattern |
| Error Handling | ProblemDetails (RFC 9457) + global exception handler |
| Database | EF Core 10 + PostgreSQL |
| Caching | Microsoft HybridCache (L1 in-memory + L2 Redis) |
| Auth | ASP.NET Identity + JWT Bearer with refresh tokens |
| Multi-Tenancy | Shared-table strategy with EF Core global query filters |
| AI / Agents | Skill Agents pattern (pluggable β OpenAI, Ollama, Semantic Kernel) |
| API Docs | Scalar (modern OpenAPI UI) |
| Logging | Serilog 10 + Elasticsearch sink |
| Observability | .NET Aspire 13 + OpenTelemetry + ELK + Grafana |
| Containerization | Docker multi-stage build (JIT + Native AOT) |
| Testing | xUnit v3 + FluentAssertions + NSubstitute + NetArchTest |
| Solution | .slnx format + Central Package Management |
ποΈ Architecture
ββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Api Layer β
β Endpoints Β· Middleware Β· OpenAPI Β· Scalar β
ββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ
β depends on
ββββββββββββββββββββΌββββββββββββββββββββββββββββββββ
β Infrastructure Layer β
β EF Core Β· Identity Β· JWT Β· Cache Β· Tenancy β
ββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ
β depends on
ββββββββββββββββββββΌββββββββββββββββββββββββββββββββ
β Application Layer β
β CQRS Handlers Β· Validators Β· Agent Abstractions β
ββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ
β depends on
ββββββββββββββββββββΌββββββββββββββββββββββββββββββββ
β Domain Layer β
β Entities Β· Value Objects Β· Result Β· Interfaces β
ββββββββββββββββββββββββββββββββββββββββββββββββββββ
Dependency rule: Each layer only depends on the layer below it. Domain has zero external dependencies. Architecture tests enforce this at build time (9 tests).
π Project Structure
clean-architecture-template/
βββ src/
β βββ Domain/ # Entities, value objects, ITenantEntity
β βββ Application/ # CQRS handlers, validators, Skill Agents
β βββ Infrastructure/ # EF Core, Identity, JWT, caching, tenancy
β βββ Api/ # Minimal API endpoints, Scalar, middleware
β βββ AppHost/ # .NET Aspire orchestration
β βββ ServiceDefaults/ # OpenTelemetry, health checks, resilience
βββ tests/
β βββ Architecture.Tests/ # Dependency rule enforcement (9 tests)
β βββ Application.UnitTests/ # Handler unit tests (8 tests)
βββ docker/
β βββ elk/ # Logstash pipeline config
β βββ grafana/ # Loki, Tempo, Prometheus, dashboards
β βββ otel/ # OpenTelemetry Collector config
βββ docs/ # 9 comprehensive documentation guides
βββ Dockerfile # Multi-stage build (JIT + AOT)
βββ docker-compose.yml # Full stack with 4 profiles
βββ Directory.Build.props # .NET 10, C# latest, nullable
βββ Directory.Packages.props # Central Package Management
βββ CHANGELOG.md # Version history
βββ README.md
π Getting Started
Prerequisites
| Tool | Version | Required |
|---|---|---|
| .NET 10 SDK | 10.0+ | β |
| Docker Desktop | 4.x+ | β |
| IDE (VS 2026 / Rider / VS Code) | Latest | π‘ |
Option A β Run with Aspire (recommended for development)
cd src/TechSpherex.CleanArchitecture.AppHost
dotnet run
This automatically starts:
- PostgreSQL database with pgAdmin
- Redis cache with RedisInsight
- API with auto-migration and seed data
- Aspire Dashboard for OpenTelemetry (traces, metrics, logs)
Option B β Run with Docker Compose
β οΈ Important: All
docker composeanddocker buildcommands must be run from the project root directory (whereDockerfileanddocker-compose.ymlare located), not fromsrc/.
# Navigate to project root
cd clean-architecture-template
# Core: API + PostgreSQL + Redis
docker compose up -d --build
# Or explicitly specify the compose file
docker compose -f docker-compose.yml up -d --build
# + ELK Stack (Elasticsearch, Logstash, Kibana)
docker compose --profile elk up -d --build
# + Grafana Stack (Loki, Grafana, Tempo, Prometheus)
docker compose --profile grafana up -d --build
# + Dev Tools (pgAdmin, RedisInsight)
docker compose --profile tools up -d
# Combine multiple profiles
docker compose --profile elk --profile tools up -d --build
Option C β Standalone (without Aspire)
docker compose up -d postgres redis # Start database & cache
cd src/Api && dotnet run # Run the API locally
π Explore the API
| Service | URL | Credentials |
|---|---|---|
| Scalar API Docs | https://localhost:7200/scalar/v1 |
β |
| API (Docker) | http://localhost:8080 |
β |
| Aspire Dashboard | https://localhost:18888 |
β |
Default admin credentials (seeded automatically in Development):
- Email:
admin@TechSpherex.dev - Password:
Admin@123
Run Tests
cd src
dotnet build TechSpherex.CleanArchitecture.slnx
dotnet test TechSpherex.CleanArchitecture.slnx
π³ Docker & Native AOT
Build Docker Image
Run from the project root directory (same level as
Dockerfile):
# Standard build (JIT)
docker build -t techspherex-api .
# Native AOT build (smaller image, faster cold start)
docker build --build-arg PUBLISH_AOT=true -t techspherex-api:aot .
| Build | Image Size | Startup | Use Case |
|---|---|---|---|
| JIT (Alpine) | ~120 MB | ~500ms | General purpose, full compatibility |
| AOT (Alpine) | ~35 MB | ~50ms | Serverless, edge, cold-start-sensitive |
Docker Compose Profiles
| Profile | Command | Services Added |
|---|---|---|
| (core) | docker compose up -d |
API + PostgreSQL + Redis |
elk |
docker compose --profile elk up -d |
+ Elasticsearch + Logstash + Kibana |
grafana |
docker compose --profile grafana up -d |
+ Loki + Grafana + Tempo + Prometheus |
tools |
docker compose --profile tools up -d |
+ pgAdmin + RedisInsight |
π’ Multi-Tenancy
Shared-table multi-tenancy with automatic tenant isolation powered by EF Core global query filters.
# Send request with tenant header
curl -H "X-Tenant-Id: acme-corp" \
-H "Authorization: Bearer <token>" \
http://localhost:8080/api/todos
Tenant resolution order: X-Tenant-Id header β JWT tenant_id claim β Default tenant
Make Any Entity Tenant-Aware
Simply implement ITenantEntity β global query filters and auto-assignment are applied automatically:
public sealed class Product : AuditableEntity, ITenantEntity
{
public string Name { get; set; } = default!;
public decimal Price { get; set; }
public string TenantId { get; set; } = default!; // Auto-set on SaveChanges
}
π Multi-Tenancy Guide
π€ Skill Agents (AI)
Built-in provider-agnostic AI agent pattern that integrates with your domain logic:
curl -X POST http://localhost:8080/api/agents/execute \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"prompt": "Show me all my todos"}'
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/api/agents/execute |
POST | π | Execute with auto skill routing |
/api/agents/execute/{skillId} |
POST | π | Execute a specific skill by ID |
/api/agents/skills |
GET | π | List all available skills |
Key features:
- π Provider-agnostic β plug in OpenAI, Azure OpenAI, Ollama, or Semantic Kernel
- π Auto-discovery β skill agents are registered automatically via assembly scanning
- π¬ Multi-turn β conversation history support for contextual interactions
- π¦ Sample included β
TodoAgentSkilldemonstrates the full pattern
π Observability
Three levels of observability, from development to production:
Level 1 β Aspire Dashboard (Development)
Built-in with .NET Aspire. Shows structured logs, distributed traces, and metrics out of the box.
Level 2 β ELK Stack
docker compose --profile elk up -d --build
| Service | URL | Purpose |
|---|---|---|
| Kibana | http://localhost:5601 | Log visualization & search |
| Elasticsearch | http://localhost:9200 | Log storage & indexing |
| Logstash | tcp://localhost:31311 | Log pipeline processing |
- Index pattern:
techspherex-logs-* - Structured JSON logs with trace correlation and tenant context
Level 3 β Grafana Stack (Recommended for Production)
docker compose --profile grafana up -d --build
| Service | URL | Credentials |
|---|---|---|
| Grafana | http://localhost:3000 | admin / Admin@123 |
| Prometheus | http://localhost:9090 | β |
| Loki | http://localhost:3100 | β |
| Tempo | http://localhost:3200 | β |
Pre-built dashboard with 12 panels:
- Request rate Β· P99 latency Β· Error rate (5xx) Β· Active connections
- Memory usage Β· GC collections Β· Thread pool Β· Log volume
- HTTP status distribution Β· Recent logs
Cross-linked datasources: Loki (logs) β Tempo (traces) β Prometheus (metrics)
ποΈ Service Ports Reference
| Service | Port | Profile |
|---|---|---|
| API | 8080 |
core |
| PostgreSQL | 5432 |
core |
| Redis | 6379 |
core |
| Elasticsearch | 9200 |
elk |
| Logstash (Beats / TCP) | 5044 / 31311 |
elk |
| Kibana | 5601 |
elk |
| Grafana | 3000 |
grafana |
| Loki | 3100 |
grafana |
| Tempo | 3200 |
grafana |
| Prometheus | 9090 |
grafana |
| OTel Collector (gRPC / HTTP) | 4320 / 4321 |
elk / grafana |
| pgAdmin | 5050 |
tools |
| RedisInsight | 5540 |
tools |
π Sample: Todos Feature
The template includes a complete Todos CRUD feature as a reference implementation:
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/api/todos |
GET | π | Get all todos (paginated) |
/api/todos/{id} |
GET | π | Get a todo by ID |
/api/todos |
POST | π | Create a new todo |
/api/todos/{id} |
PUT | π | Update a todo |
/api/todos/{id}/complete |
PATCH | π | Mark as completed |
/api/todos/{id} |
DELETE | π | Delete a todo |
Adding a New Feature
Follow the Todos pattern β four simple steps:
- Domain β Add entity in
Domain/Entities/(implementITenantEntityif multi-tenant) - Application β Create feature folder in
Application/Features/YourFeature/with Command/Query + Handler + Validator - Infrastructure β Add EF Core configuration in
Infrastructure/Persistence/Configurations/ - Api β Add endpoint group in
Api/Endpoints/and register inProgram.cs
π§ Key Design Decisions
| Decision | Why |
|---|---|
| Manual CQRS over MediatR | Zero licensing risk β MediatR is commercial since v13. Learn the pattern, not a library. |
| Scalar over Swagger UI | Modern, faster, better DX. Swagger UI is legacy. |
| HybridCache over IMemoryCache | Built-in stampede protection, L1+L2 cache layers, automatic serialization. |
| Result pattern over exceptions | Explicit error handling, no hidden control flow, better API contracts. |
| Shared-table tenancy | Simple, no migration complexity, cost-efficient β good for most SaaS apps. |
| Interface-only agents | No LLM provider lock-in. Swap OpenAI, Ollama, or Semantic Kernel freely. |
| Assembly scanning DI over Scrutor | Zero dependencies β 40 lines of reflection replaces an entire NuGet package. |
| .slnx over .sln | XML-based, merge-friendly, smaller β the future of .NET solution files. |
π Education Roadmap
New to Clean Architecture? Follow this learning path from the innermost layer outward. Each step builds on the previous one β just like the dependency rule itself.
Step 1 Step 2 Step 3 Step 4 Step 5
ββββββββββ βββββββββββββββ ββββββββββββββββββ ββββββββββββ ββββββββββββββββ
β Domain β βββΆβ Application ββββΆβ Infrastructure ββββΆβ Api ββββΆβ DevOps / Ops β
ββββββββββ βββββββββββββββ ββββββββββββββββββ ββββββββββββ ββββββββββββββββ
Core Use Cases Implementations Endpoints Docker, CI/CD
Step 1 β ποΈ Domain Layer (start here!)
"Understand the heart of the application β the business rules."
| What to Read | Why |
|---|---|
Domain/Entities/ |
Learn how entities are modeled β TodoItem, AuditableEntity |
Domain/Interfaces/ |
See the contracts (e.g., IRepository<T>, ITenantProvider) β no implementation details here |
Domain/Common/Result.cs |
Understand the Result pattern β how errors are handled without exceptions |
Domain/Common/ITenantEntity.cs |
See how multi-tenancy is declared at the domain level |
π― Key takeaway: Domain has zero NuGet dependencies. It defines what the system does, not how.
Step 2 β π Application Layer
"Learn how use cases orchestrate domain logic."
| What to Read | Why |
|---|---|
Application/Features/Todos/ |
Full CQRS example β Commands, Queries, Handlers, Validators |
Application/Features/Todos/Commands/CreateTodo/ |
Follow a Command from DTO β Handler β Result |
Application/Features/Todos/Queries/GetTodos/ |
Follow a Query with pagination |
Application/Common/ |
Shared behaviors, interfaces, pagination models |
Application/Agents/ |
See how Skill Agent abstractions are defined (provider-agnostic AI) |
π― Key takeaway: Application depends only on Domain. It defines what happens when a user action occurs.
Step 3 β π§ Infrastructure Layer
"See how contracts become concrete implementations."
| What to Read | Why |
|---|---|
Infrastructure/Persistence/AppDbContext.cs |
EF Core setup, multi-tenant query filters, audit fields |
Infrastructure/Persistence/Configurations/ |
Entity-to-table mapping with Fluent API |
Infrastructure/Persistence/Repositories/ |
Generic Repository<T> implementing IRepository<T> from Domain |
Infrastructure/Identity/ |
ASP.NET Identity + JWT token generation |
Infrastructure/Caching/ |
HybridCache implementation (L1 + L2) |
Infrastructure/DependencyInjection.cs |
How everything is wired together β study this carefully |
π― Key takeaway: This is where the Dependency Inversion Principle shines β Infrastructure implements Domain interfaces.
Step 4 β π Api Layer
"Connect everything to the outside world."
| What to Read | Why |
|---|---|
Api/Program.cs |
The composition root β where all layers are registered |
Api/Endpoints/ |
Minimal API endpoint groups β see how requests flow in |
Api/Middleware/ |
Global exception handling, tenant resolution |
Api/Extensions/ |
Service registration helpers, OpenAPI config |
π― Key takeaway: Api is the entry point but contains zero business logic. It only maps HTTP β Application.
Step 5 β π³ DevOps & Orchestration
"Understand how the app runs in real environments."
| What to Read | Why |
|---|---|
AppHost/Program.cs |
.NET Aspire orchestration β how services are composed |
ServiceDefaults/ |
OpenTelemetry, health checks, resilience defaults |
Dockerfile |
Multi-stage build β JIT vs Native AOT |
docker-compose.yml |
Full stack with profiles (ELK, Grafana, tools) |
docker/ |
Logstash, Grafana, OTel Collector configs |
π― Key takeaway: DevOps config is separate from application code β clean boundary.
π§ͺ Bonus β Tests
"Read tests to verify your understanding."
| What to Read | Why |
|---|---|
tests/Architecture.Tests/ |
Must-read! 9 tests that enforce dependency rules between layers |
tests/Application.UnitTests/ |
See how handlers are tested in isolation with mocks |
π Suggested Reading Order (TL;DR)
1. Domain/Common/Result.cs β Understand error handling
2. Domain/Entities/TodoItem.cs β See a real entity
3. Domain/Interfaces/ β Learn the contracts
4. Application/Features/Todos/ β Follow a full CQRS feature
5. Infrastructure/DependencyInjection.csβ See how DI wires everything
6. Infrastructure/Persistence/ β See DB implementation
7. Api/Program.cs β The composition root
8. Api/Endpoints/TodoEndpoints.cs β HTTP β Application mapping
9. tests/Architecture.Tests/ β Verify the rules
10. Dockerfile + docker-compose.yml β Production deployment
π License
This project is licensed under the MIT License.
Use it, modify it, ship it. Attribution appreciated but not required.
-
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.