Post
JA EN

みなと屋ホテルズのADR台帳——DDDファーストAIプロトの裏で並走する意思決定記録

みなと屋ホテルズのADR台帳——DDDファーストAIプロトの裏で並走する意思決定記録
  • 想定読者: DDD開発でADRをどう使うか(実践編)を読んで「実際にどんなADRが生まれるのか見たい」と思った人。ホテル予約システムの実装ウォークスルーを読んだ人なら、その「裏側」として読める
  • 前提知識: 実践編を先に読むことを推奨。また同シナリオの 実装ウォークスルー を読んでいると、各ADRがどのコードに対応するか分かって読みやすい
  • 所要時間: 約18分

概要

DDDファーストでAIにプロトを作らせる7フェーズのワークフローを、架空のホテルチェーン「みなと屋ホテルズ」で実装するウォークスルーを以前に公開した。Event Storming から本番化エンジニアの引き継ぎまでを追ったが、そこには描かれなかった並走物がある——ADR(Architecture Decision Record)の台帳だ。

各フェーズで、実は無数の設計判断が下されていた。「予約」を Reservation と Booking に割るか。ドメインを4つの境界に切るか。会計システムとの関係をどうするか。状態を型でどう表現するか。これらは 実践編 で論じた通り、AGENTS.md に書く「いまの制約(What)」とは別に、「なぜそうしたか・何を捨てたか(Why)」としてADRに残すべき決定だった。

本記事は、みなと屋ホテルズのプロジェクトで生まれた 10本のADR を、Michael Nygard のフォーマット(Status / Context / Decision / Consequences)1で1つずつ見せる。重要なのは、これが「きれいに書かれた成果物の展示」ではないことだ。境界を間違えて引き直す(ADR-002 を ADR-010 で supersede する)、定義を見落として後から足す(ADR-008)、AIが下書きしたADRを人が承認する(ADR-006)——実践編で論じた運用が、台帳の上でどう動くかを追う。台帳を時系列で読むと、このプロジェクトが何を考え、何を間違え、どう直したかの履歴がそのまま見える。それがADRの効用だ。

前提:ADRをどこに置き、AGENTS.md とどう棲み分けるか

役割4(AI環境整備エンジニア)が、プロジェクト開始時にADRの置き場所を決めた。

1
2
3
4
5
6
7
8
9
project-root/
├── AGENTS.md            # いまの制約(毎ターンAIがロード)
├── docs/
│   └── adr/             # なぜそうしたかの台帳(append-only)
│       ├── 0001-reservation-booking-split.md
│       ├── 0002-four-bounded-contexts.md
│       └── ...
├── src/contexts/        # Bounded Context ごとのコード
└── CLAUDE.md            # 「設計変更の前に docs/adr/ を確認せよ」の1行を含む

棲み分けのルールはシンプルだ。AGENTS.md には「Reservation は仮押さえ、30分で失効」と現在形で短く書く。なぜ Reservation と Booking を分けたのか、なぜ30分なのかは ADR に書く。 AGENTS.md は毎ターンAIが読むので肥大化させない。ADRは普段読まれないが、AIが「なぜこうなっている?」と問われたとき、あるいは設計を変えようとしたときに参照する。CLAUDE.md には「設計変更の前に docs/adr/ を確認せよ」という1行を入れ、AIが過去の決定を勝手に覆さないようにした2

なお、これら10本のADRの管理——起票、初稿生成、整形・採番、supersede 処理、整合性チェック——は、このプロジェクトではAIが回している。人(役割1・役割4)が握るのは、戦略的な決定そのものと「Whyの妥当性検証」だ。以下で「役割1が書く」と記すのは、正確には「役割1が決定し、Whyを確定する。起票と整形はAIが行う」という分担を指す。

では、フェーズを追ってADRが生まれていく様子を見る。

Phase 1 の裏で:ドメイン分割の決定(役割1)

Event Storming の3日間で、最も重要な2本のADRが生まれた。決定とWhyの確定を担うのは役割1(ドメイン定義者)、起票と整形はAIだ。

ADR-0001:Reservation と Booking を別概念として分離する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# ADR-0001: Reservation と Booking を別 Aggregate に分離する

