ドメインモデル設計 - 国際貨物輸送管理システム
概要
本ドキュメントは、国際貨物輸送管理システムの DDD(ドメイン駆動設計)戦術的設計を定義する。システムは以下の 6 つの境界付けられたコンテキスト(Bounded Context)で構成される。
| コンテキスト |
日本語名 |
主な責務 |
| Booking Context |
予約コンテキスト |
貨物予約の受付・旅程管理・状態遷移 |
| Routing Context |
経路コンテキスト |
航海スケジュール・経路情報の管理 |
| Tracking Context |
追跡コンテキスト |
貨物追跡・例外イベント管理 |
| Handling Context |
荷役コンテキスト |
荷役作業登録・通関申告管理 |
| Billing Context |
精算コンテキスト |
請求書発行・割引・支払い管理 |
| Shared Domain |
共有ドメイン |
共有カーネル(Location・TransportStatus) |
各コンテキストは自律的に変更可能な集約を持ち、コンテキスト間の連携はドメインイベントおよび ACL(Anti-Corruption Layer)ポートを通じて行う。
ユビキタス言語
| 英語(コード名) |
日本語(業務用語) |
使用コンテキスト |
説明 |
| Cargo |
貨物 |
Booking Context |
予約の中心的エンティティ。荷主から荷受人へ輸送される物品 |
| Shipper |
荷主 |
Booking Context |
貨物を発送する主体。個人・法人の 2 種別 |
| Consignee |
荷受人 |
Booking Context |
貨物を受け取る主体。氏名・住所・連絡先を保持 |
| BookingId |
予約 ID |
Booking Context |
予約を一意に識別する値オブジェクト |
| RouteSpecification |
ルート仕様 |
Booking Context |
出発地・目的地・到着期限の要件定義 |
| CargoItinerary |
旅程 |
Booking Context |
貨物の輸送経路全体。1 つ以上の Leg で構成 |
| Leg |
輸送区間 |
Booking Context |
単一航海での積込港から荷降港までの区間 |
| Delivery |
配送状況 |
Booking Context |
現在の輸送状態・経路状態・最終荷役イベントの集合 |
| Voyage |
航海 |
Routing Context |
特定の船舶が実施する一連の運送区間 |
| Schedule |
航海スケジュール |
Routing Context |
航海を構成する時系列の運送区間一覧 |
| CarrierMovement |
運送区間 |
Routing Context |
出発港・到着港・出発時刻・到着時刻を持つ区間単位 |
| TrackingActivity |
追跡レコード |
Tracking Context |
貨物の追跡情報全体を管理する集約 |
| TrackingNumber |
追跡番号 |
Tracking Context |
追跡活動を一意に識別する番号 |
| TrackingActivityEvent |
追跡イベント |
Tracking Context |
時系列で記録される追跡の出来事 |
| TrackingExceptionEvent |
追跡例外イベント |
Tracking Context |
遅延・損傷・紛失・税関保留などの例外事象 |
| HandlingActivity |
荷役作業 |
Handling Context |
実際に行われた荷役作業の記録 |
| HandlingActivityHistory |
荷役履歴 |
Handling Context |
クエリ専用の荷役作業履歴(Read Model) |
| Invoice |
精算書 |
Billing Context |
貨物輸送 1 件に対して発行される請求書 |
| DiscountPolicy |
割引方針 |
Billing Context |
法人・ボリューム・シーズン割引のポリシー |
| Location |
位置情報 |
Shared Domain |
UN/LOCODE で識別される港湾・地点の共有カーネル |
| TransportStatus |
輸送状態 |
Shared Domain |
貨物の現在の輸送フェーズを表す共有列挙型 |
| RoutingStatus |
経路状態 |
Shared Domain |
経路の妥当性状態(NOT_ROUTED / ROUTED / MISROUTED) |
| BookingStatus |
予約状態 |
Booking Context |
予約ライフサイクルの状態(8 値) |
| CargoType |
貨物種別 |
Booking Context |
GENERAL / HAZARDOUS / REFRIGERATED |
| ExceptionType |
例外種別 |
Tracking Context |
DELAY / DAMAGE / LOST / CUSTOMS_HOLD |
| CustomsStatus |
通関状態 |
Handling Context |
PENDING / CLEARED / HELD / REJECTED |
| PaymentStatus |
支払い状態 |
Billing Context |
PENDING / CONFIRMED / OVERDUE / REFUNDED |
アクターとコンテキストの対応
| アクター |
対話するコンテキスト |
主要コマンド / 操作 |
| 営業担当者 |
Booking Context |
BookCargoCommand・RouteCargoCommand・見積作成 |
| 経路設計者 |
Routing Context + Booking Context |
RouteCargoCommand・AssignTrackingNumberCommand |
| 荷役作業員 |
Handling Context |
HandlingActivityRegistrationCommand |
| 追跡管理者 |
Tracking Context |
AddTrackingEventCommand・例外登録 |
| 荷主 |
Booking Context(読取)+ Tracking Context(読取) |
追跡照会・状態確認 |
| 荷受人 |
Tracking Context(読取)+ Booking Context(読取) |
到着確認・引取手続き |
| 経理担当者 |
Billing Context |
GenerateInvoiceCommand・ConfirmPaymentCommand |
境界付けられたコンテキスト概要

