Skip to content

Menu — version 2

Menu bounded context — the catalogue of pizzas, sizes and toppings the pizzeria sells. It is the upstream that publishes the ubiquitous language of money and toppings; Ordering shares its Currency as a shared kernel and conforms to its Topping weight (see context-map.koi). Version 2 of the published model: a kcal nutrition field was added in v2, demonstrating contract evolution with @since.

classDiagram
    class Currency {
        <<enumeration>>
        EUR
        USD
        GBP
    }
    class MassUnit {
        <<enumeration>>
        Gram
        Kilogram
    }
    class Size {
        <<enumeration>>
        Small
        Medium
        Large
    }
    class Availability {
        <<enumeration>>
        Available
        SoldOut
        Seasonal
    }
    class Money {
        <<value object>>
        +Decimal amount
        +Currency currency
    }
    class Portion {
        <<quantity>>
        +Decimal amount
        +MassUnit unit
    }
    class HappyHour {
        <<value object>>
        +Range~Instant~ window
    }
    class Topping {
        <<value object>>
        +String name
        +Money surcharge
        +Portion portion
        +String /key
    }
    class Pizza {
        <<aggregate root>>
        +PizzaCode id
        +String name
        +Size size
        +Money basePrice
        +Availability availability
        +String description
        +Set~String~ toppings
        +Int kcal
        +String /displayName
        +String /summary
        +Bool /isAvailable
        +Bool /hasNutrition
    }
    Money *-- Currency
    Portion *-- MassUnit
    Topping *-- Money
    Topping *-- Portion
    Pizza *-- Size
    Pizza *-- Money
    Pizza *-- Availability

A pizza on the menu — the product the pizzeria sells. Its identity is a natural string key (PizzaCode as natural(String), no client-side New()), and being an aggregate root it gains an IPizzaRepository and joins the context’s generated IUnitOfWork. The repository block tunes the mutating set and adds intention-revealing finders.

Root entity: Pizza (identified by PizzaCode)

Repository finders:

  • available(): List<Pizza>
  • bySize(size: Size): List<Pizza>

Repository operations: getById, add, update

Business rules

  • a pizza needs a name

A monetary amount in a specific currency. Never negative. Currency is a shared-kernel type owned jointly with Ordering (see context-map.koi), so the same enum flows through both contexts without translation.

FieldTypeDescription
amountDecimal
currencyCurrency

Business rules

  • a price cannot be negative
FieldTypeDescription
amountDecimal
unitMassUnit

Business rules

  • a portion weight cannot be negative
FieldTypeDescription
windowRange<Instant>

A topping that can be added to a pizza — pepperoni, mushrooms, extra cheese. A first-class value object so a “topping” is never just a bare string, and a rich one: it carries its own surcharge and portion weight. Exported to Kitchen, which conforms to Menu and imports it to list a ticket’s toppings.

FieldTypeDescription
nameString
surchargeMoney
portionPortion
keyStringderived

Business rules

  • a topping needs a name

Values: EUR(”€”, 2), USD(”$”, 2), GBP(”£”, 2)

The unit a topping’s portion weight is expressed in. Drives the unit-checked arithmetic on the Portion quantity below.

Values: Gram, Kilogram

The three pizza sizes on offer. A plain enum used for routing and pricing.

Values: Small, Medium, Large

Whether a menu item is currently sellable. Defaults to Available.

Values: Available, SoldOut, Seasonal

KindCoveredTotal
aggregate11
entity11
enum44
query02
readModel01
value44

⚠️ 3 not documented