Appendix D: 記入例(ランニング例の完成形)

Appendix B のテンプレを、ランニング例(小規模タスク管理)に対して記入した例です。テンプレ番号(B-1..B-8)に対応する順で掲載しています。

対象(ケース):

  • ケース1: 「タスク割り当て + 通知(メール)」(D-1..D-8)
  • ケース2: 「期限超過の表示 + 通知(メール)」(D-9..D-16)
テンプレ 記入例 ねらい
B-1 D-1 要求(なぜやるか)を KPI で固定する
B-2 D-2 要件(Shall)を実装から分離して列挙する
B-3 D-3 仕様(外部観測の振る舞い)を曖昧さなく定義する
B-5 D-4 設計(内部構造)を最小でアウトライン化する
B-4 D-5 S/D/V で依存の痛みを半定量化する
B-6 D-6 変更理由(Change Drivers)で「なぜ今」を揃える
B-7 D-7 ADR で重大な分岐を最小記録する
B-8 D-8 テスト配分(単体/統合/E2E)を合意する
テンプレ 記入例(ケース2) ねらい
B-1 D-9 要求(なぜやるか)を KPI で固定する
B-2 D-10 要件(Shall)を実装から分離して列挙する
B-3 D-11 仕様(外部観測の振る舞い)を曖昧さなく定義する
B-5 D-12 設計(内部構造)を最小でアウトライン化する
B-4 D-13 S/D/V で依存の痛みを半定量化する
B-6 D-14 変更理由(Change Drivers)で「なぜ今」を揃える
B-7 D-15 ADR で重大な分岐を最小記録する
B-8 D-16 テスト配分(単体/統合/E2E)を合意する

追加(任意):

テンプレ 記入例 ねらい
B-9 D-17 相互作用を焦点化し、設計の介入点を作る
B-10 D-18 失敗理由(code)を契約として固定する
B-11 D-19 要件→仕様→設計→テストの対応を最小で維持する
B-12 D-20 受け入れ条件(AC)をID化し、会話コストを下げる
B-13 D-21 認可ルールを表形式で合意し、仕様/テストの前提を揃える
B-14 D-22 API の入出力・エラー・冪等性を契約として固定する
B-15 D-23 整合性制約と同時更新の方針を合意する
B-16 D-24 外部I/Fの失敗時期待(継続/再送/検知)を仕様として固定する

D-1. 要求(Needs / Goals)の記入例(B-1)

テーマ: 「タスク割り当て + 通知(メール)」

背景/課題(As-Is)

  • 何が起きているか(事実): タスクが割り当てられても担当者が気づかず、着手が遅れる
  • 誰が困っているか: 管理者(進捗管理・調整コスト)、担当者(見落としによる期限超過)
  • 放置するとどうなるか(損失/機会損失): 期限超過の増加、リマインド/再割り当ての手間、監査(誰が割り当てたか)の不備

目的(Goals / To-Be)

  • 目標状態(業務/体験): 管理者の割り当てが担当者に伝わり、期限内に着手/完了できる
  • 期限(いつまでに): 次のリリースまで(例)

KPI(測定)

指標 現状 目標 測定方法 備考
割り当て後 24h 未着手率 30%(例) 10%(例) assignedAtin_progress までの差分を集計 タスク種別で分ける余地
期限超過率 15%(例) 5%(例) dueAtdoneAt を集計 期限ルール変更で変動
通知失敗の検知遅延 2日(例) 当日(例) 失敗ログ/アラートの検知時間を集計 運用体制に依存

スコープ/非ゴール

  • 含む:
    • 管理者による担当者割り当て
    • 担当者への通知(メール)
    • 失敗時の検知と再送方針の明文化
  • 含まない(非ゴール):
    • 通知チャネルの多重化(Slack 等)
    • 高度な配信保証(厳密な exactly-once)
    • 既読・承認フロー(通知に対するリアクション管理)

制約/前提

  • 体制: 単一チーム、単一リポジトリ
  • 外部I/F: メール送信はネットワーク越しの外部サービス
  • 運用: 通知失敗は業務影響を持つため、検知手段が必要

D-2. 要件(Requirements / Shall)の記入例(B-2)

スコープ

  • 含む:
    • タスクに担当者を割り当てできる
    • 割り当て時に担当者へ通知できる
    • 割り当て操作の監査ができる
  • 含まない(非ゴール):
    • 通知チャネルの多重化(Slack 等)
    • 高度な配信保証(厳密な exactly-once)

機能要件(Shall)

ID Shall(要件) 根拠(要求/KPI) 優先度 備考
R-1 システムは管理者がタスクに担当者を割り当てできること 未着手率の低減 Must  
R-2 システムは権限により割り当て操作を制御すること(管理者のみ) セキュリティ/監査 Must  
R-3 システムは割り当て(誰が/いつ/誰に/どのタスク)を記録できること 監査 Should 監査要件次第で Must
R-4 システムは割り当て時に担当者へ通知できること 未着手率の低減 Must 通知チャネルは仕様で固定
R-5 システムは通知が失敗しても割り当ての確定を妨げないこと 業務継続 Must 失敗は検知可能であること
R-6 システムは通知失敗を運用で検知できること 検知遅延の短縮 Must ログ/メトリクス/アラート
R-7 システムは存在しないタスクへの割り当てを失敗として扱うこと 品質 Must エラー形式は仕様で定義