1. Booking Context(予約コンテキスト)
ドメインモデル図

集約・エンティティ・値オブジェクト一覧
| 種別 |
クラス名 |
日本語名 |
責務 |
| 集約ルート |
Cargo |
貨物 |
予約の中心。状態遷移・旅程・配送状況を統括 |
| 値オブジェクト |
BookingId |
予約 ID |
予約の一意識別 |
| 値オブジェクト |
ShipperId |
荷主識別子 |
荷主 ID と種別(個人・法人)の保持 |
| 値オブジェクト |
Consignee |
荷受人情報 |
荷受人の名前・住所・連絡先メール |
| 値オブジェクト |
RouteSpecification |
ルート仕様 |
出発地・目的地・到着期限の要件定義 |
| 値オブジェクト |
CargoItinerary |
旅程 |
輸送区間(Leg)の集合と到着時刻計算 |
| 値オブジェクト |
Leg |
輸送区間 |
単一航海での積込港から荷降港までの区間 |
| 値オブジェクト |
Delivery |
配送状況 |
現在の輸送状態・経路状態・最終荷役イベント |
| 値オブジェクト |
Money |
金額 |
金額と通貨コードのペア。多通貨対応 |
| 値オブジェクト |
CargoHandlingActivity |
荷役活動(参照用) |
最終荷役イベントの記録 |
| 列挙型 |
BookingStatus |
予約状態 |
8 段階の予約ライフサイクル |
| 列挙型 |
ShipperType |
荷主種別 |
INDIVIDUAL / CORPORATE |
| 列挙型 |
CargoType |
貨物種別 |
GENERAL / HAZARDOUS / REFRIGERATED |
| 列挙型 |
RoutingStatus |
経路状態 |
NOT_ROUTED / ROUTED / MISROUTED |
ビジネスルール
- 貨物は必ず BookingId・ShipperId・CargoType を持つ
- RouteSpecification の出発地と目的地は異なる(UN/LOCODE 形式で検証)
- CargoItinerary は 1 つ以上の Leg で構成される。
Leg[n].unloadLocation == Leg[n+1].loadLocation の連結制約を満たす必要がある
- BookingStatus の遷移は
PRELIMINARY → ROUTE_PROPOSED → CONFIRMED → TRACKING_ISSUED → IN_TRANSIT → DELIVERED → SETTLED の順に進む。いずれの状態からも CANCELLED に遷移可能
- CORPORATE ShipperType の荷主は割引適用の対象となる
- HAZARDOUS / REFRIGERATED の CargoType は指定港のみ取扱可能
コマンド一覧
| コマンド |
実行アクター |
主な処理 |
| BookCargoCommand |
営業担当者 |
貨物予約の新規登録(PRELIMINARY 状態で作成) |
| RouteCargoCommand |
経路設計者 |
CargoItinerary を Cargo に割り当て、ROUTE_PROPOSED → CONFIRMED に遷移 |
| AssignTrackingNumberCommand |
経路設計者 |
TrackingNumber を Cargo に紐付け、TRACKING_ISSUED に遷移 |
| UpdateBookingStatusCommand |
システム |
BookingStatus の状態遷移を更新 |
2. Routing Context(経路コンテキスト)
ドメインモデル図