## Status
accepted (2026-XX-XX)

## Context
Event Storming 2日目、予約担当が言う「予約」とフロントが言う「予約」が
別物だと判明した。前者はカード認証前の仮押さえ、後者は会計計上される確定枠。
同じ「予約」という1概念で実装すると、カード認証の前後・会計計上のタイミングが
状態フラグの中に埋もれ、AIに実装させたとき「確定」の意味が文脈ごとにぶれる。

## Decision
仮押さえを Reservation、カード認証成功後の確定枠を Booking とし、
別々の Aggregate Root として実装する。用語集(ユビキタス言語)でも禁則を定める
(Reservation の Confirmed 状態を「予約成立」と呼ばない 等)。

## Alternatives considered
- 単一の Reservation エンティティに status だけ持たせる案
  → 却下。会計計上の境界が型に現れず、AIが「確定」を曖昧に実装するリスクが高い。
- 「Order」など汎用語に寄せる案
  → 却下。ホテル業務の語彙ではなく、訓練データの一般語に引きずられる。

## Consequences
+ 用語が型・テーブル・UI で一貫する。
+ 会計連携の境界(Booking = 売上計上の単位)が明確になる。
- Aggregate が増え、Reservation → Booking への遷移ユースケースを明示する必要。
フォローアップ: 遷移はカード認証成功イベントを契機とする(INV-3 として型・テストに)。

この決定は、DDDファーストの設計論が説く「AIが選んだ語彙と業務推測が既成事実化する」事故を断つ核心だ。booking と reservation を取り違えるAIエージェントの寓話3が示す通り、ここを曖昧にすると業務レベルの実害につながる。だからこそ ADR として根拠ごと残す。

ADR-0002:ドメインを4つの Bounded Context に分割する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# ADR-0002: 4つの Bounded Context に分割する

## Status
accepted (2026-XX-XX) — のちに ADR-0010 で部分的に superseded

## Context
イベントの塊と用語の違いから、顧客予約・在庫管理・フロント業務・清掃の
4領域が浮かび上がった。これをどう構造に落とすか。

## Decision
4つの Bounded Context に分け、src/contexts/ 配下にディレクトリ分離する。
クロスコンテキストの import は ACL 層経由のみ許可し、それ以外はガードレールCIで fail させる。

## Alternatives considered
- 単一ドメインモデルで通す案 → 却下(「部屋」「在庫」の用語衝突が解けない)。
- 最初からマイクロサービス分割 → 却下。β段階では過剰。モジュラモノリスで十分で、
  境界が間違っていたとき引き直すコストも低い。

## Consequences
+ 境界がファイル構造とCIに反映され、AIが越境コードを書いても検出される。
- 境界の引き方が間違っていた場合、生成済みコードに影響が及ぶ(後述の ADR-0010 で現実化)。

この ADR の Status 行に注目してほしい。「のちに ADR-0010 で部分的に superseded」——この境界は後で引き直される。その経緯は Phase 7 で見る。重要なのは、引き直すとき「なぜ最初4つに、しかもこの切り方で分けたか」がここに残っていることだ。

Phase 2 の裏で:境界の関係と業務ルールの決定(役割1)

ドメイン定義の5要素(ユビキタス言語・ドメインモデル・Bounded Context・不変条件・ユースケース)を整理する1週間で、外部システムとの関係と業務数値が決まった。

ADR-0003:会計システム(既存オンプレ)との関係を Conformist + ACL にする

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# ADR-0003: 会計システムとの境界を Conformist にし ACL で語彙汚染を防ぐ

## Status
accepted (2026-XX-XX)

## Context
既存のオンプレ会計システムとの連携が必須要件。会計側は変更できず、
語彙も異なる(会計の「予約」は売上計上ベース)。

## Decision
関係性は Conformist(相手の語彙に従う)とする。ただし顧客予約コンテキストとの間に
ACL(Anti-Corruption Layer)を置き、会計側の語彙が自ドメインに侵入するのを防ぐ。
β期間中は ACL の先をモックとし、本番化フェーズで実連携を実装する。