非機能(最小合意)

  • 性能: 割り当て操作は通常時 1 秒以内(例: p95)で完了する
  • 可用性: メンテ時間帯を除き稼働(SLA/SLO は将来導入なら「未定」でもよい)
  • セキュリティ/権限: 管理者/一般ユーザーを識別し、割り当ては管理者のみに制限する
  • 監査/ログ: 割り当て(誰が/いつ/誰に/どのタスク)を検索可能な形で残す
  • 運用(アラート/リトライ/バックアップ): 通知失敗が検知でき、再送方針(手動/自動)が明文化されている

未決/リスク

  • 通知失敗時の再送方式(手動/自動、再送回数、間隔)
  • 監査ログの保存期間・閲覧権限
  • 同時更新(競合)の扱い(後勝ち/排他/409 など)

D-3. 仕様(Specification / Behavior)の記入例(B-3)

参照(要求/要件)

  • 要求: D-1(割り当ての見落としを減らす)
  • 要件: R-1〜R-7

外部I/F(観測できる面)

  • UI:
    • 管理者はタスク詳細で担当者を選択し「割り当て」を実行できる
    • 成功時に「割り当て完了」を表示し、担当者表示が更新される
  • API(例):
    • POST /api/tasks/{taskId}/assignment body: { "assigneeId": "user-123" }
    • 成功時は 200 を返す
  • 外部連携(通知):
    • 割り当て時に担当者へ通知(メール)を送信する
    • メール送信の失敗/遅延が発生し得るため、失敗時の期待(業務継続/検知/再送)を定義する

受け入れ条件(Given/When/Then)

  • Given: 管理者がログインしており、タスクが todo 状態で存在する
    • When: 管理者が担当者 user-123 を割り当てる
    • Then:
      • タスクの assigneeIduser-123 に更新される
      • 画面に「割り当て完了」が表示される
      • 担当者に「タスクが割り当てられた」旨の通知(メール)が送信される
  • Given: 管理者がログインしており、対象タスクが存在しない
    • When: 管理者が割り当て操作を行う
    • Then:
      • API は 404 を返す
      • UI は「対象タスクが見つからない」旨を表示する
      • 監査/ログに「対象なし」が記録される(必要なら)
  • Given: メール送信サービスが一時的に失敗する
    • When: 管理者が割り当て操作を行う
    • Then:
      • タスクの割り当て自体は成功する(業務継続を優先)
      • 送信失敗が運用で検知できる(ログ、メトリクス、アラートのいずれか)
      • 再送の方針(手動/自動)が明文化されている

例外系/失敗時の振る舞い(Behavior)

  • 認可失敗:
    • 管理者以外が割り当て API を呼ぶと 403(または同等)を返す
  • 存在しない/不正入力:
    • assigneeId が不正な形式なら 400(または同等)を返す
  • 状態/業務ルール違反:
    • タスクが割り当て可能な状態でない場合(例: done)は 409(または同等)を返す
  • 競合(同時更新):
    • 更新競合が発生した場合の扱いを固定する(例: 409、または後勝ち。どちらでも良いが曖昧にしない)
  • 外部I/F失敗(通知):
    • 割り当て確定の合否と、通知送信の合否を混同しない(R-5)
    • 失敗の検知方法と再送の起点を固定する(ログ/キュー/手順)
  • 冪等性(二重送信):
    • 同一タスクに同一担当者を再割り当てしても、結果が重複しない(少なくとも監査ログや通知が増殖しない)
  • 時間/期限:
    • 期限が過去の場合の扱い(許可/拒否/警告)を固定する(例: 割り当ては許可するが UI で警告する)
  • 監査/ログ:
    • 403/404/400/409 等の失敗も、原因追跡できる粒度で記録する(ただし個人情報をログに出さない)

観測点(何をもって合否判定するか)

  • 画面表示: 担当者の表示が更新され、成功/失敗が表示できる
  • API レスポンス: ステータスコード(200/403/404 等)とエラー形式(最低限 codemessage)が一定
  • 監査/ログ: 割り当てイベント(actor/task/assignee/時刻)と通知失敗が検索できる

テスト観点(仕様から導出)

  • 単体テストで守る振る舞い: 権限判定、状態遷移、期限ルールなど(純粋ロジック)
  • 統合テストで守る契約(境界): API+DB の永続化、認可接続、通知I/Fの失敗時の扱い
  • E2E で守る導線: 管理者が割り当て、担当者表示が更新される(メール到達そのものはE2Eに含めない)

D-4. 設計(Design / Structure)アウトラインの記入例(B-5)

参照(要求/要件/仕様)

  • 要求: D-1
  • 要件: R-1〜R-7
  • 仕様: D-3

構造(境界と責務)

  • domain:
    • 権限ルール(管理者のみ割り当て可)
    • 状態遷移(todo → in_progress → done)と割り当て可否
    • 期限判定(表示用ステータス等)
  • usecases:
    • assignTask(割り当ての確定、通知要求、監査の記録)
    • 依存(DB/通知/時刻/認可)を port として引数で受ける
  • adapters:
    • HTTP(ルーティング、入力検証、エラー形式)
    • DB(永続化、監査ログ)
    • mailer(外部メールI/F)

