Delivery — version 1
Delivery bounded context — getting a delivery order to the customer’s door. It owns the Address value object (supplied downstream to nobody else here, but a customer-supplier candidate) and enforces the rule that anchors this context: a delivery order must carry a delivery address.
Domain Model
Section titled “Domain Model”classDiagram
class DeliveryStatus {
<<enumeration>>
Scheduled
PickedUp
EnRoute
Delivered
Failed
}
class Address {
<<value object>>
+String street
+String city
+String postalCode
+String country
+String /formatted
}
class Courier {
<<value object>>
+String name
+String phone
}
class DeliveryScheduled {
<<event>>
+DeliveryId delivery
+OrderId order
}
class DeliveryCompleted {
<<event>>
+DeliveryId delivery
}
class Delivery {
<<aggregate root>>
+DeliveryId id
+OrderId order
+Address destination
+Courier courier
+DeliveryStatus status
+Bool /assigned
+Bool /isDelivered
+schedule(OrderId order, Address destination) Delivery
+pickUp(Courier by)
+depart()
+complete()
}
DeliveryScheduled --> Delivery
DeliveryCompleted --> Delivery
Delivery *-- Address
Delivery *-- Courier
Delivery *-- DeliveryStatus
Aggregates
Section titled “Aggregates”Dispatch
Section titled “Dispatch”The delivery aggregate: one record per delivery order. Being an aggregate root it gains an IDeliveryRepository and joins the context UoW; the repository block adds intention-revealing finders.
Root entity: Delivery (identified by DeliveryId)
Repository finders:
enRoute(): List<Delivery>byCourier(courier: Courier): List<Delivery>
Repository operations: getById, add, update
Domain Events
Section titled “Domain Events”DeliveryScheduled
Raised inside the aggregate when a delivery is scheduled by the factory.
| Field | Type | Description |
|---|---|---|
| delivery | DeliveryId | |
| order | OrderId |
DeliveryCompleted
Raised when a delivery is completed.
| Field | Type | Description |
|---|---|---|
| delivery | DeliveryId |
Lifecycle
Section titled “Lifecycle”stateDiagram-v2
[*] --> Scheduled
Scheduled --> PickedUp
Scheduled --> Failed
PickedUp --> EnRoute
PickedUp --> Failed
EnRoute --> Delivered
EnRoute --> Failed
Delivered --> [*]
Failed --> [*]
| From | To | Guard |
|---|---|---|
Scheduled | PickedUp | |
Scheduled | Failed | |
PickedUp | EnRoute | |
PickedUp | Failed | |
EnRoute | Delivered | |
EnRoute | Failed | |
Delivered | (terminal) | |
Failed | (terminal) |
Commands
Section titled “Commands”pickUp(by: Courier)
Section titled “pickUp(by: Courier)”Assign a courier and have them collect the order.
Preconditions:
- only a scheduled delivery can be picked up
Effects:
courier -> bystatus -> PickedUp
depart()
Section titled “depart()”Send a picked-up delivery on its way.
Preconditions:
- only a picked-up delivery can depart
- a delivery cannot depart without a courier
Effects:
status -> EnRoute
complete()
Section titled “complete()”Mark a delivery as completed at the door.
Preconditions:
- only an en-route delivery can be completed
Effects:
status -> Delivered
Events:
DeliveryCompleted(delivery: id)
Factory Operations
Section titled “Factory Operations”schedule(order: OrderId, destination: Address)
Section titled “schedule(order: OrderId, destination: Address)”Schedule a delivery for a placed delivery order. The same-named parameters auto-bind the required fields; status defaults to Scheduled.
Preconditions:
- a delivery order requires a delivery address
Events:
DeliveryScheduled(delivery: id, order: order)
Invariants
Section titled “Invariants”Business rules
- a delivery order requires a delivery address
- a delivery en route must have a courier
Domain Types
Section titled “Domain Types”Address — value object
Section titled “Address — value object”A street address a pizza can be delivered to. A first-class value object so a delivery destination is never a bare string, validated by shape and normalized via string ops. Owned here and supplied to partners (see context-map).
| Field | Type | Description |
|---|---|---|
| street | String | |
| city | String | |
| postalCode | String | |
| country | String | |
| formatted | String | derived |
Business rules
- a delivery needs a street
- a delivery needs a city
- invalid postal code
Courier — value object
Section titled “Courier — value object”A driver assigned to a delivery. A small value object so an assignee is typed.
| Field | Type | Description |
|---|---|---|
| name | String | |
| phone | String |
Business rules
- a courier needs a name
DeliveryStatus — enum
Section titled “DeliveryStatus — enum”How a delivery is doing. Drives the states status { … } machine below.
Values: Scheduled, PickedUp, EnRoute, Delivered, Failed
Services
Section titled “Services”DeliveryService
Section titled “DeliveryService”The application service interface (IDeliveryService).
Use Cases
Section titled “Use Cases”-
ScheduleDelivery(order: OrderId, destination: Address): DeliveryId -
CompleteDelivery(delivery: DeliveryId)
Coverage
Section titled “Coverage”| Kind | Covered | Total |
|---|---|---|
| aggregate | 1 | 1 |
| entity | 1 | 1 |
| enum | 1 | 1 |
| event | 2 | 2 |
| query | 0 | 1 |
| readModel | 0 | 1 |
| value | 2 | 2 |
⚠️ 2 not documented