ワンクリックで
clean-architecture-guide
Modular Monolith + Clean Architecture の設計ガイド。新しいモジュールの作成、画面の実装、機能追加を行う際には、必ずこのスキルを参照して従ってください。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Modular Monolith + Clean Architecture の設計ガイド。新しいモジュールの作成、画面の実装、機能追加を行う際には、必ずこのスキルを参照して従ってください。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Office ドキュメント(Excel / PowerPoint 等)の設計書を解析するためのガイド。設計書の内容を読み取り・理解する際には、必ずこのスキルを参照して従ってください。
Provides up-to-date information about ASP.NET Core 10 and Blazor .NET 10 new features. Use when the user asks about Blazor .NET 10 capabilities, ASP.NET Core 10 features, OpenAPI, Minimal APIs, SignalR, or needs guidance on ASP.NET Core/Blazor .NET 10 specific features.
Provides up-to-date information about .NET 10 and C# 14 new features for C# developers. Use when the user asks about .NET 10 capabilities, C# 14 language features, ASP.NET Core 10 Blazor, EF Core 10, or needs guidance on .NET 10/C# 14 specific features.
| name | clean-architecture-guide |
| description | Modular Monolith + Clean Architecture の設計ガイド。新しいモジュールの作成、画面の実装、機能追加を行う際には、必ずこのスキルを参照して従ってください。 |
このスキルは、本プロジェクトにおける Modular Monolith + Clean Architecture の具体的な設計パターンとルールを定義します。
重要: このスキルに基づいてコード編集・生成を行う際には、対応する言語・プラットフォームのスキル(例:
dotnet10、aspnetcore-blazor10等)を必ず併せて参照してください。最新の言語機能や API を正しく使用するために必要です。
新しいモジュールは以下の 3 プロジェクトで構成します。
src/Modules/<ModuleName>/
<ModuleName>.Domain/ # エンティティ、値オブジェクト(依存なし)
<ModuleName>.Application/ # UseCase、DTO、リポジトリインターフェース(Domain のみ依存)
<ModuleName>.Infrastructure/ # リポジトリ実装、外部サービス連携、DI 登録(Application に依存)
# 1. プロジェクト作成
dotnet new classlib -n <ModuleName>.Domain -o src/Modules/<ModuleName>/<ModuleName>.Domain --framework net10.0
dotnet new classlib -n <ModuleName>.Application -o src/Modules/<ModuleName>/<ModuleName>.Application --framework net10.0
dotnet new classlib -n <ModuleName>.Infrastructure -o src/Modules/<ModuleName>/<ModuleName>.Infrastructure --framework net10.0
# 2. ソリューションに追加
dotnet sln add src/Modules/<ModuleName>/<ModuleName>.Domain
dotnet sln add src/Modules/<ModuleName>/<ModuleName>.Application
dotnet sln add src/Modules/<ModuleName>/<ModuleName>.Infrastructure
# 3. プロジェクト参照設定
dotnet add src/Modules/<ModuleName>/<ModuleName>.Application reference src/Modules/<ModuleName>/<ModuleName>.Domain
dotnet add src/Modules/<ModuleName>/<ModuleName>.Infrastructure reference src/Modules/<ModuleName>/<ModuleName>.Application
# 4. Infrastructure に DI パッケージ追加
dotnet add src/Modules/<ModuleName>/<ModuleName>.Infrastructure package Microsoft.Extensions.DependencyInjection.Abstractions
# 5. Infrastructure に EF Core パッケージ追加
dotnet add src/Modules/<ModuleName>/<ModuleName>.Infrastructure package Microsoft.EntityFrameworkCore
# DB プロバイダーパッケージも追加(例: SqlServer, Sqlite, Npgsql 等)
# ⚠️ プロバイダーが不明な場合はユーザーに確認すること
dotnet add src/Modules/<ModuleName>/<ModuleName>.Infrastructure package Microsoft.EntityFrameworkCore.<Provider>
# 6. Web からの参照追加
dotnet add src/Web reference src/Modules/<ModuleName>/<ModuleName>.Application
dotnet add src/Web reference src/Modules/<ModuleName>/<ModuleName>.Infrastructure
# 7. 自動生成された Class1.cs を各プロジェクトから削除
Web ──→ Application (UseCase インターフェース、DTO のみ)
Web ──→ Infrastructure (DI 登録の拡張メソッド呼び出しのためのみ)
Infrastructure ──→ Application (リポジトリインターフェースの実装)
Application ──→ Domain (エンティティの利用)
Domain ──→ (依存なし)
| ルール | 説明 |
|---|---|
| Web から Domain エンティティを直接参照しない | Web 層は Application 層の DTO のみを使用する |
| Web から Repository を直接注入しない | Web 層は UseCase インターフェース経由でのみデータにアクセスする |
| ビジネスロジックを Web / Infrastructure に書かない | ビジネスロジックは Domain と Application のみに配置する |
| Application 層から Infrastructure を参照しない | Application 層はインターフェースを定義し、実装は Infrastructure 層が行う |
| リポジトリ内で SaveChangesAsync を呼ばない | SaveChangesAsync は UseCase が IUnitOfWork 経由で呼ぶ。1 UseCase = 1 トランザクション単位とする |
ビジネスの中核となるデータ構造を定義します。
namespace <ModuleName>.Domain;
public class <EntityName>
{
public int ID { get; set; }
public string Name { get; set; } = "";
// ビジネスルールに関わるメソッドもここに配置可能
}
Web 層に公開するデータ転送オブジェクトです。Domain エンティティの代わりにこれを使います。
namespace <ModuleName>.Application;
public record <EntityName>Dto(int ID, string Name);
データアクセスの抽象を定義します。UseCase 内部から使用され、Web 層には公開しません。
namespace <ModuleName>.Application;
public interface I<EntityName>Repository
{
Task<IReadOnlyList<Domain.<EntityName>>> GetAllAsync();
Task UpdateAsync(int id, ...);
}
Unit of Work の抽象を定義します。UseCase がトランザクションの完了(SaveChangesAsync)を制御するために使用します。
namespace <ModuleName>.Application;
public interface IUnitOfWork
{
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
}
ポイント:
IUnitOfWorkを Application 層に置くことで、UseCase は Infrastructure 層(DbContext)に直接依存せずにトランザクション管理を行えます。
Web 層が唯一依存する操作インターフェース です。1 つの操作 = 1 つの UseCase とし、ExecuteAsync メソッドを持ちます。
namespace <ModuleName>.Application.UseCases;
// インターフェース
public interface IGet<EntityName>sUseCase
{
Task<IReadOnlyList<<EntityName>Dto>> ExecuteAsync(string? searchText = null);
}
// 実装(Application 層内に配置)
public class Get<EntityName>sUseCase(I<EntityName>Repository repository) : IGet<EntityName>sUseCase
{
public async Task<IReadOnlyList<<EntityName>Dto>> ExecuteAsync(string? searchText = null)
{
var entities = await repository.GetAllAsync();
// フィルタリングなどのビジネスロジックはここで行う
var filtered = string.IsNullOrEmpty(searchText)
? entities
: entities.Where(e => e.Name.Contains(searchText, StringComparison.OrdinalIgnoreCase)).ToList();
// Domain → DTO 変換
return filtered.Select(e => new <EntityName>Dto(e.ID, e.Name)).ToList();
}
}
namespace <ModuleName>.Application.UseCases;
public interface IUpdate<EntityName>UseCase
{
Task ExecuteAsync(int id, ...);
}
public class Update<EntityName>UseCase(I<EntityName>Repository repository, IUnitOfWork unitOfWork) : IUpdate<EntityName>UseCase
{
public async Task ExecuteAsync(int id, ...)
{
await repository.UpdateAsync(id, ...);
// Unit of Work: UseCase の最後で変更を永続化
await unitOfWork.SaveChangesAsync();
}
}
データアクセスには Entity Framework Core を使用します。DbContext が Application 層の IUnitOfWork を実装し、Unit of Work パターンの役割を担います。トランザクション管理と変更追跡を一括して行います。
using <ModuleName>.Application;
using <ModuleName>.Domain;
using Microsoft.EntityFrameworkCore;
namespace <ModuleName>.Infrastructure;
public class <ModuleName>DbContext(DbContextOptions<<ModuleName>DbContext> options) : DbContext(options), IUnitOfWork
{
public DbSet<<EntityName>> <EntityName>s => Set<<EntityName>>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// エンティティの設定(テーブル名、キー、制約など)
modelBuilder.Entity<<EntityName>>(entity =>
{
entity.HasKey(e => e.ID);
// 必要に応じてプロパティの設定を追加
});
}
// SaveChangesAsync は DbContext に既に定義されているため、
// IUnitOfWork.SaveChangesAsync として自動的に公開される
}
リポジトリは DbContext を注入し、EF Core を使ってデータアクセスを行います。SaveChangesAsync() はリポジトリでは呼び出さず、UseCase 側で制御します。
using <ModuleName>.Domain;
using Microsoft.EntityFrameworkCore;
namespace <ModuleName>.Infrastructure;
public class <EntityName>Repository(<ModuleName>DbContext dbContext) : Application.I<EntityName>Repository
{
public async Task<IReadOnlyList<<EntityName>>> GetAllAsync()
{
return await dbContext.<EntityName>s.ToListAsync();
}
public async Task UpdateAsync(int id, ...)
{
var item = await dbContext.<EntityName>s.FindAsync(id);
if (item is not null)
{
// プロパティの更新(変更追跡により自動で検出される)
}
// SaveChangesAsync は UseCase 側で呼ぶ
}
}
モジュール単位で Add<ModuleName>Module() 拡張メソッドを提供します。
using <ModuleName>.Application;
using <ModuleName>.Application.UseCases;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace <ModuleName>.Infrastructure;
public static class <ModuleName>ServiceCollectionExtensions
{
public static IServiceCollection Add<ModuleName>Module(this IServiceCollection services, string connectionString)
{
// EF Core DbContext(Unit of Work)
services.AddDbContext<<ModuleName>DbContext>(options =>
options.UseSqlServer(connectionString)); // プロバイダーはプロジェクトに応じて変更
services.AddScoped<IUnitOfWork>(sp => sp.GetRequiredService<<ModuleName>DbContext>());
// Infrastructure(リポジトリ実装)
services.AddScoped<I<EntityName>Repository, <EntityName>Repository>();
// Application(UseCase)
services.AddScoped<IGet<EntityName>sUseCase, Get<EntityName>sUseCase>();
services.AddScoped<IUpdate<EntityName>UseCase, Update<EntityName>UseCase>();
return services;
}
}
Web 層は UseCase インターフェースと DTO のみ を使用します。
@page "/<route>"
@using <ModuleName>.Application
@using <ModuleName>.Application.UseCases
@rendermode InteractiveServer
<PageTitle>ページタイトル</PageTitle>
<h1>ページタイトル</h1>
@* UI コンポーネント *@
@code {
[Inject]
private IGet<EntityName>sUseCase Get<EntityName>sUseCase { get; set; } = default!;
[Inject]
private IUpdate<EntityName>UseCase Update<EntityName>UseCase { get; set; } = default!;
private IReadOnlyList<<EntityName>Dto> items = [];
protected override async Task OnInitializedAsync()
{
items = await Get<EntityName>sUseCase.ExecuteAsync();
}
}
using <ModuleName>.Infrastructure;
builder.Services.Add<ModuleName>Module(builder.Configuration.GetConnectionString("<ModuleName>")!);
新しいモジュールや機能を実装する際に確認してください。
Add<ModuleName>Module() を追加したかdotnet build が成功するか