集約・エンティティ・値オブジェクト一覧
| 種別 |
クラス名 |
日本語名 |
責務 |
| 集約ルート |
Voyage |
航海 |
航路スケジュールを管理する中心エンティティ |
| 値オブジェクト |
VoyageNumber |
航海番号 |
Routing Context 固有の航海一意識別子 |
| 値オブジェクト |
Schedule |
航海スケジュール |
時系列の CarrierMovement 一覧を保持 |
| エンティティ |
CarrierMovement |
運送区間 |
出発地・到着地・出発時刻・到着時刻の区間単位 |
| 共有カーネル参照 |
Location |
位置情報 |
UN/LOCODE で識別される港湾・地点 |
ビジネスルール
- 航海は必ず一意の VoyageNumber を持つ
- Schedule は時系列順の CarrierMovement で構成される
- CarrierMovement の出発地と到着地は異なる
- Location は UN/LOCODE で一意に識別される(例:
JPOSA = 大阪、USLAX = LA)
コマンド一覧
| コマンド |
実行アクター |
主な処理 |
| RegisterVoyageCommand |
経路設計者 |
新規航海スケジュールの登録 |
| UpdateScheduleCommand |
経路設計者 |
運送区間の追加・変更 |
3. Tracking Context(追跡コンテキスト)
ドメインモデル図

集約・エンティティ・値オブジェクト一覧
| 種別 |
クラス名 |
日本語名 |
責務 |
| 集約ルート |
TrackingActivity |
追跡レコード |
貨物の追跡情報全体を管理 |
| エンティティ(集約内) |
TrackingActivityEvent |
追跡イベント |
時系列で記録される追跡の出来事 |
| エンティティ(集約内) |
TrackingExceptionEvent |
追跡例外イベント |
遅延・損傷・紛失・税関保留の例外記録 |
| 値オブジェクト |
TrackingNumber |
追跡番号 |
追跡活動を一意に識別 |
| 値オブジェクト |
TrackingBookingId |
予約参照 ID |
Booking Context との関連を保持 |
| 値オブジェクト |
TrackingLocation |
追跡位置情報 |
コンテキスト固有の位置情報型(ACL 変換) |
| 値オブジェクト |
TrackingVoyageNumber |
追跡航海番号 |
Tracking Context 固有の航海番号型 |
| 列挙型 |
TrackingStatus |
追跡状態 |
9 段階の追跡フェーズ |
| 列挙型 |
ExceptionType |
例外種別 |
DELAY / DAMAGE / LOST / CUSTOMS_HOLD |
ビジネスルール
- 追跡活動は必ず一意の TrackingNumber を持つ
- TrackingActivityEvent は時系列順で管理される。イベントごとに位置と時刻が必須
- ExceptionType が LOST の場合、escalationFlag を
true に設定し上位管理者へエスカレーションする
- CUSTOMS_HOLD 例外は税関システム(CustomsClearancePort)からの通知によって自動登録される
ResolveExceptionCommand の実行により TrackingStatus は例外発生前の状態に復帰する
コマンド一覧
| コマンド |
実行アクター |
主な処理 |
| AssignTrackingNumberCommand |
Booking Context(イベント駆動) |
TrackingActivity を新規作成し TrackingNumber を割り当て |
| AddTrackingEventCommand |
追跡管理者 |
TrackingActivityEvent を時系列で追加 |
| RegisterExceptionCommand |
追跡管理者・税関システム |
TrackingExceptionEvent を登録 |
| ResolveExceptionCommand |
追跡管理者 |
例外を解決し TrackingStatus を復帰 |
4. Handling Context(荷役コンテキスト)
ドメインモデル図

