Front of House Context¶
The Front of House context manages the customer-facing operations inside each restaurant — reservations, table seating, order management, billing, and payment.
Purpose¶
Every dine-in interaction flows through Front of House. When a guest calls for a reservation, walks in, orders food and drinks, and pays the bill, this context orchestrates it. It also serves as the origin point for outbound messages to the Kitchen, Bar, and Loyalty contexts.
Interview Connection¶
This context was shaped by interviews with the Host (reservations, seating), Server (ordering, payment), and Online Customer (online reservations). Key pain points addressed:
- The Host's reservation system was unresponsive and frequently crashed, forcing paper backups
- Servers contended for limited terminals during peak hours
- System failures caused cascading impacts across the restaurant
Types¶
The context defines shared types for reservations, orders, and payments:
type ReservationId is Id(FrontOfHouse.Reservation) with {
briefly "Reservation identifier"
described by "Unique identifier for a reservation."
}
type TableOrderId is Id(FrontOfHouse.TableOrder) with {
briefly "Table order identifier"
described by "Unique identifier for a dine-in table order."
}
type TableNumber is Natural with {
briefly "Table number"
described by "Physical table number in the restaurant."
}
type PartySize is Natural with {
briefly "Party size"
described by "Number of guests in the party."
}
type ReservationStatus is any of {
Requested,
Confirmed,
Seated,
Completed,
Cancelled,
NoShow
} with {
briefly "Reservation status"
described by "Current status of a reservation."
}
type OrderStatus is any of {
DraftStatus,
SubmittedStatus,
InPreparationStatus,
ReadyToServeStatus,
BillPresentedStatus,
PaymentCompleteStatus,
ClosedStatus
} with {
briefly "Order status"
described by "Current status of a table order."
}
type PaymentMethod is any of {
Cash,
CreditCard,
DebitCard,
MobilePayment,
GiftCard
} with {
briefly "Payment method"
described by "Method used to pay for the order."
}
Notice the Id() type constructor — ReservationId is typed as
an identifier for the Reservation entity. This gives the
compiler enough information to enforce type safety across context
boundaries.
The context also defines record types for structured data:
type MenuItemInfo is {
itemCode is String(1, 50) with {
briefly "Item code"
described by "Identifier code for the menu item."
}
itemName is String(1, 200) with {
briefly "Item name"
described by "Display name of the menu item."
}
itemPrice is Decimal(8, 2) with {
briefly "Price"
described by "Price of the menu item."
}
itemCategory is String(1, 50) with {
briefly "Category"
described by "Category such as appetizer, entree, drink, dessert."
}
} with {
briefly "Menu item"
described by "An item from the restaurant menu."
}
type OrderLine is {
orderLineItem is MenuItemInfo with {
briefly "Item"
described by "The menu item ordered."
}
orderLineQuantity is Natural with {
briefly "Quantity"
described by "Number of this item ordered."
}
orderLineNotes is optional String(1, 500) with {
briefly "Notes"
described by "Special instructions for this item."
}
} with {
briefly "Order line"
described by "A single line item in an order."
}
type PaymentInfo is {
paymentMethod is PaymentMethod with {
briefly "Method"
described by "Payment method used."
}
paymentAmount is Decimal(10, 2) with {
briefly "Amount"
described by "Amount paid."
}
tipAmount is optional Decimal(8, 2) with {
briefly "Tip"
described by "Tip amount if applicable."
}
transactionRef is optional String(1, 100) with {
briefly "Transaction reference"
described by "External payment transaction reference."
}
} with {
briefly "Payment information"
described by "Payment details for an order."
}
Reservation Entity¶
The Reservation entity models the full lifecycle from request
through confirmation, seating, or cancellation:
entity Reservation is {
command MakeReservation is {
reservationId is ReservationId
guestName is GuestName
guestPhone is GuestPhone
partySize is PartySize
reservationTime is TimeStamp
}
command ConfirmReservation is {
reservationId is ReservationId
confirmedTable is TableNumber
}
command CancelReservation is {
reservationId is ReservationId
cancellationReason is optional String(1, 500)
}
command SeatParty is {
reservationId is ReservationId
seatedTable is TableNumber
seatedAt is TimeStamp
}
// Events mirror commands
event ReservationMade is { ... }
event ReservationConfirmed is { ... }
event ReservationCancelled is { ... }
event PartySeated is { ... }
state ActiveReservation of Reservation.ReservationStateData
handler ReservationHandler is {
on command MakeReservation {
morph entity FrontOfHouse.Reservation to state
FrontOfHouse.Reservation.ActiveReservation
with command MakeReservation
tell event ReservationMade to
entity FrontOfHouse.Reservation
}
on command ConfirmReservation {
tell event ReservationConfirmed to
entity FrontOfHouse.Reservation
}
on command CancelReservation {
tell event ReservationCancelled to
entity FrontOfHouse.Reservation
}
on command SeatParty {
tell event PartySeated to
entity FrontOfHouse.Reservation
}
}
}
The morph statement in MakeReservation creates the entity
instance, transitioning it from non-existence to the
ActiveReservation state. Subsequent commands use tell to emit
events that update the entity's state.
TableOrder Entity¶
The TableOrder entity has a 7-command lifecycle covering the
full dine-in order flow:
| Command | What Happens |
|---|---|
CreateOrder |
Server opens an order for a table |
AddItem |
Server adds a menu item |
RemoveItem |
Server removes a menu item |
SubmitOrder |
Order sent to kitchen and bar |
PresentBill |
Bill presented to the table |
ProcessPayment |
Payment collected |
CloseOrder |
Order finalized and closed |
The handler follows the same pattern — morph on creation,
tell for subsequent state transitions.
Repositories¶
Two repositories persist the entity data:
repository ReservationRepository is {
schema ReservationData is relational
of reservations as Reservation
index on field Reservation.reservationId
index on field Reservation.guestName
index on field Reservation.reservationTime
}
repository TableOrderRepository is {
schema TableOrderData is relational
of orders as TableOrder
index on field TableOrder.tableOrderId
index on field TableOrder.tableNumber
}
The schema definition specifies storage as relational with
named indexes. The index on field clauses tell the system
which fields need fast lookup — essential for finding
reservations by guest name or time.
Projector: ReservationBoard¶
The ReservationBoard projector provides a real-time read
model for the host's seating display, replacing the paper
backup system:
projector ReservationBoard is {
updates repository ReservationRepository
record ReservationBoardEntry is {
reservationId is ReservationId
guestName is GuestName
partySize is PartySize
reservationTime is TimeStamp
reservationStatus is ReservationStatus
assignedTable is optional TableNumber
}
handler ReservationBoardHandler is {
on event Reservation.ReservationMade {
prompt "Add reservation to board"
}
on event Reservation.ReservationConfirmed {
prompt "Update board entry to confirmed"
}
on event Reservation.ReservationCancelled {
prompt "Remove cancelled reservation from board"
}
on event Reservation.PartySeated {
prompt "Update board entry to seated"
}
}
}
This is a CQRS read model — it listens to reservation events and projects them into a denormalized view optimized for the host's display screen.
Adaptors¶
Front of House has three outbound adaptors that route messages to other contexts:
adaptor ToKitchen to context Restaurant.Kitchen is {
handler KitchenRouting is {
on command Restaurant.Kitchen.KitchenTicket.ReceiveTicket {
prompt "Route food items from submitted order to kitchen"
}
}
}
adaptor ToBar to context Restaurant.Bar is {
handler BarRouting is {
on command Restaurant.Bar.DrinkOrder.ReceiveDrinkOrder {
prompt "Route drink items from submitted order to bar"
}
}
}
adaptor ToLoyalty to context Restaurant.Loyalty is {
handler LoyaltyRouting is {
on command Restaurant.Loyalty.LoyaltyAccount.AccruePoints {
prompt "Send payment event to loyalty for point accrual"
}
}
}
When a table order is submitted, the ToKitchen adaptor extracts
the food items and creates a kitchen ticket, while the ToBar
adaptor extracts drink items and creates a drink order. When
payment is processed, the ToLoyalty adaptor triggers point
accrual.
Design Decisions¶
Why is Front of House separate from Kitchen and Bar? These are different bounded contexts with different ubiquitous languages. A "ticket" in the kitchen is not the same concept as an "order" at the table. Separating them means each context can evolve independently — the kitchen display can be redesigned without affecting table ordering.
Why the ReservationBoard projector? The Host's interview revealed that when the reservation system crashes, they fall back to paper. The projector provides a read-optimized view that stays current through events. If the main entity processing is slow, the board still shows the last known state.