Foundation
Development Guidelines

アーキテクチャ

バックエンドのクリーンアーキテクチャ4層構成のルール。

目的

AIが実装時にアーキテクチャに違反したコードを書かないようにする。また、レビュー時にアーキテクチャに違反したコードを検出する。

レイヤー構成

クリーンアーキテクチャに基づく4層構成である。

API → UseCase → Domain ← Infrastructure
  • Domain層は他のレイヤーに依存しない
  • Infrastructureは Domainのインターフェースを実装する(依存性逆転)

各層の責務

Domain層

ビジネスの本質を表現する。フレームワークや外部技術に一切依存しない。

UseCase層

アプリケーション固有の操作を実行する。Domain層のエンティティとRepositoryインターフェースを組み合わせてロジックを実行する。

Infrastructure層

技術的な詳細を実装する。Domain層で定義されたRepositoryインターフェースの具体的な実装を提供する。

API層

外部とのインターフェースを担う。クライアントからのリクエストを受け取り、UseCaseに委譲する。ビジネスロジックを持たない。

ルール

Domain層

エンティティ

  • クラスで定義する
  • constructorは private にする。生成経路を create() / reconstruct() に限定する
  • create() は新規作成用。ビジネスルール(初期値の設定など)を強制する。idcreatedAt はUseCaseから渡す
  • reconstruct() はDBからの復元用。全フィールドをそのまま受け取る
  • フィールドは readonly で公開する
  • constructor内でValibotスキーマによるランタイム検証を行う
  • update() メソッドは新しいインスタンスを返す(不変パターン)

ID

  • domain/id.tsgenerateId() で生成する(nanoid)
  • UUIDは使わない

Repository

  • インターフェース(interface)として定義する
  • メソッド名は操作の意図を明確にする(create / update / findById / findAll

UseCase層

  • クラスとして定義し、execute() メソッドで実行する
  • 1クラス1操作を原則とする
  • コンストラクタでRepositoryインターフェースを受け取る(コンストラクタインジェクション)
  • 入力スキーマはUseCaseがValibotで定義・exportする。API層はそのスキーマをimportしてバリデーションに使う
  • 更新系はLoad-Mutate-Saveパターンで実装する
  • execute() の戻り値はDTO(plainなtype)で返す。Domain Entityをそのまま返さない
  • DTOは usecase/{domain}/{domain}-dto.tsXxxDto 型と toXxxDto 変換関数を定義する

Infrastructure層

  • di/container.ts でUseCaseとその依存を組み立てる
  • Repository実装は infrastructure/ 配下に置く
  • DBの行からエンティティへの変換は toDomain ヘルパーで reconstruct() を使う

API層

  • tRPCルーターはUseCaseを呼び出すだけ。ビジネスロジックを持たない
  • ドメインエラーから TRPCError への変換は trpc.ts のmiddlewareが行う
  • ルーター内でエラーをキャッチしない。エラー変換はmiddlewareに一任する

エラーハンドリング

Domain層

  • ビジネスルール違反は DomainError のサブクラスをthrowする
  • ドメイン固有のエラークラスは作らず、汎用エラー(NotFoundError, ValidationError, AlreadyExistsError など)を全ドメインで使い回す

UseCase層

  • Domain層のエラーはキャッチせず、そのまま上位に伝播させる
  • UseCase固有のエラーが必要な場合も DomainError のサブクラスとして定義する

Infrastructure層

  • ドメインエラーをthrowしない
  • データの不在は戻り値(null, 空配列など)で表現し、UseCase層に判断を委ねる
  • 技術的な障害(DB接続エラー等)はそのまま上位に伝播させる

API層

  • trpc.ts のmiddlewareが DomainError のサブクラスを検出し、適切なコードの TRPCError に変換する

ディレクトリ構成

server/
├── api/
│   ├── trpc.ts              # tRPC初期化・ドメインエラー変換middleware
│   ├── index.ts             # appRouterの定義
│   └── routers/             # 各ドメインのルーター
├── usecase/
│   └── {domain}/            # ドメインごとにディレクトリを分ける
├── domain/
│   ├── id.ts                # ID生成(nanoid)
│   ├── error/               # ドメインエラー
│   └── {domain}/            # エンティティ + Repositoryインターフェース
└── infrastructure/
    ├── di/                  # DIコンテナ
    └── {impl}/              # Repository実装

On this page