依存方向(ルール)

  • domain は I/O やフレームワークに依存しない
  • usecases は domain と port にのみ依存する
  • adapters が port を実装し、外部 I/F(DB/メール等)を扱う

データモデル

  • 論理(概念/エンティティ):
    • Task: id/title/status/dueAt/assigneeId/assignedAt
    • AssignmentAudit: taskId/actorId/assigneeId/assignedAt
  • 物理(DB テーブル例):
    • tasks: id, title, status, due_at, assignee_id, assigned_at
    • audit_logs: id, action, task_id, actor_id, payload, created_at

重要アルゴリズム/ルール

  • 管理者のみ割り当て可能(認可は境界で enforce し、domain ルールとしても保持する)
  • 完了済み(done)への割り当ては不可(例。運用要件に合わせて固定する)

トレードオフ

  • 得るもの: 割り当て確定と通知を分離でき、外部I/Fの失敗で業務確定が止まりにくい
  • 失うもの: 通知が即時に届く保証は弱くなるため、検知と再送の運用が必要

テスト戦略への影響

  • domain は単体を厚く、adapters 境界は統合で守る
  • E2E は価値導線に限定し、外部メール到達は含めない(フレーク源になりやすい)

D-5. S/D/V 採点(依存関係トップ)の記入例(B-4)

例として、依存関係トップ 10 のうち代表的なものを記入します。

# 依存元 依存先 依存の内容 S D V コメント(観測/根拠) 手当案
1 UI API 割り当て操作の入出力・エラー形式 4 3 3 UI/API で入力検証・権限表示がズレると破綻 仕様(D-3)を固定 + 統合テスト
2 usecases authz 権限判定(管理者のみ割り当て可) 4 3 3 認可ルール変更が UI/API に波及しやすい 判定を domain 側へ寄せ、単体で守る
3 usecases db 割り当ての永続化と監査ログ 4 3 2 同時変更は必須、ただし変動性は低め schema/DAO を境界に固定 + 統合テスト
4 usecases mailer 割り当て通知の送信 2 4 3 外部I/Fで失敗が起きる、運用要件が増えやすい adapter 化 + 失敗時の扱いを ADR 化

採点の狙い:

  • 「今すぐ手当すべき」ものは、S と D と V が同時に悪い領域になりやすい
  • ただし S が強い領域は「分離」より「一体で扱う」ほうがコストが低い場合がある(章 03 の判断原則)

D-6. Change Drivers(記入例)(B-6)

対象: 「通知を境界として強める」

背景(何が起きているか)

  • 事象(観測): 通知失敗が顕在化し、問い合わせが発生した
  • 影響(価値/運用/コスト): 担当者が気づかず、期限超過が増える
  • 期限(いつまでに): 次のリリースまでに検知手段を用意したい

ドライバー(何が変更を必要にしているか)

ドライバー 内容 強さ(低/中/高) 根拠
変動性(V) 通知要件が増える 追加要望(再送/テンプレ)が出ている
距離(D) 外部メール I/F 失敗/遅延が発生する
統合強度(S) 割り当て確定は必須 業務確定のため
運用要件 失敗検知が必要 問い合わせが発生した
チーム/組織 単一チーム 現時点では分割不要

対応方針(案)

  • 何を変える: 通知を adapter として明確化し、失敗を検知できる形にする
  • 変えないこと(非ゴール): 高度な配信保証、複数チャネル対応
  • テスト戦略への影響: 通知は統合テスト中心、E2E には入れない
  • ADR が必要か: 必要(通知の扱いは重大な分岐)

D-7. ADR(記入例)(B-7)

ADR: 通知(メール)失敗時の扱いを「業務継続優先」にする

  • Status: accepted
  • Date: 2026-01-12
  • Deciders: 開発チーム
  • Scope: タスク割り当て/通知

Context

  • 背景: 割り当て時に通知(メール)が必要になった
  • 問題: メール送信は外部 I/F であり、失敗/遅延が発生する
  • 制約: 割り当ては業務上の確定であり、通知失敗で割り当て自体を失敗させたくない

Decision

  • 採用する決定: 割り当ての永続化は成功させ、通知失敗は「検知 + 再送方針」で扱う
  • 理由: D が大きい外部 I/F である一方、割り当ての S は強い(同時変更が必須)。境界(adapter)で失敗を吸収し、ユースケースは業務確定を優先する

Consequences

  • 得られる効果: 業務フローが外部障害に引きずられにくい
  • 失うもの/トレードオフ: 「通知が届いていない」可能性が残るため、運用で検知する必要がある
  • 後続タスク: 失敗ログ/メトリクス整備、再送手順の明文化
  • 見直し条件: 通知が SLA 対象になった、または失敗が頻発した場合

D-8. テスト配分(記入例)(B-8)

対象: 「タスク割り当て + 通知(メール)」

方針(ねらい)

  • 価値導線: 管理者が割り当て、担当者が着手/完了できること
  • 主要リスク: 権限漏れ、割り当て不整合、通知失敗の検知漏れ
  • 許容できない障害: 権限逸脱、データ不整合(割り当てが失われる)

配分(例)

レベル ねらい 対象 備考
単体 コアの振る舞い保護 権限判定、状態遷移、期限判定 時刻は注入して固定
統合 境界の契約保護 API+DB、認可、通知 I/F(失敗時の扱い) 外部メールは stub/spy で契約固定
E2E 価値導線の保護 管理者が割り当て、担当者表示が更新される メール到達は含めない

