This guide provides an overview of adding new features to AppBlueprint using Clean Architecture and Domain-Driven Design principles.
📚 Definitions​
Domain-Driven Design Components​
- Entity: Core domain objects with unique identity
- DTO (Data Transfer Objects)
- Request DTOs: API input models
- Response DTOs: API output models
- Interfaces: Contracts defining service behaviors
- Services: Business logic implementation
- Repositories: Data persistence abstractions
- Database
- Migrations: Version-controlled schema changes
- Contexts: Entity Framework DbContext configurations
📁 File Structure​
├─ .github # GitHub workflows
├─ Code # Application source code
│ ├─ AppBlueprint # SaaS Blueprint projects
│ ├─ ApiService # .NET API (REST API)
│ ├─ AppGateway # .NET API Gateway with YARP proxy
│ ├─ AppHost # .NET Aspire AppHost
│ ├─ DeveloperCli # .NET CLI for developers
│ ├─ ServiceDefaults # .NET Aspire service defaults
│ ├─ Tests # .NET tests (unit, integration, architecture, bunit)
│ ├─ Web # .NET Blazor server web app
│ ├─ Shared-Modules # Clean Architecture shared modules
│ ├─ Api.Client.Sdk # .NET architecture tests
│ ├─ Application # .NET architecture tests
│ ├─ Contracts # .NET architecture tests
│ ├─ Domain # .NET architecture tests
│ ├─ Infrastructure # .NET architecture tests
│ ├─ Presentation.ApiModule # .NET architecture tests
│ ├─ SharedKernel # .NET Aspire shared kernel
│ ├─ UiKit # .NET architecture tests
Development Process​
Adding a new feature typically involves these steps in order:
1. Domain Layer - Define Business Logic​
Create your entities, value objects, and business rules.
- What: Domain entities with strongly-typed IDs, business methods, enums
- Where:
Shared-Modules/AppBlueprint.Domain/Entities/ - Why: Encapsulate business logic, ensure type safety
📖 Detailed Guide: Adding Domain Entities
2. Infrastructure Layer - Data Access​
Implement repositories for data persistence.
- What: Repository interfaces and implementations using EF Core
- Where:
Shared-Modules/AppBlueprint.Infrastructure/Repositories/ - Why: Abstract database operations, testable data access
📖 Detailed Guide: Adding Repositories
3. Presentation Layer - API Endpoints​
Expose your feature through REST APIs.
- What: API Controllers with DTOs, validation, error handling
- Where:
Shared-Modules/AppBlueprint.Presentation.ApiModule/Controllers/ - Why: Provide external interface, protect internal implementation
📖 Detailed Guide: Creating API Controllers
4. UI Layer - User Interface (Optional)​
Build Blazor components for user interaction.
- What: Blazor components with Tailwind CSS
- Where:
AppBlueprint.Web/Components/ - Why: User-friendly interface for your feature
📖 Detailed Guide: Creating Blazor Components
5. Tests - Quality Assurance​
Write comprehensive tests for your feature.
- What: Unit, integration, and API tests
- Where:
AppBlueprint.Tests/Features/ - Why: Ensure correctness, prevent regressions
📖 Detailed Guide: Writing Tests
Quick Example: Project Management Feature​
Here's what implementing a complete "Project" feature looks like:
| Layer | Implementation |
|---|---|
| Domain | Project entity with ProjectId, Archive(), Activate() methods |
| Infrastructure | IProjectRepository with GetByTeamIdAsync(), AddAsync(), etc. |
| Presentation | ProjectController with GET, POST, PUT, PATCH, DELETE endpoints |
| UI | ProjectList.razor and ProjectForm.razor with Tailwind CSS styling |
| Tests | Unit tests for domain logic, integration tests for repository |
Architecture Layers​
AppBlueprint follows Clean Architecture with these layers:
┌─────────────────────────────────────────┐
│ Presentation Layer │ ← API Controllers, Blazor Pages
│ (Web, ApiService, ApiModule) │
└──────────────────┬──────────────────────┘
│
┌──────────────────▼──────────────────────┐
│ Application Layer │ ← Use Cases, DTOs, Interfaces
│ (Commands, Queries, Services) │
└──────────────────┬──────────────────────┘
│
┌──────────────────▼──────────────────────┐
│ Domain Layer │ ← Business Logic, Entities
│ (Entities, Value Objects, Enums) │
└──────────────────┬──────────────────────┘
│
┌──────────────────▼──────────────────────┐
│ Infrastructure Layer │ ← Data Access, External APIs
│ (DbContext, Repositories, Services) │
└──────────────────────────────────────────┘
Key Principle: Dependencies point inward. Domain layer has no dependencies.
Best Practices Checklist​
Before submitting your feature:
- ✅ Use strongly-typed IDs (no
stringorGuidfor entity IDs) - ✅ Implement factory methods for entity creation
- ✅ Keep business logic in domain entities
- ✅ Use repository pattern for data access
- ✅ Write tests for all business logic
- ✅ Add XML documentation comments
- ✅ Use proper null checking (
is null,ThrowIfNull) - ✅ Include cancellation tokens in async methods
- ✅ Return appropriate HTTP status codes
- ✅ Validate input at API boundaries
Common Patterns​
Strongly-Typed IDs​
public readonly record struct ProjectId
{
public Ulid Value { get; }
public static ProjectId NewId() => new(Ulid.NewUlid());
}
Factory Methods​
public static Project Create(string name, TeamId teamId)
{
ArgumentException.ThrowIfNullOrEmpty(name);
return new Project { Id = ProjectId.NewId(), Name = name, TeamId = teamId };
}
Repository Interface​
public interface IProjectRepository
{
Task<Project?> GetByIdAsync(ProjectId id, CancellationToken ct = default);
Task AddAsync(Project project, CancellationToken ct = default);
}
API Controller​
[HttpGet("{id}")]
public async Task<ActionResult<ProjectDto>> GetProject(string id)
{
if (!ProjectId.TryParse(id, out var projectId))
return BadRequest("Invalid ID");
var project = await _repository.GetByIdAsync(projectId);
return project is null ? NotFound() : Ok(ToDto(project));
}
Development Workflow​
- Plan - Identify entities, relationships, and use cases
- Domain - Create entities with business logic
- Database - Configure EF Core, create migration
- Repository - Implement data access layer
- API - Create controllers and DTOs
- Test - Write comprehensive tests
- UI - Build Blazor components (if needed)
- Review - Run tests, check code quality
- Deploy - Merge PR, deploy changes
Getting Help​
- Detailed Guides - Click the links above for step-by-step instructions
- Code Examples - Check existing features:
TodoEntity,TeamEntity - GitHub Discussions - Ask questions at saas-factory-labs/Saas-Factory
Next Steps​
Start with the domain layer:
Or jump to a specific guide: