Skip to content
bitzorcas
EN

Guide

Add a module

How to add a new platform module — five-piece module suite, Vertical Slice endpoints, repository, domain entities, and service layer.

Last updated

This guide walks through creating a new platform module following BitzOrcas’s five-piece module suite pattern.

Module structure

A BitzOrcas module consists of:

Platform.Application/
└── {ModuleName}/
├── {Module}Service.cs → Business logic
├── I{Module}Repository.cs → Repository port
├── I{Module}EventPublisher.cs → Event publishing port
├── I{Module}AuditSink.cs → Audit port
├── InMemory{Module}Repository.cs → Test/Shell default
└── Null{Module}EventPublisher.cs → No-op default
SaaS.Contracts/
└── {ModuleName}/ → Integration event DTOs
Infrastructure.SqlSugar/
└── {ModuleName}/
├── {Module}PlatformDependencyInjection.cs
└── SqlSugar{Module}Repository.cs
Infrastructure.Persistence.Models/
└── {ModuleName}/
└── {Module}Entity.cs → Persistence model
Api/
├── Endpoints/
│ └── {Module}Endpoints.cs → Minimal API endpoints
│ └── {Request}Dto.cs → Request DTOs

Step-by-step

1. Define the entity

// Infrastructure.Persistence.Models/{ModuleName}/
public class TodoEntity : TenantSoftDeleteEntityBase
{
[SugarColumn(Length = 200)]
public string Title { get; set; }
public bool IsCompleted { get; set; }
}

2. Register in PersistenceModelRegistry

Add the entity to PersistenceModelRegistry so SqlSugar auto-creates the table.

3. Create the service port

// Platform.Application/{ModuleName}/
public interface ITodoRepository
{
Task<IReadOnlyList<Todo>> GetAllAsync(TenantId tenantId, CancellationToken ct);
Task<Todo?> GetByIdAsync(Guid id, CancellationToken ct);
Task<Todo> CreateAsync(TenantId tenantId, string title, CancellationToken ct);
}

4. Implement the service

public class TodoService
{
public async Task<Todo> CreateAsync(TenantId tenantId, string title, CancellationToken ct)
{
// Business logic here
}
}

5. Create Minimal API endpoints

public static class TodoEndpoints
{
public static void MapTodoEndpoints(this IEndpointRouteBuilder app)
{
var group = app.MapGroup("/api/todos")
.RequireAuthorization();
group.MapPost("/", async (...) => ...);
group.MapGet("/", async (...) => ...);
}
}

6. Register in DI

Add to PersistenceRegistration and EndpointMap.

See also