対象別の分類(例)

対象 単体 統合 E2E 補足
権限判定 主要導線で E2E も可
DB 永続化 - schema/クエリの契約を守る
通知(メール) - - 外部 I/F は統合で stub 化
主要導線(割り当て) - E2E は少数精鋭

配分の目安(例):

  • 単体 20 / 統合 10 / E2E 3

D-9. 要求(Needs / Goals)の記入例(B-1)

テーマ: 「期限超過の表示 + 通知(メール)」

背景/課題(As-Is)(期限超過)

  • 何が起きているか(事実): 期限が近い/超過したタスクが見落とされ、着手や調整が遅れる
  • 誰が困っているか: 担当者(見落としによる期限超過)、管理者(期限超過の後追い・調整コスト)
  • 放置するとどうなるか(損失/機会損失): 期限超過率の上昇、手動リマインドの増加、説明責任(いつ気づけたか)が曖昧

目的(Goals / To-Be)(期限超過)

  • 目標状態(業務/体験): 期限が近い/超過したタスクが UI で即座に判別でき、期限超過時に担当者へ通知される
  • 期限(いつまでに): 次のリリースまで(例)

KPI(測定)(期限超過)

指標 現状 目標 測定方法 備考
期限超過率 15%(例) 8%(例) dueAtdoneAt の差分を集計 タスク種別で分ける余地
平均期限超過日数 3日(例) 1日(例) doneAt - dueAt の平均 外れ値に注意
期限超過の検知遅延 2日(例) 当日(例) dueAt と通知/表示のタイミングを集計 運用体制に依存

スコープ/非ゴール(期限超過)

  • 含む:
    • 期限(dueAt)を基にした「期限が近い/超過」の表示(UI)
    • 期限超過時の担当者への通知(メール)
    • 二重通知を避けるための最小の冪等性
  • 含まない(非ゴール):
    • 複数チャネル通知(Slack 等)
    • 複雑なスケジューリング(営業時間、祝日カレンダー、リマインド頻度の多段階)
    • 期限計算の高度化(営業日換算、タイムゾーン個別対応)

制約/前提(期限超過)

  • タイムゾーン: 初期は単一タイムゾーン(例: JST)で運用する(個別対応は将来課題)
  • 期限判定: dueAt と「現在時刻」の比較で決める(判定ロジックは domain に集約する)
  • 外部I/F: メール送信はネットワーク越しの外部サービス

D-10. 要件(Requirements / Shall)の記入例(B-2)

スコープ(期限超過)

  • 含む:
    • 期限ステータス(期限が近い/超過)を判定できる
    • 期限ステータスを UI で表示できる
    • 期限超過時に担当者へ通知できる
  • 含まない(非ゴール):
    • 複数チャネル通知、複雑なスケジューリング、タイムゾーン個別対応

機能要件(Shall)(期限超過)

ID Shall(要件) 根拠(要求/KPI) 優先度 備考
DUE-1 システムは dueAt と現在時刻から期限ステータス(例: ok/due_soon/overdue)を判定できること 期限超過率の低減 Must 判定ロジックは重複させない
DUE-2 システムは期限ステータスをタスク一覧/詳細で表示できること 見落とし低減 Must UI の観測点を仕様で固定
DUE-3 システムはタスクが期限超過になった場合、担当者へ通知できること 検知遅延の短縮 Should 初期はメールのみ
DUE-4 システムは期限超過通知を重複して送らないこと(冪等性) 運用負債の抑制 Must 二重実行を前提にする
DUE-5 システムは期限超過通知の送信結果(成功/失敗)を運用で検知できること 検知遅延の短縮 Must ログ/メトリクス/アラート

非機能(最小合意)(期限超過)

  • 性能: 期限ステータス表示により、一覧表示が体感で劣化しないこと(測定対象を合意する)
  • 可用性: 主要導線(一覧/詳細表示)が営業時間内に利用できること
  • セキュリティ/権限: 期限情報は閲覧権限に従うこと(権限逸脱を許容しない)
  • 監査/ログ: 期限超過通知の実行(対象/時刻/結果)が追跡できること

未決/リスク(期限超過)

  • due_soon の閾値(例: 2日)と見直し条件
  • 期限超過の検知タイミング(即時/定期)と許容遅延
  • タイムゾーン個別対応が必要になった場合の方針

D-11. 仕様(Specification / Behavior)の記入例(B-3)

参照(要求/要件)(期限超過)

  • 要求: D-9
  • 要件: DUE-1〜DUE-5

外部I/F(観測できる面)(期限超過)

  • UI:
    • 一覧で期限ステータス(ok/due_soon/overdue)が表示される
    • 期限超過は強い視認性(例: バッジ)で判別できる
  • API(例):
    • GET /api/tasksdueAt と期限ステータス(または表示に必要な情報)を返す
  • 外部連携(通知):
    • 期限超過時に担当者へ通知(メール)を送信する
    • 外部I/Fの失敗/遅延が起き得るため、失敗時の期待(検知/再送)を定義する

