원클릭으로
modular-monolith
Use when structuring a modular monolith with module isolation and inter-module communication.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Use when structuring a modular monolith with module isolation and inter-module communication.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Use when adding caching to .NET APIs or optimizing response times with distributed cache, output cache, or ETags.
Use when configuring API response formats, custom formatters, or Accept header handling.
Use when building controller-based REST APIs with action results, model binding, or MediatR integration.
Use when creating RESTful API controllers with MediatR dispatch and ProblemDetails error responses.
Use when designing gRPC services, proto files, or adding gRPC-Web or JSON transcoding.
Use when building minimal API endpoints with route groups, filters, or TypedResults.
| name | modular-monolith |
| description | Use when structuring a modular monolith with module isolation and inter-module communication. |
| metadata | {"category":"architecture","agent":"dotnet-architect","when-to-use":"When designing modular monolith structure, module isolation, or inter-module communication"} |
src/
{Company}.{Domain}.WebApi/ # Host — composition root
{Company}.{Domain}.SharedKernel/ # Base classes, common interfaces
Modules/
Orders/
{Company}.{Domain}.Orders.Api/ # Public contracts (DTOs, interfaces)
{Company}.{Domain}.Orders.Core/ # Domain + Application logic
{Company}.{Domain}.Orders.Infrastructure/ # Data access, external services
Inventory/
{Company}.{Domain}.Inventory.Api/
{Company}.{Domain}.Inventory.Core/
{Company}.{Domain}.Inventory.Infrastructure/
Shipping/
{Company}.{Domain}.Shipping.Api/
{Company}.{Domain}.Shipping.Core/
{Company}.{Domain}.Shipping.Infrastructure/
// Modules/Orders/Orders.Api/IOrderModule.cs
namespace {Company}.{Domain}.Orders.Api;
// Only this project is referenced by other modules
public interface IOrderModule
{
Task<OrderSummaryDto?> GetOrderSummaryAsync(
Guid orderId, CancellationToken ct);
Task<bool> OrderExistsAsync(Guid orderId, CancellationToken ct);
}
public sealed record OrderSummaryDto(
Guid Id, string CustomerName, decimal Total, string Status);
// Modules/Orders/Orders.Core/OrderModule.cs
namespace {Company}.{Domain}.Orders.Core;
internal sealed class OrderModule(OrderDbContext db) : IOrderModule
{
public async Task<OrderSummaryDto?> GetOrderSummaryAsync(
Guid orderId, CancellationToken ct)
{
return await db.Orders
.Where(o => o.Id == orderId)
.Select(o => new OrderSummaryDto(
o.Id, o.CustomerName, o.Total, o.Status.ToString()))
.FirstOrDefaultAsync(ct);
}
public async Task<bool> OrderExistsAsync(
Guid orderId, CancellationToken ct)
{
return await db.Orders.AnyAsync(o => o.Id == orderId, ct);
}
}
// Modules/Orders/Orders.Infrastructure/OrderDbContext.cs
namespace {Company}.{Domain}.Orders.Infrastructure;
internal sealed class OrderDbContext(
DbContextOptions<OrderDbContext> options) : DbContext(options)
{
public DbSet<Order> Orders => Set<Order>();
public DbSet<OrderItem> OrderItems => Set<OrderItem>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("orders"); // schema isolation
modelBuilder.ApplyConfigurationsFromAssembly(
typeof(OrderDbContext).Assembly);
}
}
// SharedKernel/Events/IIntegrationEvent.cs
public interface IIntegrationEvent : INotification
{
Guid EventId { get; }
DateTimeOffset OccurredAt { get; }
}
// Orders module publishes
public sealed record OrderPlacedIntegrationEvent(
Guid OrderId,
string CustomerName,
decimal Total) : IIntegrationEvent
{
public Guid EventId { get; } = Guid.NewGuid();
public DateTimeOffset OccurredAt { get; } = DateTimeOffset.UtcNow;
}
// Inventory module handles
internal sealed class ReserveInventoryOnOrderPlaced(
InventoryDbContext db)
: INotificationHandler<OrderPlacedIntegrationEvent>
{
public async Task Handle(
OrderPlacedIntegrationEvent notification,
CancellationToken ct)
{
// Reserve inventory for the order
var reservation = InventoryReservation.Create(
notification.OrderId, notification.OccurredAt);
db.Reservations.Add(reservation);
await db.SaveChangesAsync(ct);
}
}
// Each module has a registration extension
// Modules/Orders/Orders.Infrastructure/OrderModuleRegistration.cs
public static class OrderModuleRegistration
{
public static IServiceCollection AddOrderModule(
this IServiceCollection services, IConfiguration configuration)
{
services.AddDbContext<OrderDbContext>(options =>
options.UseSqlServer(
configuration.GetConnectionString("Default"),
sql => sql.MigrationsHistoryTable(
"__EFMigrationsHistory", "orders")));
services.AddScoped<IOrderModule, OrderModule>();
services.AddMediatR(cfg =>
cfg.RegisterServicesFromAssembly(
typeof(OrderModule).Assembly));
return services;
}
}
// WebApi/Program.cs
builder.Services
.AddOrderModule(builder.Configuration)
.AddInventoryModule(builder.Configuration)
.AddShippingModule(builder.Configuration);
// SharedKernel/BaseEntity.cs
public abstract class BaseEntity
{
public Guid Id { get; protected set; } = Guid.NewGuid();
private readonly List<IDomainEvent> _domainEvents = [];
public IReadOnlyList<IDomainEvent> DomainEvents =>
_domainEvents.AsReadOnly();
protected void AddDomainEvent(IDomainEvent e) => _domainEvents.Add(e);
public void ClearDomainEvents() => _domainEvents.Clear();
}
// SharedKernel/IUnitOfWork.cs
public interface IUnitOfWork
{
Task<int> SaveChangesAsync(CancellationToken ct = default);
}
InternalsVisibleTo for tests only)Modules/ folder structure in the solution| Question | Answer |
|---|---|
| How do modules communicate? | Integration events (async) or module interfaces (sync reads) |
| Can modules share a database? | Same server is OK, but use separate schemas |
| What goes in SharedKernel? | Base classes, common interfaces, integration event contracts |
| When to split into microservices? | When independent deployment or scaling is needed |
| How to handle transactions across modules? | Eventual consistency via events; avoid distributed transactions |