共通アーキテクチャ方針
本ドキュメントは、Java Spring Boot 実装における共通アーキテクチャ方針を定義する。 特定機能・特定フェーズに依存しない原則・規約を記載する。
関連ドキュメント
Section titled “関連ドキュメント”本ドキュメントと合わせて以下を参照すること。
| ドキュメント | 内容 |
|---|---|
| CodingConventions_Common.md | 共通コーディング規約 |
| AuthenticationSpecification_Common.md | 共通認証仕様 |
| 機能別アーキテクチャ方針(例:ArchitecturePolicy_Coordination_Sprint1.md) | 機能・フェーズ固有のパッケージ構成・APIパス設計等 |
本ドキュメントは、機能Aの Java Spring Boot 実装におけるアーキテクチャ方針を定義する。
Claude Code によるコード生成時は、本ドキュメントの内容を前提として、以下の成果物を生成すること。
- Handler(Primary Adapter)
- UseCase
- Domain Model(Entity・値オブジェクト)
- Port(Repositoryインターフェース・TransactionManagerインターフェース)
- Repository実装(Secondary Adapter)
- MyBatis Mapper(インターフェース + XML)
- Exception(ドメイン例外)
- 生成DTO(OpenAPIから自動生成)
- レスポンスMapper(ドメイン型 → 生成DTO変換)
- Unit Test / Integration Test の雛形
2. 技術スタック
Section titled “2. 技術スタック”本アーキテクチャが対象とする技術選定の指針を以下に示す。具体的なバージョン・製品名は機能別方針ドキュメントを参照すること。
| 区分 | 技術選定指針 |
|---|---|
| 言語 | Java(LTS版を使用する) |
| フレームワーク | Spring Boot(安定版を使用する) |
| Web | Spring Web |
| DB アクセス | SQL Mapper(XML マッパー形式を推奨) |
| DB | RDBMS(PostgreSQL系を使用する) |
| ビルドツール | Gradle(Kotlin DSL) |
| API 仕様 | OpenAPI 3.0.x(スキーマファースト) |
| コード生成 | openapi-generator(interfaceOnly) |
| JSON 処理 | Jackson 3 |
| Validation | Jakarta Bean Validation(Handler 層のみ) |
| テスト | JUnit 6 互換 / Mockito / Testcontainers / ArchUnit |
| ログ | SLF4J + 実装ライブラリ |
| コードフォーマット | Spotless(Google Java Format) |
| 静的解析 | Error Prone / NullAway |
| API Lint | Spectral(OAS) |
| SQL Lint | sqlfluff 等 |
| Null 安全 | JSpecify(@NullMarked / @Nullable) |
| Git Hooks | Lefthook(pre-commit)(フェーズごとの方針ドキュメントを参照) |
OpenAPI バージョンについて: 3.0.x を使用する。ASTM の OAS(運航調整プロトコル関連)が 3.0 系で記載されており、将来的な互換性(運航調整機能を ASTM へ提案・マージしていくこと等)を考えると 3.0 系で記述することが望ましいため。現時点では 3.1.x・3.2.x でなければ記述できない新機能が必要になる見込みはない(将来的に必要になった場合は、自社での開発を優先しつつ OAS のバージョンアップを検討する)。3.1.x は 3.0.x と記法が変わっている箇所があるため(exclusiveMinimum/exclusiveMaximum の値の型など)、3.0.x で記述する際は 3.1.x 系の記法を混在させないよう注意すること。
3. 基本アーキテクチャ
Section titled “3. 基本アーキテクチャ”ヘキサゴナルアーキテクチャ(Ports and Adapters)とクリーンアーキテクチャの共通原則(依存の逆転・ビジネスロジックのインフラ独立)を採用する(ADR-013)。
フレーミングはヘキサゴナルアーキテクチャの用語(Port/Adapter、Primary/Secondary)を使う。
[Primary Adapter(Handler)] HTTP Handler / gRPC Handler / MQTT Handler など ↓ UseCase を call する[UseCase 層] ユースケース単位の処理フロー ↓ Port(インターフェース)を call する[Domain 層] Entity / 値オブジェクト / Port I/F 定義 ↑ implements(Secondary Adapter が Port を実装する)[Infrastructure 層(Secondary Adapter)] PostgresRepository / ExternalAPIClient 等- Infrastructure → Domain(型依存)
- Handler → UseCase → Domain(呼び出し)
- Domain は Infrastructure を知らない
- UseCase は HTTP 固有の型(
HttpStatus等)を知らない
クリーンアーキテクチャ固有の Output Port / Presenter パターンは、本アーキテクチャの標準としては採用しない(MUST NOT ではない。ADR-013 参照)。UseCase はドメイン型を戻り値として返すことを基本とするが、採用した方が良いケースでは Output Port / Presenter パターンを採用してよい。
同様に、Handler 層がドメイン型に直接触れること自体も禁止しない。厳格なクリーンアーキテクチャでは UseCase 層が持つ Request Model への詰め替えを行い、ドメインオブジェクトの構築も UseCase 層で行うが、本アーキテクチャでは Handler 層で UseCase の戻り値(ドメイン型)を直接扱うことも許容する。UseCase から Handler への逆流ではないため、採用した方が良いケースでは Handler でドメイン型に触れてよい。
3.1 Handler 層(Primary Adapter)
Section titled “3.1 Handler 層(Primary Adapter)”Handler 層は、プロトコル(HTTP 等)とアプリケーションコアをつなぐアダプターである。
Handler 層では以下を行う。
- OpenAPI 生成インターフェース(
XxxApi)の実装 - リクエストの受け取りとプロトコル固有情報の吸収
- 形式バリデーション(OpenAPI Spec 由来・生成 DTO の
@Valid)の起動 - 意味的 parse(基本型 → ドメイン値オブジェクトへの変換)
- UseCase の呼び出し
- ドメイン型 → 生成 DTO へのレスポンス変換
- HTTP ステータスコードの返却
Handler 層では以下を行わない。
- 業務ロジック
- DB アクセス
@Transactionalによるトランザクション制御- ドメイン例外への HTTP ステータス設定(GlobalExceptionHandler に委ねる)
3.2 UseCase 層
Section titled “3.2 UseCase 層”UseCase 層は、ユースケース単位の処理フローを担当する。
UseCase 層では以下を行う。
- 1 ユースケース 1 クラス(
executeメソッド) - Domain オブジェクトの組み合わせによるビジネス要件の実現
- Port(インターフェース)経由での Infrastructure 呼び出し
- トランザクション境界の制御(
TransactionManager.executeを使用) - DB 参照が必要な整合性チェック(重複確認・存在確認・権限の事前チェック等)
- ドメイン例外の送出
UseCase 層では以下を行わない。
- HTTP 固有の処理(
HttpStatus・ResponseEntity・ヘッダー等) @Transactionalの使用- Infrastructure の具象クラスへの直接依存
@Component/@Serviceの付与(Spring の自動スキャンを使わない)- Observability の計装コード(
io.micrometer・io.opentelemetryの import 禁止)
3.3 Domain 層
Section titled “3.3 Domain 層”Domain 層は、ビジネスルールを担当する。
Domain 層では以下を行う。
- エンティティ・値オブジェクトの定義
- ビジネスルールの実装
- スマートコンストラクタによる不変条件の保証(Always-Valid)
sealed interfaceによる状態ごとの型分け- Port(Repository・TransactionManager 等のインターフェース)の定義
Domain 層では以下を行わない。
- Spring / MyBatis / Infrastructure への依存(
import禁止) @Entity・@Column等の ORM アノテーションの付与@NotNull・@Min等の Bean Validation アノテーションの付与- HTTP 固有の型への依存
- Port からの直接呼び出し(Port を call するのは UseCase の責務)
3.4 Infrastructure 層(Secondary Adapter)
Section titled “3.4 Infrastructure 層(Secondary Adapter)”Infrastructure 層は、Domain の Port を DB・外部 API 等の実装で満たす。
Infrastructure 層では以下を行う。
- Port インターフェースの実装
- MyBatis Mapper を用いた SQL 実行
- DB 行レコード(
XxxRecord)とドメイン型の相互変換 DataAccessExceptionをRepositoryException(ドメイン用語の例外)にラップ
Infrastructure 層では以下を行わない。
- 業務ロジック
- ドメイン型への DB 都合(行レコード・SQL)の漏洩
5. クラス命名規約
Section titled “5. クラス命名規約”クラス名は以下の規約に従う。
| 種別 | 命名規約 | 例 |
|---|---|---|
| Handler(Primary Adapter) | XxxHandler | FeatureAHandler |
| UseCase | XxxUseCase | CreateFeatureAUseCase |
| Domain Entity(状態なし) | XxxEntity など意味ある名称 | FeatureAEntity |
| Domain Entity(状態あり sealed) | XxxState / 状態ごとに型名を持つ | FeatureA.Draft / FeatureA.Approved |
| 値オブジェクト | 意味ある名称 | FeatureAId / FeatureARoute |
| Port(Repository I/F) | XxxRepository | FeatureARepository |
| Port(その他 I/F) | IXxx または XxxPort | TransactionManager |
| Repository 実装 | XxxRepositoryImpl | FeatureARepositoryImpl |
| MyBatis Mapper | XxxMapper | FeatureAMapper |
| DB 行レコード | XxxRecord | FeatureARecord |
| レスポンス変換 Mapper | XxxResponseMapper | FeatureAResponseMapper |
| ドメイン例外 | XxxException | FeatureANotFoundException |
| Config | XxxConfig | AppConfig |
| Test | XxxTest | CreateFeatureAUseCaseTest |
6. Domain Model 方針
Section titled “6. Domain Model 方針”6.1 ドメインエンティティ・値オブジェクト
Section titled “6.1 ドメインエンティティ・値オブジェクト”Domain は DB・HTTP などのインフラに一切依存しない。
Domain では以下を定義する。
- ビジネスルール・不変条件(スマートコンストラクタで保証)
- 状態遷移ロジック(
sealed interface+recordによる状態ごとの型分け) - Port インターフェース(
domain.portパッケージに定義)
Domain では以下を行わない。
@Entity・@Column等の ORM アノテーションの付与@NotNull・@Min等の Jakarta Bean Validation アノテーションの付与- Spring・MyBatis の
import
6.2 状態を持つ集約(sealed interface パターン)
Section titled “6.2 状態を持つ集約(sealed interface パターン)”状態遷移が存在する集約は sealed interface + record で状態ごとに型を分け、不正な遷移をコンパイル時に防ぐ。
// Domain 層: 状態ごとにクラスを分けるsealed interface FeatureAEntity permits FeatureAEntity.Draft, FeatureAEntity.Submitted, FeatureAEntity.Approved, FeatureAEntity.Rejected {
record Draft(FeatureAId id, FeatureAData data) implements FeatureAEntity { public Submitted submit() { return new Submitted(id, data); } // approve() は存在しない → コンパイルエラーで不正呼び出しを防ぐ }
record Submitted(FeatureAId id, FeatureAData data) implements FeatureAEntity { public Approved approve() { return new Approved(id, data); } public Rejected reject(String reason) { return new Rejected(id, data, reason); } } // ...}6.3 値オブジェクトのスマートコンストラクタ
Section titled “6.3 値オブジェクトのスマートコンストラクタ”値オブジェクトはスマートコンストラクタで生成時に不変条件を検証し、不正値を存在させない(Always-Valid)。
ParseResult<T> 型(sealed interface + record)を用いて parse 結果を型として後続処理に引き渡す。
// Domain 層: ParseResult 型sealed interface ParseResult<T> permits ParseResult.Ok, ParseResult.Err { record Ok<T>(T value) implements ParseResult<T> {} record Err<T>(String message) implements ParseResult<T> {}}
// 値オブジェクト例(record で実装)record FeatureAId(String value) { // コンパクトコンストラクタ: 内部不変条件の安全網(直接 new される場合も防御) FeatureAId { if (value == null || value.isBlank()) throw new IllegalArgumentException("IDは空にできません"); }
// 推奨エントリポイント: ParseResult で parse 結果を型安全に後続処理へ引き渡す public static ParseResult<FeatureAId> parse(String raw) { if (raw == null || raw.isBlank()) return new ParseResult.Err<>("IDは空にできません"); return new ParseResult.Ok<>(new FeatureAId(raw)); }}6.4 生成 DTO(OpenAPI 由来)
Section titled “6.4 生成 DTO(OpenAPI 由来)”OpenAPI yaml から openapi-generator で生成した DTO は generated/ パッケージに配置する。
- 生成 DTO は Handler 層からのみ参照する(ArchUnit で強制)
- 生成コードは手編集禁止
- OAS を変更したら
./gradlew openApiSyncToSrcで再生成する - 生成コードは
srcにコミットし、ドリフトを CI が検査する
例外(横断的関心事の生成型の配置): RFC 9457 Problem Details 型(ProblemDetail・ValidationProblemDetail・FieldError 等)のように、複数の OpenAPI 定義(機能・audience)から共通で参照される横断的関心事の生成型に限り、generated/ 直下ではなく <root>.problem.generated.model のような専用パッケージに配置してよい。各 OpenAPI 定義からは schemaMappings 等でこの共通型にマッピングし、個別に再生成しない運用とする。この専用パッケージも「Handler 層からのみ参照する」という原則自体は変わらないが、ArchUnit の生成 DTO 検査ルールは現時点で generated.. パッケージのみを対象範囲としており、この専用パッケージまでは検査範囲に含まれていない。検査範囲の拡張は今後の課題とする。
6.5 DB 行レコード
Section titled “6.5 DB 行レコード”DB 行レコード(XxxRecord)は Infrastructure 層内にのみ存在する。
- Domain 層・UseCase 層・Handler 層に DB 行レコードを持ち込まない
- DB 行レコード ↔ ドメイン型の変換は Repository 実装クラス内で行う
7. Mapper 方針
Section titled “7. Mapper 方針”変換処理は層ごとに担当を分ける。
| 場所 | 変換方向 | 実装場所 |
|---|---|---|
| Handler 層 | ドメイン型 → 生成 DTO | handler.response.XxxResponseMapper |
| Infrastructure 層 | ドメイン型 → DB 行レコード、DB 行レコード → ドメイン型 | XxxRepositoryImpl |
8. トランザクション方針
Section titled “8. トランザクション方針”@Transactional は使用しない。
トランザクション境界は domain.port.TransactionManager(Port インターフェース)を使用して制御する。
// Port(domain.port に定義)interface TransactionManager { <T> T execute(Supplier<T> action); <T> T execute(TransactionOptions options, Supplier<T> action);}UseCase の execute() 全体が 1 トランザクション単位となる。
// UseCase でのトランザクション使用例return transactionManager.execute(() -> { var entity = repository.findByIdForUpdate(id).orElseThrow(...); return repository.save(entity.doSomething());});対象処理:
- 登録
- 更新
- 削除
- 複数テーブルをまたぐ更新
参照系処理では TransactionOptions.forReadOnly() を渡す。
return transactionManager.execute( TransactionOptions.forReadOnly(), () -> repository.findAll());Handler 層・Infrastructure 層では原則としてトランザクション制御を行わない。
9. 例外処理方針
Section titled “9. 例外処理方針”9.1 ドメイン例外
Section titled “9.1 ドメイン例外”ドメイン固有の例外は domain.exception パッケージに定義する。
ドメイン例外は HTTP ステータスコードを含まない。
例:
- 対象データが存在しない →
FeatureANotFoundException - 状態遷移不正 →
InvalidFeatureATransitionException - ビジネスルール違反 →
BusinessRuleException(継承して使う)
9.2 システム例外
Section titled “9.2 システム例外”Infrastructure 層の DB アクセス失敗は RepositoryException にラップする。
DataAccessException(Spring の DB 例外)は Infrastructure 層の外に漏らさない。
try { return mapper.findById(id).map(this::toDomain);} catch (DataAccessException e) { throw new RepositoryException("failed to find entity", e);}9.3 共通例外ハンドリング(RFC 9457 Problem Details)
Section titled “9.3 共通例外ハンドリング(RFC 9457 Problem Details)”例外は @RestControllerAdvice(GlobalExceptionHandler)を使用して一元的にハンドリングする。
エラーレスポンス形式は RFC 9457 Problem Details に準拠する。
{ "type": "https://example.com/problems/not-found", "title": "リソースが見つかりません", "status": 404, "detail": "指定されたIDが存在しません。id=xxx", "instance": "/utm/api/v1/featureA/xxx"}バリデーションエラー(422)には errors 配列を含める。
Handler ごとに try-catch を多用しない。
10. HTTPステータスコード方針
Section titled “10. HTTPステータスコード方針”API の HTTP ステータスコードは以下を基本とする。
| 処理結果 | HTTP ステータス |
|---|---|
| 正常取得 | 200 OK |
| 正常登録 | 201 Created |
| 正常更新 | 200 OK |
| 正常削除 | 204 No Content |
| 入力エラー(形式・必須) | 400 Bad Request |
| 認証エラー | 401 Unauthorized |
| 認可エラー | 403 Forbidden |
| 対象なし | 404 Not Found |
| 競合エラー | 409 Conflict |
| ビジネスルール違反 | 422 Unprocessable Entity |
| サーバエラー | 500 Internal Server Error |
HTTP ステータスの設定は Handler 層(または GlobalExceptionHandler)の責務であり、UseCase・Domain では設定しない。
11. バリデーション方針
Section titled “11. バリデーション方針”入力値チェックは以下の 4 段階で実施する。
HTTP Request(未検証) │ ▼ [Handler / Primary Adapter] │ ① OpenAPI Spec 由来のバリデーション(型・必須・フォーマット) │ ② 構文 parse: Jackson による基本型変換(String → LocalDate 等) │ ③ 意味的 parse: 基本型 → ドメイン値オブジェクトへの変換 │ ▼ [UseCase 層] │ ④ インフラ参照が必要な整合性チェック(重複確認・存在確認等) │ ▼ [Domain 層] ← ここに来る値は常に valid ⑤ 値オブジェクトのスマートコンストラクタ(意味的制約) ⑥ Entity のビジネスルール・状態遷移の妥当性11.1 Handler 層のバリデーション
Section titled “11.1 Handler 層のバリデーション”- ① 型・必須・フォーマット・パターン:OAS に記述し、生成 DTO の
@NotNull・@Size・@Pattern等として実体化する - ② 構文 parse:OAS の
format(date・uuid等)で生成 DTO がその型を持ち、Jackson が parse する - ③ 意味的 parse:Handler メソッド内でドメイン値オブジェクトへ変換する
11.2 Domain 層のバリデーション(スマートコンストラクタ)
Section titled “11.2 Domain 層のバリデーション(スマートコンストラクタ)”値オブジェクトのコンストラクタ内で意味的制約を検証する。
// 値オブジェクトのコンパクトコンストラクタrecord FeatureAId(String value) { public FeatureAId { if (value == null || value.isBlank()) throw new InvalidFeatureAIdException(); }}ドメインオブジェクト(Entity・値オブジェクト)に @NotBlank・@NotNull・@Min 等の Bean Validation アノテーションを付与しない。
11.3 UseCase 層のバリデーション
Section titled “11.3 UseCase 層のバリデーション”DB 参照が必要な整合性チェックは UseCase 層で実施する。
例:
- 重複していないか
- 対象データが存在するか
- 利用者に操作権限があるか(DB 参照が必要な場合)
12. Repository 実装方針
Section titled “12. Repository 実装方針”Repository は MyBatis を使用する。
Port インターフェースは domain.port パッケージに定義する。
実装クラスは infrastructure.persistence.postgres パッケージに配置する。
// Port(domain.port に定義)public interface FeatureARepository { FeatureAEntity findById(FeatureAId id); Optional<FeatureAEntity> findByIdForUpdate(FeatureAId id); List<FeatureAEntity> findAll(); FeatureAEntity save(FeatureAEntity entity); void deleteById(FeatureAId id);}MyBatis Mapper インターフェースは infrastructure.persistence.postgres.mapper パッケージに配置する。
SQL は Mapper XML に記述する。パラメータは必ず #{} を使用し、文字列連結は禁止する。
複雑な検索条件は <sql> フラグメントで重複を避ける。
状態遷移・競合制御が必要な場合は findByIdForUpdate(SELECT FOR UPDATE)を使用する(ADR-019)。
15. 日時方針
Section titled “15. 日時方針”日時型は以下を使用する。
| 用途 | Java 型 |
|---|---|
| 日付 | LocalDate |
| 日時 | OffsetDateTime |
| 時刻 | LocalTime |
外部に出す日時(API レスポンス)は UTC 日時とする。
API レスポンスでは ISO 8601 形式(UTC)を使用する。
2026-06-29T01:00:00ZDB の timestamp 型とのマッピングは、DDL の定義を優先して決定する。
タイムゾーンの扱いは暗黙的な環境依存を避け、明示的に指定する。
17. ログ出力方針
Section titled “17. ログ出力方針”ログは SLF4J を使用する。
ログレベルは以下を基本とする。
| レベル | 用途 |
|---|---|
| ERROR | 処理継続不可のエラー |
| WARN | 業務上の警告、想定内の異常 |
| INFO | 処理開始、処理終了、主要な業務イベント |
| DEBUG | 開発時の詳細情報 |
セキュリティイベント(認証失敗、権限エラー等)を記録する。
UseCase 層では業務イベント(処理開始・処理終了・主要な状態変更)を INFO レベルで記録することを推奨する。UseCase への SLF4J ロギングは許容する(後述の計装制限とは別)。
ロギングによる顕著な性能低下・副作用を起こさない。
機密情報(パスワード・アクセストークン・リフレッシュトークン・API キー・秘密鍵・個人情報・認証ヘッダ)はログに出力しない。
Observability の計装配置
Section titled “Observability の計装配置”- Handler 層・Infrastructure 層のみに計装(メトリクス・トレース)を置く
- UseCase・Domain は
io.micrometer/io.opentelemetryを import しない(ArchUnit で強制)
18. セキュリティ方針
Section titled “18. セキュリティ方針”以下のアーキテクチャ原則を遵守する。
- 多層防御:複数のセキュリティ層を設ける
- 最小権限の原則:システム・ユーザー・プロセス等に必要な権限のみを付与する
- デフォルト拒否:認証が実装された場合は、明示的に許可されたもの以外は拒否する(認証未実装のフェーズでの適用方法は機能別方針ドキュメントを参照すること)
- セキュリティ設計の単純化:複雑さは脆弱性が忍び込む確率を上げる
入出力の処理
Section titled “入出力の処理”- すべての外部入力(ユーザー入力・API・ファイルアップロード等)は信頼できないものとして検証する
- 拒否リスト方式は原則使わない
- 暗黙的な環境依存(ロケール・タイムゾーン・環境変数等)を避ける
- 出力先のコンテキストに応じて適切にエスケープ処理を実施する
- 詳細なエラー情報(スタックトレース・内部情報等)をユーザーには表示しない
- 不正な状態を検知したならば速やかに失敗させる
認証・認可の詳細は AuthenticationSpecification_Common.md を参照すること。
19. 設定ファイル方針
Section titled “19. 設定ファイル方針”設定値は application.yaml に定義する。
環境依存の値は、基本的に環境変数経由で設定する。プロファイル分離(application-dev.yaml 等)を使用することは禁止しないが、本番・ステージング等の機密性の高い環境では環境変数を優先する。
機密情報は Git 管理対象に含めない。
機能固有の設定対象リストは各機能の方針ドキュメントを参照すること。
20. テスト方針
Section titled “20. テスト方針”テストは以下の方針で作成する。
20.1 UseCase ユニットテスト
Section titled “20.1 UseCase ユニットテスト”UseCase 層の業務ロジックを中心に単体テストを作成する。
使用技術:
- JUnit 6
- Mockito(Repository の Mock)
- NoopTransactionManager(テスト用の TransactionManager 実装)
テスト対象:
- 正常系
- 入力不正
- 対象データなし
- 重複エラー
- 状態遷移不正
- Repository 例外発生時
// UseCase テストにおける NoopTransactionManager の使い方TransactionManager noopTx = new TransactionManager() { @Override public <T> T execute(Supplier<T> action) { return action.get(); }};20.2 Handler テスト
Section titled “20.2 Handler テスト”Handler 層は MockMvc を使用してテストする。
確認対象:
- HTTP ステータス
- レスポンス JSON(Problem Details 形式含む)
- バリデーションエラー
- UseCase 呼び出し
20.3 Infrastructure テスト
Section titled “20.3 Infrastructure テスト”Repository 実装・MyBatis Mapper は以下を確認する。
- BoundSql 検証(
ON CONFLICT・FOR UPDATEの有無等) - Testcontainers を用いた実 DB でのテスト
20.4 統合テスト
Section titled “20.4 統合テスト”@SpringBootTest(webEnvironment = RANDOM_PORT) + Testcontainers + RestClient で統合テストを行う。
H2 Database によるインメモリテストを禁止するわけではない。PostGIS 等の PostgreSQL 固有機能を使用しない範囲や開発初期の簡易検証では H2 を使用してよい。
20.5 アーキテクチャテスト
Section titled “20.5 アーキテクチャテスト”ArchUnit による層依存の強制を行う。
確認対象:
- Domain が Spring・MyBatis・Infrastructure を参照していないこと
- UseCase が HTTP 固有の型を使用していないこと
- UseCase・Domain に
@Transactionalが使用されていないこと - UseCase・Domain が
io.micrometer・io.opentelemetryを import していないこと - generated コードが Handler 層からのみ参照されていること
21. OpenAPI との対応方針(スキーマファースト)
Section titled “21. OpenAPI との対応方針(スキーマファースト)”API 仕様はスキーマファーストで管理する(ADR-010)。
1. docs/openapi/*.yaml に OpenAPI 仕様を定義する2. ./gradlew openApiSyncToSrc で generated/ 以下にコードを生成する3. Handler は生成された XxxApi インターフェースを implements するOpenAPI yaml に定義された以下の内容を生成コードに反映する。
- path
- HTTP method
- requestBody
- parameters
- responses
- schema
- required
- nullable
- format
- minLength / maxLength
- pattern
- example
生成コードは手編集禁止。CI でドリフトを検査する。
OpenAPI 定義と本アーキテクチャ方針が矛盾する場合は、以下の優先順位とする。
- 業務仕様書
- OpenAPI yaml
- DB create SQL
- 本アーキテクチャ方針
- Claude Code の判断
22. DB create SQL との対応方針
Section titled “22. DB create SQL との対応方針”DB create SQL に定義された以下の内容を MyBatis Mapper XML および DB 行レコードに反映する。
- テーブル名
- カラム名
- データ型
- NOT NULL 制約
- UNIQUE 制約
- 主キー
- 外部キー
- インデックス
- デフォルト値
DB 行レコード(XxxRecord)のカラム定義は DB create SQL を正とする。
Domain Entity のカラム定義は DB create SQL を正とする。
OpenAPI 上の項目名と DB カラム名が異なる場合は、Repository 実装内または ResponseMapper で変換する。
23. API バージョニング方針
Section titled “23. API バージョニング方針”- API は URI パス方式でバージョニングする。バージョン番号は整数とする。
- 内部 API と外部 API はパスレベルで分離する。
- 基本パスは
<base-path>/api/v1とする。<base-path>は現時点ではアプリケーション自体には設定しない(Spring 側のserver.servlet.context-pathは追加しない)。将来リバースプロキシ・API Gateway 等のインフラ層でプレフィックスを付与する可能性に備えて表記上残す。 - 内部 API と外部 API の分離は
<base-path>/api/v1/internal/...のようにパスの追加セグメントで表現する。 - 例外: 対向先が他社 UTM(USS)となる API(他社との合意済みプロトコル、例: 運航調整機能の ASTM 準拠 API)は、上記の
<base-path>/api/v1規則の対象外とし、当該プロトコル仕様のパス(例:/uss/v1/...)をそのまま用いてよい。 - 上記に基づく具体的なパス設計(機能名の付与位置等)は機能別方針ドキュメントを参照すること。