## Consequences
+ ドメインモデルが会計システムの都合で汚染されない。
- ACL の実装・保守コスト。β中は会計連携を手動コピペで運用する(既知の制約として明記)。

ADR-0004:Reservation の有効期限を30分とする(業務判断)

これは技術ではなく業務上の決定(BDR的なADR)だ。要約で示す。

Status accepted / Context 仮押さえ枠の保持時間。長いと在庫が死に、短いと顧客が決済前に失効する / Decision 30分。INV-2 として型とプロパティテストに落とす / Alternatives 15分(離脱が増える懸念)・60分(在庫を圧迫)。経営とフロントの合意で30分に / Consequences 在庫回転と顧客体験のバランス。失効処理は要監視(→ ADR-0006)

「なぜ30分か」を残すのが効く場面は、半年後に「やっぱり45分にしたい」と言われたときだ。当時15分と60分を検討して30分にした経緯があれば、議論は差分から再開できる。

Phase 3 の裏で:技術選定の決定(役割4)

AGENTS.md を書き、技術スタックを確定するこのフェーズで、役割4(AI環境整備エンジニア)が技術選定ADRを書いた。

ADR-0005:ホスティングを OpenNext on AWS にする(Vercel を採用しない)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# ADR-0005: ホスティングに OpenNext on AWS を採用する

## Status
accepted (2026-XX-XX)

## Context
本番技術として Next.js 16 を使う。最も手軽なのは Vercel だが、
本プロジェクトには (a) オンプレ会計システムへの VPC 経由連携、(b) 自社での
データ管理、(c) コスト予測性 の要件がある。

## Decision
OpenNext on AWS(Lambda + CloudFront + S3 + Aurora Serverless v2)を採用する。

## Alternatives considered
- Vercel → 却下。VPC 経由のオンプレ連携が困難で、ベンダーロックインも避けたい。
- Cloudflare(@cloudflare/next-on-pages)→ 保留。構造は同等に組めるが、
  Aurora/VPC 連携の都合で今回は AWS を選ぶ。将来の移行先候補としては残す。

## Consequences
+ AWS 上で自社管理でき、VPC で会計システムと連携できる。
- 運用が複雑(CDK、Lambda の実行制約、コネクションプール = RDS Proxy 必須)。
  → この制約は AGENTS.md の「OpenNext 固有のルール」に現在形で転記する。

ここで実践編の What / Why の分離 が具体的に見える。ADR-0005 には「なぜ Vercel を捨てて AWS にしたか」が残る。一方、その帰結である「Lambda は読み取り専用だから一時ファイルは /tmp のみ」「長時間処理は EventBridge に分解」といった現在形の制約は AGENTS.md に転記され、AIが毎ターン参照する。同じ決定の Why と What が、別々のファイルに、別々の寿命で置かれる。

Phase 4 の裏で:型表現の決定(役割4)

ADR-0007:ドメインの状態を discriminated union で表現する

Status accepted / Context Reservation/Booking は複数状態を持つ。不正な状態の組合せを防ぎ、AI生成コードの品質を型で守りたい / Decision status を discriminated union にし、各状態が持つフィールドを型で固定する(Pending のときだけ expiresAt を持つ、等) / Alternatives 単一 interface に optional フィールドを並べる案 → 却下(不正な状態の組合せが書けてしまう)。enum + 別テーブル → 過剰 / Consequences 不正状態がコンパイルエラーになり、AIが型違反を書けない。状態追加時は全分岐の更新が必要

このADRは、実践編で「AGENTS.md と型がAIの品質を物理的に守る」と述べた足場の、設計判断としての裏付けだ。「なぜ optional フィールドではなく discriminated union なのか」を残しておくと、後でAIが「optional のほうが簡単では」と提案してきても、却下理由が台帳にある。

Phase 5–6 の裏で:ADRが運用される——検知と下書き

ここはADRが生まれるより使われるフェーズだ。2つの場面が起きた。

場面1:役割2がADR違反を検知してエスカレーションする。 プロト作成中、AIが在庫管理コンテキストから顧客予約コンテキストの内部型を直接 import するコードを生成した。ガードレールCIが落ちる。役割2(業務に明るいIT担当、非エンジニア)は、コードの是非を技術的に判断する力はない。だが docs/adr/0002-four-bounded-contexts.md を開いて「ADR-0002 で、コンテキストをまたぐ参照は ACL 経由のみと決まっている。これは違反では?」と役割4にエスカレーションできた。実践編で述べた通り、役割2は決定しない。ADRを根拠に検知する。