集約・エンティティ・値オブジェクト一覧
| 種別 |
クラス名 |
日本語名 |
責務 |
| 集約ルート |
HandlingActivity |
荷役作業 |
荷役作業の登録と妥当性検証 |
| エンティティ(集約内) |
CustomsDeclaration |
通関申告 |
通関申告の状態管理 |
| 値オブジェクト |
CargoBookingId |
貨物予約識別子 |
Booking Context との関連識別子 |
| 値オブジェクト |
HandlingType |
荷役種別 |
RECEIVE / LOAD / UNLOAD / CUSTOMS / CLAIM。VoyageNumber 必須判定を内包 |
| 値オブジェクト |
CargoSnapshot |
貨物スナップショット |
ACL 経由で取得した貨物情報。妥当性検証に使用 |
| 値オブジェクト |
LegSnapshot |
旅程区間スナップショット |
CargoSnapshot 内の区間情報 |
| 値オブジェクト |
VoyageNumber |
航海番号 |
Handling Context 固有の航海番号型 |
| 列挙型 |
CustomsStatus |
通関状態 |
PENDING / CLEARED / HELD / REJECTED |
| Read Model |
HandlingActivityHistory |
荷役履歴 |
クエリ専用の荷役作業履歴。集約と切り離して管理 |
ビジネスルール
荷役妥当性検証(isValidFor)のデシジョンテーブル:
| 荷役タイプ |
VoyageNumber 必須 |
場所チェック |
MISROUTED 判定条件 |
| RECEIVE(受領) |
不要 |
出発港(RouteSpecification.origin)と一致 |
不一致で警告 |
| LOAD(積込) |
必須 |
Itinerary の積込港(Leg.loadLocation)と一致 |
不一致で MISROUTED |
| UNLOAD(荷降し) |
必須 |
Itinerary の荷降港(Leg.unloadLocation)と一致 |
不一致で MISROUTED |
| CLAIM(引取) |
不要 |
目的港(RouteSpecification.destination)と一致 |
不一致で警告 |
追加ルール:
- LOAD / UNLOAD 作業で MISROUTED が確定した場合、Booking Context の RoutingStatus を MISROUTED に更新する
- CustomsDeclaration が CLEARED 状態になるまで CLAIM(引取)は実施できない
- HandlingActivityHistory はクエリ専用の Read Model として管理され、集約とは切り離す
コマンド一覧
| コマンド |
実行アクター |
主な処理 |
| HandlingActivityRegistrationCommand |
荷役作業員 |
荷役作業を登録し、CargoSnapshot で妥当性を検証 |
| RegisterCustomsDeclarationCommand |
荷役作業員 |
通関申告を新規登録(PENDING 状態で作成) |
| UpdateCustomsStatusCommand |
税関システム(ACL) |
通関申告の状態を更新(CLEARED / HELD / REJECTED) |
5. Billing Context(精算コンテキスト)
ドメインモデル図