受け入れ条件(Given/When/Then)(期限超過)

  • Given: タスクに dueAt=2026-01-10 が設定されている(JST)
    • When: 現在日が 2026-01-09 で一覧を表示する
    • Then:
      • 期限ステータスは due_soon として表示される
  • Given: タスクに dueAt=2026-01-10 が設定されている(JST)
    • When: 現在日が 2026-01-11 で一覧を表示する
    • Then:
      • 期限ステータスは overdue として表示される
  • Given: タスクが期限超過になった(dueAt < now
    • When: 期限超過の検知が実行される(例: 定期ジョブ)
    • Then:
      • 担当者へ期限超過通知(メール)が送信される
      • 通知の実行結果(成功/失敗)が追跡できる

例外系/失敗時の振る舞い(Behavior)(期限超過)

  • 入力/データ不備:
    • dueAt が未設定の場合は ok として扱う(表示は「期限なし」等)
  • 時刻/タイムゾーン:
    • 期限判定のタイムゾーンを固定し、UI/API/DB で解釈がズレないようにする(曖昧にしない)
  • 冪等性(二重実行):
    • 同一タスクに対する期限超過通知は重複しない(少なくとも同一の通知が増殖しない)
  • 外部I/F失敗(通知):
    • 送信失敗は運用で検知でき、再送の起点が残る(再送方式の詳細は要件化してから決める)

観測点(何をもって合否判定するか)(期限超過)

  • UI: overdue が視認でき、一覧で取りこぼさない
  • API: 期限ステータス(または表示に必要な情報)が一定の形式で取得できる
  • 運用: 通知実行の成功/失敗が追跡できる(ログ/メトリクス/監査ログ)

テスト観点(仕様から導出)(期限超過)

  • 単体テストで守る振る舞い: 期限判定ロジック(ok/due_soon/overdue)、閾値の扱い、タイムゾーン解釈
  • 統合テストで守る契約(境界): 期限表示の入出力、通知実行の記録、失敗時の検知/再送起点
  • E2E で守る導線: 一覧で期限超過が視認でき、重要導線(作成/割り当て/完了)の妨げにならない

D-12. 設計(Design / Structure)アウトラインの記入例(B-5)

参照(要求/要件/仕様)(期限超過)

  • 要求: D-9
  • 要件: DUE-1〜DUE-5
  • 仕様: D-11

構造(境界と責務)(期限超過)

  • domain:
    • 期限判定(nowdueAt からステータスを返す)
    • タイムゾーン解釈の前提(固定)を持つ
  • usecases:
    • 一覧表示用の DTO 生成(期限ステータスの付与)
    • 期限超過通知の実行(対象抽出、通知要求、実行結果の記録)
  • adapters:
    • HTTP(一覧取得、表示用データの返却)
    • scheduler(定期実行の起点。詳細は運用と合意して決める)
    • DB(タスク、通知実行ログ/監査ログ)
    • mailer(外部メールI/F)

依存方向(ルール)(期限超過)

  • 期限判定は domain に集約し、UI/API が独自に判定しない
  • scheduler は「起点」であり、判定ロジックを持たない(usecases を呼ぶ)

トレードオフ(期限超過)

  • 通知を「いつ送るか」を厳密にし過ぎると、実装/運用コストが増える
  • まずは表示(UI)を確実にし、通知は最小の契約(重複しない/失敗が追える)から始める

D-13. S/D/V 採点(依存関係トップ)の記入例(B-4)

依存 S D V 観測(根拠) 手当(方向性)
UI と API が期限判定を重複実装 3 2 4 ルール変更時に両方同時変更が必要 判定を domain に集約し、UI/API は結果を利用
期限超過通知(usecases → mailer) 2 4 3 外部I/Fの失敗・遅延が現実に起きる 通知要求と送信を分離、失敗検知/再送起点を固定
scheduler(定期起点)と期限判定 2 3 3 実行タイミングの議論が運用に波及 起点を最小化し、要件化した時点で強化

D-14. Change Drivers(記入例)(B-6)

対象: 「期限超過の見落としを減らす」

背景(何が起きているか)(期限超過)

  • 期限超過が一定割合で発生し、管理者の調整コストが上がっている
  • 期限が近いタスクを一覧で拾えず、手動リマインドが増えている

ドライバー(何が変更を必要にしているか)(期限超過)

  • 期限判定ルールが変更される可能性(V)と、UI/API の重複実装による手戻り
  • 通知の外部I/F(D)が大きく、失敗時の運用が未整備

対応方針(案)(期限超過)

  • 期限判定を domain に集約し、表示と判定のズレを無くす
  • 通知は最小契約(重複しない/失敗が追える)で開始し、必要に応じて再送を強化する

D-15. ADR(記入例)(B-7)

ADR: 期限超過通知は「重複しない最小契約」で開始する

Context(期限超過通知)

  • 期限超過の見落としが課題だが、複雑なスケジューリングを初期から導入すると過剰設計になりやすい
  • 外部メールI/Fは失敗し得るため、到達性をE2Eで直接保証しにくい

Decision(期限超過通知)

  • 期限超過通知は「同一タスクで重複しない」ことを契約として固定し、送信失敗は検知可能にする
  • 通知の送信タイミングは運用と合意できる最小単位(例: 定期ジョブ)で開始し、要件化した時点で強化する

Consequences(期限超過通知)

  • 良いこと: 早期に価値(見落とし低減)を出しつつ、後から運用要件に合わせて強化できる
  • 失うもの/トレードオフ: “即時通知”は保証しないため、通知遅延を許容する前提が必要
  • 見直し条件: 通知が SLA 対象になった、または遅延が業務影響になった場合

D-16. テスト配分(記入例)(B-8)

対象: 「期限超過の表示 + 通知(メール)」

方針(ねらい)(期限超過)

  • 価値導線: 期限超過を見落とさず、着手/完了に繋げる
  • 主要リスク: 期限判定のズレ、二重通知、通知失敗の検知漏れ
  • 許容できない障害: 期限超過が表示されない、権限逸脱、データ不整合

配分(例)(期限超過)

レベル ねらい 対象 備考
単体 コアの振る舞い保護 期限判定(時刻注入)、閾値、タイムゾーン前提 now() を注入して固定
統合 境界の契約保護 一覧の入出力、通知実行ログ、失敗時の検知 外部メールは stub/spy で契約固定
E2E 価値導線の保護 一覧で overdue が視認できる メール到達は含めない

配分の目安(例):

  • 単体 20 / 統合 10 / E2E 2

D-17. 相互作用マップ(記入例)(B-9)

対象: ケース2(期限超過の表示 + 通知)

変更シナリオ 波及先(例) 観測点(例) 制約/最小手当(例) 次アクション(接続)
due_soon の閾値変更(2日→3日) UI 表示、API 出力、並び替え、テスト期待値 UI のバッジ、API の dueStatus、単体テストの境界値 期限判定を domain に集約し、UI/API の重複実装を禁止(時刻は注入) 依存(UI↔API)の S/D/V 採点→テスト配分(単体/統合/E2E)
タイムゾーンの解釈変更(JST固定→将来拡張) 期限判定、保存形式、表示、運用手順 判定結果の差分、ログの時刻、監査 タイムゾーンの前提を仕様として固定し、入出力形式を境界で統一する 仕様(観測点)を再定義→統合テストで契約を固定
期限超過通知の実行タイミング変更(定期→準リアルタイム) scheduler、通知I/F、運用監視、再送 実行ログ、失敗検知、遅延の測定 起点(scheduler)を薄く保ち、通知要求の記録を契約にする(到達性は外部要因) Change Drivers→ADR(必要なら)で進化条件を明文化

D-18. エラーコードカタログ(記入例)(B-10)

対象: ケース1(割り当て API: POST /api/tasks/{taskId}/assignment

code message(利用者向け) 起点(境界) HTTP 再試行可否 監査/ログ 備考
forbidden 権限がありません 認可 403 No actor/taskId/code/相関ID 管理者以外の割り当ては拒否
not_found 対象タスクが見つかりません 参照 404 No actor/taskId/code/相関ID 存在しないID参照
invalid 入力が不正です 入力検証 400 No actor/code/相関ID 個人情報はログに出さない
conflict 競合が発生しました 同時更新 409 Yes/No actor/taskId/code/相関ID 楽観ロック等(方針を固定)

補足:

  • 通知(メール)送信失敗は、割り当ての合否と混同しない(ケース1 D-3/D-5)。API の失敗として返すのではなく、運用で検知できる記録(ログ/メトリクス/監査)に落とす。

D-19. トレーサビリティマップ(記入例)(B-11)

本例では、仕様(受け入れ条件/例外系)の参照を「D-3/D-11 のセクション名」で行います。受け入れ条件に ID(例: AC-1)を振る例は D-20 を参照してください。

ケース1(AC-ID): タスク割り当て + 通知

要件ID Shall(要約) 仕様(受け入れ条件/観測点) 設計(境界/ADR/エラーcode等) テスト(単体/統合/E2E) 状態 備考
R-1 管理者が担当者を割り当てできる D-3「受け入れ条件」/「観測点」 D-4(assignTask D-8(統合/E2E) 完了 主要導線
R-2 管理者のみ割り当て可能(認可) D-3「例外系: 認可失敗」 D-4(domain ルール), D-18(forbidden D-8(単体/統合) 完了 権限逸脱は許容しない
R-3 割り当ての監査記録が残る D-3「観測点: 監査/ログ」 D-4(AssignmentAudit), D-7(監査の扱い) D-8(統合) 完了 保存期間は運用要件次第
R-4 割り当て時に通知できる D-3「外部連携(通知)」 D-4(mailer adapter) D-8(統合: stub/spy) 完了 到達性は外部要因
R-5 通知失敗でも割り当て確定は成立 D-3「外部I/F失敗」 D-4(分離方針), D-7(意思決定) D-8(統合) 完了 再送は運用で扱う
R-6 通知失敗を運用で検知できる D-3「観測点: 監査/ログ」 D-4(ログ/アラート前提) D-8(統合) 完了 相関ID があると解析が短い
R-7 存在しないタスクは失敗 D-3「例外系: Not Found」 D-18(not_found D-8(統合) 完了  

ケース2(AC-ID): 期限超過の表示 + 通知

要件ID Shall(要約) 仕様(受け入れ条件/観測点) 設計(境界/ADR/エラーcode等) テスト(単体/統合/E2E) 状態 備考
DUE-1 期限ステータスを判定できる D-11「受け入れ条件」/「時刻/タイムゾーン」 D-12(期限判定を domain へ) D-16(単体) 完了 時刻は注入して固定
DUE-2 期限ステータスを表示できる D-11「外部I/F: UI」/「観測点」 D-12(DTO に必要情報のみ) D-16(統合/E2E) 完了 表示要件は変動しやすい
DUE-3 期限超過時に通知できる D-11「外部連携(通知)」 D-12(通知 I/F を境界化) D-16(統合) 完了  
DUE-4 期限超過通知が重複しない D-11「冪等性(二重実行)」 D-12(冪等キー/記録) D-16(単体/統合) 完了 二重実行を前提にする
DUE-5 通知結果を運用で検知できる D-11「観測点」 D-12(ログ/メトリクス) D-16(統合) 完了  

D-20. 受け入れ条件(AC)ID 管理(記入例)(B-12)

対象: ケース1(タスク割り当て + 通知)

AC ID 要件ID Given(前提) When(操作/イベント) Then(期待結果/観測点) 例外系/エラーcode 推奨テスト 備考
AC-1 R-1, R-4 管理者がログインしており、タスクが存在する 担当者を割り当てる 担当者が更新され、成功が表示される - E2E/統合 導線の最小セット
AC-2 R-2 一般ユーザーがログインしている 割り当てを実行する forbidden として失敗する forbidden 統合/単体 仕様は D-3、code は D-18
AC-3 R-7 管理者がログインしている 存在しないタスクに割り当てる not_found として失敗する not_found 統合  
AC-4 R-5, R-6 管理者がログインしている 割り当て時に通知が失敗する 割り当ては成立し、失敗が追跡できる - 統合 外部I/F到達性は分離する

対象: ケース2(期限超過の表示 + 通知)

AC ID 要件ID Given(前提) When(操作/イベント) Then(期待結果/観測点) 例外系/エラーcode 推奨テスト 備考
AC-5 DUE-1, DUE-2 dueAt=2026-01-10(JST) now=2026-01-09 で一覧を表示 due_soon として表示される - 単体/統合 判定ロジックは domain に集約
AC-6 DUE-1, DUE-2 dueAt=2026-01-10(JST) now=2026-01-11 で一覧を表示 overdue として表示される - 単体/統合  
AC-7 DUE-3〜DUE-5 期限超過タスクが存在する 検知(例: 定期ジョブ)が実行される 通知が実行され、結果が追跡できる - 統合 重複通知は DUE-4 で抑止

D-21. 認可(Authorization)ルール表(記入例)(B-13)

前提(例):

  • 役割: admin / user
  • 属性: タスクには assigneeId があり、担当者は assigneeId == actorId
  • 失敗時の振る舞い: 認可失敗は forbidden/403not_found と混同しない)
操作ID 操作(Action) 対象(Resource) 許可条件(Role/属性) 失敗時(code/HTTP) 監査/ログ 推奨テスト 備考
AUTHZ-1 assign_task task admin のみ forbidden/403 actor/taskId/code/相関ID 統合/単体 UI の表示制御に依存しない
AUTHZ-2 update_status task assigneeId == actorId forbidden/403 actor/taskId/code/相関ID 統合/単体 状態遷移ルールは D-3/D-12 を参照
AUTHZ-3 view_task task admin または assigneeId == actorId forbidden/403 actor/taskId/code/相関ID 統合 一覧/詳細の両方に適用

D-22. API 契約(記入例)(B-14)

対象: ケース1(割り当て API: POST /api/tasks/{taskId}/assignment

関連(要求/要件/受け入れ条件)

  • 要件ID: R-1, R-2, R-4, R-5, R-7
  • AC ID: AC-1, AC-2, AC-3, AC-4
  • 認可ルール(参照): D-21(AUTHZ-1)

エンドポイント

  • method/path: POST /api/tasks/{taskId}/assignment
  • 認証/認可: 認証必須、認可は admin のみ

Request

  • headers(任意):
    • Idempotency-Key: 二重送信対策(クライアントが送れる場合)
  • params:
    • taskId(path): 割り当て対象タスクID
  • body:
    • assigneeId(必須): 割り当て先のユーザーID

Response(Success)

  • status: 200
  • body(例):
    • taskId: "task-123"
    • assigneeId: "user-123"
    • assignedAt: "2026-01-10T12:34:56Z"(例: ISO 8601)

Response(Error)

最小形式(例):

  • { "code": "<reason>", "message": "<user-facing>" }
code HTTP 条件(いつ起きるか) 再試行可否 備考
forbidden 403 認可失敗(admin 以外) No D-18
not_found 404 taskId が存在しない No D-18
invalid 400 assigneeId の形式不正等 No D-18
conflict 409 同時更新/状態ルール違反 Yes/No D-18

冪等性(二重送信)/同時更新(競合)

  • 冪等性の方針(例):
    • Idempotency-Key が同一なら、同一結果(同一レスポンス)に収束させる
    • Idempotency-Key が無い場合でも、同一 taskId に同一 assigneeId の再割り当ては no-op とし、通知や監査ログが増殖しない(R-5 の運用負債を抑制)
  • 同時更新の方針(例):
    • 競合時は conflict/409 を返す(後勝ちにする場合も、方針を曖昧にしない)

ログ/監査(最小)

  • 監査/ログ: actor、taskId、assigneeId、code(失敗時)、相関ID
  • 個人情報はログに出さない(ID と code を中心にする)

D-23. データ整合性/同時更新(記入例)(B-15)

対象: ケース1(割り当て)+ ケース2(期限超過通知の重複抑止)

不変条件(Invariant)

ID 不変条件(守るべきこと) 破ると何が起きるか 守る場所(domain/DB/両方) 備考
I-1 存在しないタスクへ割り当てできない 監査/通知/表示が破綻する 両方 API は not_found/404(D-18)
I-2 done のタスクへ割り当てできない(例) 状態遷移が破綻する domain conflict/409(D-18)
I-3 割り当て変更は監査ログに記録される 説明責任が満たせない 両方 保存期間は運用要件次第
I-4 期限超過通知は重複しない(DUE-4) 運用負債(メール増殖) 両方 二重実行を前提にする

整合性境界(トランザクション)

  • 同一トランザクションで成立させるもの(例):
    • タスクの assigneeId/assignedAt 更新
    • 割り当て監査ログの追記
    • 通知要求の記録(送信の実行は別扱い)
  • 結果整合でよいもの(例):
    • メール到達(外部I/Fのため。失敗時の検知/再送は別途設計)

同時更新(競合)方針

  • 方針(例): 楽観ロック
    • tasksversion(または updatedAt)を持ち、更新時に一致確認する
    • 競合時は conflict/409 を返す(後勝ちにする場合も、方針を曖昧にしない)
  • 再試行(例):
    • API: クライアント側で再試行するかは、業務影響とUXを見て決める(上限/間隔を固定)
    • 定期ジョブ(期限超過通知): 冪等性が担保できるなら再試行可(重複抑止が前提)

DB 物理(任意: 例)

  • UNIQUE 制約(例):
    • 期限超過通知の重複抑止: (task_id, notification_type) の UNIQUE
  • バージョン列(例):
    • tasks.version(整数のインクリメント)

D-24. 外部I/F失敗時設計(記入例)(B-16)

対象: ケース1(割り当て通知: メール送信)

前提/非ゴール

  • 外部I/F: メール送信サービス(ネットワーク越し)
  • 失敗が業務に与える影響:
    • 通知失敗でも割り当ては成立させる(R-5)
    • 通知失敗は運用で検知できる(R-6)
  • 非ゴール:
    • 厳密な exactly-once は目指さない(重複抑止は「自系の範囲」で行う)
    • 外部サービスの SLA を自系で保証しない(遅延/障害は起こり得る)

失敗分類(観測できること)

code(運用) 失敗種別 再試行 期待する挙動(仕様) 観測点(ログ/メトリクス) 備考
NOTIFY-1 TIMEOUT タイムアウト Yes 通知要求は失わず、再送起点(outbox)に残る code/相関ID/attempt 一時障害
NOTIFY-2 5XX 500/503 Yes 自動再試行(上限あり)。上限超過はアラート failed/backlog 無限リトライ禁止
NOTIFY-3 RATE_LIMIT 429 Yes バックオフして再試行 retry_scheduled レート制限
NOTIFY-4 4XX 400/401/403 No 恒久失敗として保管し、手動対応 failed 設定ミス/宛先不正

失敗時の業務継続(同期/非同期)

  • 分離: する(割り当て確定とメール送信を混同しない)
  • 外部挙動(例: 割り当て API):
    • 割り当てが成立したら 200 を返す(メール送信の成功は待たない)
    • 「通知は遅延する可能性がある」を利用者へ明示(UI/ヘルプ/運用)
  • 停止させる条件:
    • なし(通知失敗で業務を止めない)

再試行/再送方針

  • 自動再試行: Yes
    • 上限: 3回(例)
    • 間隔: 1分→10分→1時間(例: バックオフ)
    • 実行主体: 定期ジョブ(ワーカー)が outbox をポーリングして送信
  • 手動再送: Yes
    • 起点: 失敗一覧(管理画面)または運用スクリプト
    • 権限: admin のみ
    • 手順(例): failedpending に戻し再送(相関IDで追跡)
  • 冪等性/重複抑止(例):
    • dedupeKey = assignment:{taskId}:{assignedAt}
    • dedupeKey を UNIQUE にし、二重登録を防ぐ
    • 外部サービスが冪等性キーを受け付ける場合は header に付与(可能なら)

永続化/キュー(任意: 例)

  • outbox テーブル(例): notification_outbox
    • columns(例): id, type, taskId, recipientId, dedupeKey, status, attempts, nextAttemptAt, lastErrorCode, lastErrorAt, createdAt
  • 状態(例): pendingsendingsent / failed
  • DLQ/保管先(例): failed 行を保持し、手動再送の対象にする
  • 保持期間(例):
    • sent: 30日(監査要件に応じて調整)
    • failed: 90日(復旧/説明責任のため)

監視/アラート(最小: 例)

  • 失敗: 直近 1 時間で failed が 1 件以上 → アラート
  • 滞留: pending が一定件数を超える、または最古の pending が 15 分を超える → アラート
  • 相関ID: API リクエスト → outbox → 送信ログまで伝播させ、原因追跡を短縮する

テスト観点(最小)

  • 単体: 失敗種別→再試行可否の判定、バックオフ計算
  • 統合:
    • 通知 I/F が失敗しても割り当ては成功し、outbox に再送起点が残る
    • dedupeKey により二重送信が増殖しない(再実行/再試行に耐える)