場面2:AIがADRを下書きし、役割4が承認する。 Phase 3 で保留にしていた「30分失効をどう実行するか」が、Phase 5 で実装される。役割4が決定を下した後、それをADRに起こす作業はAIに任せた。PRの diff(EventBridge ルールと Lambda の追加)を渡し、「この変更のADR初稿を書け」と指示する4。AIが生成した初稿に、役割4が却下理由(なぜ同期処理ではないか)を追記して確定させた。

ADR-0006:Reservation 期限切れ処理を EventBridge → Lambda の非同期にする

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# ADR-0006: 期限切れ処理を EventBridge 駆動の非同期 Lambda にする

## Status
accepted (2026-XX-XX)
## 初稿: AI生成(PR #42 の diff から)/ Why と Alternatives: 役割4 が確定

## Context
ADR-0004 で定めた「30分で Reservation を Expired にする」を、どう実行するか。

## Decision
AWS EventBridge の5分間隔スケジュールで専用 Lambda を起動し、
expiresAt を過ぎた Pending Reservation を Expired に遷移させる。

## Alternatives considered
- リクエスト処理内で同期的に失効チェック → 却下。Lambda の実行制約と、
  アクセスがない時間帯に失効が遅れる問題。
- 常駐ワーカー → 却下。OpenNext / Lambda 構成(ADR-0005)と整合しない。

## Consequences
+ ADR-0005 の Lambda 制約と整合する。+ 失効処理が顧客リクエストから独立。
- 最大5分の失効遅延。DLQ とアラートを本番化時に追加(フォローアップ)。

ここが実践編の「AIが初稿、人がWhyを確定する」の実演だ。AIは diff から「EventBridge と Lambda を追加した(What)」は正確に書けた。だが「なぜ同期処理を却下したか」は diff に現れない判断であり、役割4 が追記した。Status 欄に「初稿: AI生成/Why: 役割4が確定」と作成経緯を明記しておくと、後から信頼度が分かる。

Phase 7 / β運用の裏で:見落とし・追加・引き直し(役割1)

同シナリオの 実装ウォークスルー は、β運用で「落とし穴」が現実化したと書いた。その落とし穴は、ADR台帳の上では3本の新しいADRとして記録される。

ADR-0008:キャンセル料ルールを導入する(落とし穴1の事後補正)

β運用で、経営者が「無料キャンセル可のままでは収益的に困る」と気づいた。Phase 2 でキャンセル料の業務ルールを定義し忘れていた——実践編でいう「定義品質が結果に伝播する」落とし穴だ。これをADRで補正する。

Status accepted / Context Phase 2 でキャンセル料を定義せず、プロトが「無料キャンセル可」で実装された。β運用で収益面の問題が判明 / Decision 宿泊日からの日数に応じたキャンセル料率を Booking に持たせる / Consequences ドメイン定義に戻りルール追加。AGENTS.md の不変条件に INV-7 を追記。この見落としは「定義を AI に渡す前のクロスレビュー不足」が原因であり、再発防止として定義レビュー工程を必須化する

ADRには「決定」だけでなく、なぜ最初それを見落としたかの反省も書ける。これが次のプロジェクトへの学びになる。

ADR-0009:団体予約コンテキストを新設する(落とし穴2の還流)

β運用中に「団体予約は通常予約と別フロー」という業務知識が表面化した。最初は誰も意識していなかった。発見が定義側に還流した結果が、この新ADRだ。

Status accepted / Context β運用で団体予約(複数室一括・請求書払い・キャンセル規定が別)が通常予約と別フローだと判明 / Decision group-reservation コンテキストを新設し、src/contexts/group-reservation/ を追加 / Consequences Bounded Context マップに5つ目を追加。AGENTS.md のコンテキスト一覧を更新。既存4コンテキストには影響させない(独立性を保つ)