集約・エンティティ・値オブジェクト一覧
| 種別 |
クラス名 |
日本語名 |
責務 |
| 集約ルート |
Invoice |
精算書 |
貨物輸送 1 件に対する請求書の発行・管理 |
| 値オブジェクト |
InvoiceId |
請求書 ID |
精算書の一意識別子 |
| 値オブジェクト |
BillingBookingId |
予約参照 ID |
Booking Context の Cargo との関連識別子 |
| 値オブジェクト |
BillingShipperId |
荷主参照 ID |
法人判定(isCorporate)を内包 |
| 値オブジェクト |
Money |
金額 |
金額と通貨コードのペア |
| 値オブジェクト |
DiscountRate |
割引率 |
0〜30% の割引率。範囲バリデーション付き |
| 値オブジェクト |
DiscountPolicy |
割引方針 |
法人・ボリューム・シーズン割引のロジック |
| 列挙型 |
PaymentStatus |
支払い状態 |
PENDING / CONFIRMED / OVERDUE / REFUNDED |
| 列挙型 |
DiscountPolicyType |
割引方針種別 |
CORPORATE_STANDARD / VOLUME_DISCOUNT / SEASONAL / NONE |
ビジネスルール
- Invoice は貨物配送完了(BookingStatus = DELIVERED)後にのみ発行できる
- 法人荷主(CORPORATE)には最大 30% の割引が適用される
- 支払期限(issuedAt + 30 日)を超過した場合、PaymentStatus を OVERDUE に更新する
- 支払い確定(CONFIRMED)後のキャンセルは
IssueRefundCommand で対応し、REFUNDED 状態に遷移する
料金計算ロジック:
基本料金 = 距離係数 × 重量(kg) × 貨物種別係数
- GENERAL(一般貨物): 係数 1.0
- HAZARDOUS(危険物): 係数 1.8
- REFRIGERATED(冷凍・冷蔵): 係数 1.5
割引後料金 = 基本料金 × (1 - 割引率)
- CORPORATE 荷主: 割引率 0〜30%
- INDIVIDUAL 荷主: 割引なし(割引率 0%)
コマンド一覧
| コマンド |
実行アクター |
主な処理 |
| GenerateInvoiceCommand |
経理担当者 |
請求書を新規発行(PENDING 状態で作成) |
| ConfirmPaymentCommand |
経理担当者 |
支払い確認を記録し CONFIRMED に遷移 |
6. Shared Domain(共有ドメイン)
ドメインモデル図

共有コンポーネント一覧
| 種別 |
クラス名 |
日本語名 |
責務 |
| 共有カーネル |
Location |
位置情報 |
UN/LOCODE で識別される港湾・地点。全コンテキストで共有 |
| 共有列挙型 |
TransportStatus |
輸送状態 |
9 段階の輸送フェーズ。Booking・Tracking で共有 |
| 共有列挙型 |
RoutingStatus |
経路状態 |
NOT_ROUTED / ROUTED / MISROUTED。Booking・Handling で共有 |
VoyageNumber のコンテキスト分離設計
VoyageNumber は各コンテキストが独自型を保持する。これにより各コンテキストの自律性を保ちながら意味的な一貫性を維持する。
| コンテキスト |
型名 |
役割 |
| Routing Context |
VoyageNumber |
航海スケジュールの識別子 |
| Tracking Context |
TrackingVoyageNumber |
追跡イベントに紐づく航海番号(ACL 変換) |
| Handling Context |
HandlingVoyageNumber |
荷役作業に紐づく航海番号(ACL 変換) |
ビジネスルール
- Location の変更は全コンテキストチームの合意のもとに行う(Shared Kernel の制約)
- UN/LOCODE は国際規格(ISO 3166-1 alpha-2 + 3 文字のロケーションコード)に従う
- TransportStatus と RoutingStatus は Booking Context と Tracking / Handling Context の間で整合性を保つ
ドメインイベント
| イベント名 |
発生元 |
処理先 |
内容 |
| CargoBookedEvent |
Booking Context |
Tracking Context |
新規貨物予約後、追跡番号割り当て依頼を通知 |
| CargoRoutedEvent |
Booking Context |
Tracking Context |
旅程確定後、経路・旅程情報を追跡コンテキストに同期 |
| HandlingActivityRegisteredEvent |
Handling Context |
Tracking Context・Booking Context |
荷役作業完了後、TransportStatus と BookingStatus を同期 |
| TrackingExceptionDetectedEvent |
Tracking Context |
Booking Context・Notification |
例外(遅延・損傷・紛失・税関保留)検知後、通知を配信 |
| InvoiceCreatedEvent |
Billing Context |
Notification |
請求書発行後、荷主への通知を配信 |
ドメインイベントフロー