これは supersede ではなく純粋な追加だ。新しいドメイン知識の発見は、過去の決定を否定せず、台帳に積み増される。

ADR-0010:フロント業務と清掃の境界を「組織」から「責務」へ引き直す(落とし穴3、ADR-0002 を supersede)

最も重要なADRがこれだ。ADR-0002 で引いた境界が、β運用で間違いだと分かった。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# ADR-0010: フロント業務 / 清掃の境界を責務ベースで引き直す

## Status
accepted (2026-XX-XX) — supersedes ADR-0002 の該当部分

## Context
ADR-0002 で「フロント業務」と「清掃」を別コンテキストにした。だが β運用で、
小規模支店では同じチームが両方を担当していると判明した。境界を「組織(誰がやるか)」で
引いていたのが誤りで、本来は「責務(何を保証するか)」で引くべきだった。

## Decision
清掃を独立コンテキストとして切り出すのをやめ、責務ベースで境界を引き直す。
清掃完了通知の経路だけをフロント業務との統合点として残す。

## Consequences
+ 境界が現実の業務(小規模支店の兼任)に合う。
- housekeeping コンテキストのコード一部を front-desk 配下へ移動。
- ADR-0002 の該当部分を superseded とマークし、本ADRへのリンクを張る。

ここで実践編の supersede 機構 が効いた。境界を引き直すとき、ADR-0002 に「なぜ最初4つに、組織ベースで分けたか」が残っていた。だから引き直しは「組織ベースが誤りで、責務ベースが正しい」という差分の議論だけで済んだ。もしADR-0002 がなければ、「そもそもなぜ清掃を分けたんだっけ」という考古学から始めねばならなかった。過去の決定の理由が残っていることが、やり直しのコストを下げた。

supersede の関係を図にすると、こうなる。

flowchart TB
    A002["ADR-0002<br>4つの Bounded Context<br>(組織ベースで分割)"]
    A010["ADR-0010<br>境界を責務ベースに<br>引き直す"]
    A009["ADR-0009<br>団体予約コンテキスト<br>新設 (追加)"]
    A002 -->|"supersedes (部分)"| A010
    A002 -.->|"4→5へ拡張"| A009

引き継ぎ:役割3はADR台帳から読む

3か月のβ運用後、役割3(本番化エンジニア)が引き継ぐ。ウォークスルーでは各部品を「捨てる/残す」と仕分けしたが、その判断の速さと正確さは、ADR台帳を読めることに支えられている

  • contexts/*/domain/types.tsそのまま残すと判断できたのは、ADR-0007 で「discriminated union は意図的な品質設計」だと分かるから。
  • contexts/*/acl/*.tsモックを本番版に書き直すと判断できたのは、ADR-0003 で「β中はモック、本番で実連携」と明記されているから。
  • 清掃コンテキストの構造が他と違うことに戸惑わずに済んだのは、ADR-0010 で「責務ベースに引き直した」経緯が読めるから。

ADRがなければ、役割3はコードから設計意図を逆算しなければならない。ADRがあれば、設計意図を直接読める。これが実践編で述べた「ADRは4役割の引き継ぎプロトコル」の実際だ。

振り返り:10本のADR台帳

プロジェクトを通じて生まれた台帳の全体像。

ADRタイトルStatus決定・監督(起票/整形はAI)フェーズ
0001Reservation と Booking を分離accepted役割1P1
00024つの Bounded Context に分割superseded by 0010(部分)役割1P1
0003会計システムを Conformist + ACLaccepted役割1P2
0004Reservation 有効期限を30分accepted役割1(+経営)P2
0005OpenNext on AWS 採用(Vercel却下)accepted役割4P3
0006期限切れ処理を EventBridge 非同期acceptedAI下書き→役割4確定P5
0007状態を discriminated union で表現accepted役割4P4
0008キャンセル料ルール導入accepted役割1P7(β)
0009団体予約コンテキスト新設accepted役割1P7(β)
0010境界を責務ベースに引き直しaccepted(supersedes 0002)役割1P7(β)

この表だけで、プロジェクトの意思決定の履歴が俯瞰できる。誰が何を決め、何が覆され、AIがどこで関わったかが一目で分かる。これは AGENTS.md(現在の制約のスナップショット)からは絶対に読み取れない、台帳ならではの情報だ。

注意点として、実践編で挙げた落とし穴は実演でも顔を出す。ADRを書きすぎないこと(プロト中の些末な実装選択はADRにしない——上の10本はいずれも「3か月後に判断材料になる」ものに絞った)、AI下書きのWhyを鵜呑みにしないこと(ADR-0006 で役割4 が却下理由を確定したように)、supersede 時に AGENTS.md も同じPRで更新すること(ADR-0010 の境界変更は AGENTS.md のコンテキスト一覧と同時に直す)。台帳は放っておくと現実とズレる。参照されて初めて生きる2という原則は、メンテされて初めて成り立つ。

まとめ

みなと屋ホテルズの7フェーズの裏側で、10本のADRが並走していた。実践編で論じた4つの原則が、台帳の上で具体的にこう動いた。

  • What / Why の分離:ADR-0005 の「なぜ Vercel を却下したか」は ADR に、その帰結の「Lambda 制約」は AGENTS.md に。同じ決定の理由と制約が別の寿命で置かれる。
  • supersede がやり直しを支える:ADR-0002 を ADR-0010 で引き直せたのは、「なぜ最初その境界にしたか」が残っていたから。考古学ではなく差分の議論で済んだ。
  • 4役割の引き継ぎプロトコル:役割1がドメイン分割(0001-0004, 0008-0010)、役割4が技術選定(0005, 0007)、役割2はADR違反を検知してエスカレーション、役割3は台帳を読んで取捨選択。
  • AIが初稿、人がWhyを確定:ADR-0006 は AI が diff から初稿を書き、役割4 が却下理由を追記して確定した。

ADR台帳は、プロジェクトの「議事録」ではない。未来の人間とAIが参照するための、なぜの記録だ。みなと屋の台帳を半年後に開けば、人も、引き継いだAIも、「なぜこのシステムはこうなっているのか」を即座に答えられる。書いた時ではなく、参照された時に、決定は初めて生きる2

実践編・論考編もあわせてどうぞ: 本記事は具体的なADR台帳の実演に焦点を当てた。その使い方の原則——メリット・デメリット、AGENTS.md との分担、何をADRにする/しないか、AIに管理を任せる運用——は DDD開発でADRをどう使うか に、なぜAI時代にADRが再評価されるのかの論考とエビデンスは AI時代にADRが再評価される理由 にまとめている。

関連記事

このテーマに関連する他の記事もご覧ください:

参考資料

本文中の引用番号に対応する参考資料を番号順に記載しています。

その他参考資料(本文中で番号引用なし)

  • Agent Decision Records (AgDR) - me2resh, GitHub (2025). AIエージェントの自律決定を記録する拡張標準。ADR-0006 のように作成経緯(誰が初稿を書いたか)をメタデータに残す発想の参考。【信頼性: 中】
  1. Documenting Architecture Decisions - Michael Nygard, Relevance / Cognitect (2011-11-15). ADRの発祥。本記事のADR本文は Status / Context / Decision / Consequences のフォーマットに従う。adr.github.io で公式ハブ化。【信頼性: 高】 ↩︎

  2. A Prescription for SDD Fatigue: Recording Architectural Decisions with ADRs in the AI Era - Kosk, Zenn (2026). 「設計判断が生きるのは書かれた時ではなく参照された時」「supersede 機構」「設計変更前に ADR を確認する CLAUDE.md ルール」。【信頼性: 中】(実務家ブログ) ↩︎ ↩︎2 ↩︎3

  3. Domain Driven Agent Design - Russ Miles (2025). booking と reservation を取り違えた AI エージェントの寓話(ADR-0001 の動機)。【信頼性: 中】(実務家ブログ) ↩︎

  4. From Stale Docs to Living Architecture: Automating ADRs with GitHub + LLM - Iraj Hedayati, Medium (2025-09-14). PR の diff から LLM が ADR 初稿を生成し、人がレビュー・refine するワークフロー(ADR-0006 のモデル)。【信頼性: 中】(実務家ブログ) ↩︎

This post is licensed under CC BY 4.0 by the author.