外部システム ACL Ports
| ポート名 |
対応外部システム |
責務 |
| ExternalRoutingServicePort |
外部経路最適化システム |
出発地・目的地・期限を渡し最適 CargoItinerary を取得 |
| CustomsClearancePort |
税関システム |
通関申告の提出・状態照会・CUSTOMS_HOLD 例外の自動通知受信 |
| PaymentGatewayPort |
決済機関 |
支払い処理の実行と支払い確認の受信 |
| PortManagementPort |
港湾管理システム |
港湾の取扱可能貨物種別(HAZARDOUS / REFRIGERATED)の照会 |
| NotificationPort |
通知システム |
荷主・荷受人へのメール / SMS 通知の送信 |
各ポートはヘキサゴナルアーキテクチャの出力ポート(Secondary Port)として定義され、インフラ層のアダプターが実装を担う。これにより外部システムの変更がドメインロジックに影響しない。
集約設計の判断
Booking Context:Cargo 集約
Cargo を集約ルートとし、BookingId・ShipperId・RouteSpecification・CargoItinerary・Delivery を集約内に含める設計とした。
根拠:予約の状態遷移(BookingStatus)はこれらのオブジェクトが一体として整合性を保つ必要がある。特に CargoItinerary の Leg 連結制約(Leg[n].unloadLocation == Leg[n+1].loadLocation)は単一トランザクション内で検証しなければ不整合が生じる。Consignee は Cargo に対して 1 対 1 であるため、独立した集約とせず値オブジェクトとして含める。
Routing Context:Voyage 集約
Voyage を集約ルートとし、Schedule(CarrierMovement のリスト)を内包する設計とした。
根拠:Schedule と CarrierMovement は Voyage の文脈でのみ意味を持つ。Schedule の時系列整合性(CarrierMovement の順序・連続性)は Voyage 単位で保証する必要があるため、単一集約に含める。
Tracking Context:TrackingActivity 集約
TrackingActivity を集約ルートとし、TrackingActivityEvent と TrackingExceptionEvent を集約内エンティティとして管理する設計とした。
根拠:追跡状態(TrackingStatus)は時系列の全イベントと例外状態を総合的に判定するため、単一集約としてまとめる必要がある。例外解決時に「例外発生前の状態に復帰」するロジックは集約内の一貫したトランザクションで実行される。
Handling Context:HandlingActivity 集約 + Read Model 分離
HandlingActivity を集約ルートとし、CustomsDeclaration を集約内エンティティとした。荷役履歴は Read Model(HandlingActivityHistory)として集約と切り離す設計とした。
根拠:個々の荷役作業は独立した記録単位であり、互いに強い整合性制約を持たない。一方、通関申告(CustomsDeclaration)と荷役作業は「CLEARED にならないと CLAIM 不可」という不変条件があるため、同一集約に含める。クエリ専用の履歴参照は Read Model として分離することで、コマンド側(集約)の複雑性を低減する。
Billing Context:Invoice 集約
Invoice を集約ルートとし、DiscountPolicy はドメインサービスではなく値オブジェクトとして Invoice に委譲する設計とした。
根拠:請求書 1 件の整合性(基本料金・割引率・最終金額の一貫性)は Invoice 集約内で保証される。DiscountPolicy の割引率計算ロジックは Invoice の applyDiscount() 内で完結するため、外部ドメインサービスとして切り出す必要はない。支払い状態(PaymentStatus)の遷移も Invoice 集約が責任を持つ。