Skip to content

Commit 95e751a

Browse files
respencer-nclclaude
andcommitted
Rectify Reactive BBQ tutorial with verbatim riddl-models source
Replaces fabricated RIDDL snippets with actual code from the riddl-models repository. Adds 14 per-context pages covering all 11 bounded contexts plus external contexts and cross-cutting patterns. Rewrites 5 existing pages and restructures navigation. - 6 Restaurant context pages (FOH, Kitchen, Bar, Online, Delivery, Loyalty) - 3 BackOffice context pages (Scheduling, Inventory, Reporting) - 3 Corporate context pages (Menu Management, Supply Chain, Marketing) - External contexts page (6 third-party integrations) - Patterns page (7 cross-cutting RIDDL patterns) - All GitHub links updated from riddl-examples to riddl-models Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9fedc8b commit 95e751a

20 files changed

Lines changed: 3860 additions & 241 deletions
Lines changed: 79 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,101 @@
11
---
2-
title: "Back Office Subdomain"
3-
description: "Administrative operations in the Reactive BBQ domain model"
2+
title: "BackOffice Domain"
3+
description: "Administrative operations in the Reactive BBQ model"
44
---
55

6-
# Back Office Subdomain
6+
# BackOffice Domain
77

8-
The Back Office subdomain handles administrative and management functions
9-
that support restaurant operations but aren't directly customer-facing.
8+
The BackOffice domain handles administrative and management functions
9+
that support restaurant operations but aren't directly
10+
customer-facing. It contains three bounded contexts and two external
11+
system integrations.
1012

11-
## Bounded Contexts
12-
13-
### Scheduling
13+
## Domain Definition
1414

15-
Manages staff schedules and shifts:
16-
17-
- **Shift Planning** - Creating weekly schedules
18-
- **Time Tracking** - Recording hours worked
19-
- **Coverage** - Ensuring adequate staffing
15+
```riddl
16+
domain BackOffice is {
17+
18+
author OssumInc is {
19+
name is "Ossum Inc."
20+
email is "info@ossuminc.com"
21+
} with {
22+
briefly "Author"
23+
described by "Ossum Inc."
24+
}
2025
21-
Key entities:
22-
- `Employee` - Staff member with role and availability
23-
- `Shift` - Time slot with required roles
24-
- `Schedule` - Weekly assignment of employees to shifts
26+
user Manager is "Restaurant manager overseeing daily operations" with {
27+
briefly "Manager"
28+
described by "Manages scheduling, inventory, and reporting."
29+
}
2530
26-
### Inventory
31+
user InventoryClerk is "Staff member managing stock" with {
32+
briefly "Inventory Clerk"
33+
described by "Receives shipments, tracks stock levels, and reorders."
34+
}
2735
28-
Tracks stock levels and supplies:
36+
include "SchedulingContext.riddl"
37+
include "InventoryContext.riddl"
38+
include "ReportingContext.riddl"
39+
include "external-contexts.riddl"
40+
41+
} with {
42+
briefly "Back office operations domain"
43+
described by {
44+
| Covers staff scheduling, inventory management, and
45+
| operational reporting. Reporting is isolated in its
46+
| own context with CQRS projectors so that report
47+
| generation never degrades peak-hour performance.
48+
}
49+
}
50+
```
2951

30-
- **Stock Levels** - Current inventory counts
31-
- **Reordering** - Automated low-stock alerts
32-
- **Receiving** - Recording deliveries
52+
Notice the `user` definitions at the domain level — Manager and
53+
InventoryClerk are personas specific to back-office operations.
3354

34-
Key entities:
35-
- `InventoryItem` - Product with quantity and reorder point
36-
- `StockTransaction` - Record of stock changes
37-
- `PurchaseOrder` - Order to supplier
55+
## Bounded Contexts
3856

39-
### Reporting
57+
| Context | Purpose | Entities | Details |
58+
|---------|---------|----------|---------|
59+
| [Scheduling](scheduling.md) | Shift planning, time tracking | Shift | 6-command lifecycle |
60+
| [Inventory](inventory.md) | Stock levels, consumption | InventoryItem | Kitchen integration |
61+
| [Reporting](reporting.md) | Sales, labor, inventory reports | *(none)* | Pure CQRS projectors |
4062

41-
Generates management reports:
63+
Plus two [external contexts](../external-contexts.md):
64+
**HRSystem** and **AccountingSystem**.
4265

43-
- **Sales Reports** - Daily, weekly, monthly summaries
44-
- **Labor Reports** - Hours and costs by department
45-
- **Inventory Reports** - Usage and waste tracking
66+
## Cross-Context Integration
4667

47-
## Integration Points
68+
The BackOffice domain integrates with the Restaurant domain in
69+
two key ways:
4870

49-
The Back Office subdomain integrates with:
71+
1. **Inventory ← Kitchen** — The Inventory context has a
72+
`FromKitchen` adaptor that listens for
73+
`PreparationStarted` events. When the kitchen begins
74+
preparing an order, stock is automatically consumed.
75+
No manual tracking needed.
5076

51-
- **Restaurant** - Receives sales data, provides schedules
52-
- **Corporate** - Sends reports, receives policies
77+
2. **Reporting ← Everything** — The Reporting context has
78+
projectors that listen to events from multiple contexts:
79+
- `SalesReport` ← payment events from FrontOfHouse and
80+
OnlineOrdering
81+
- `LaborReport` ← clock-in/out events from Scheduling
82+
- `InventoryReport` ← stock events from Inventory
5383

54-
```riddl
55-
context BackOffice is {
56-
adaptor RestaurantAdapter from context Restaurant is {
57-
// Transform Restaurant events into BackOffice commands
58-
on event SaleCompleted from Restaurant.FrontOfHouse {
59-
send command RecordSale to Reporting
60-
}
61-
}
62-
}
63-
```
84+
## Design Decisions
6485

65-
## Challenges Addressed
86+
**Why isolate Reporting?** The CEO's interview revealed that
87+
report generation was slowing down production systems during
88+
peak hours. By making Reporting a pure CQRS read-model context
89+
with only projectors (no entities), reports are built
90+
asynchronously from events and never compete with production
91+
workloads.
6692

67-
| Challenge | Solution |
68-
|-----------|----------|
69-
| Report interference | Separate context, isolated resources |
70-
| Peak hour impacts | Async processing, eventual consistency |
71-
| Multi-timezone | Location-aware scheduling |
93+
**Why separate Scheduling from HR?** The HR system is modeled
94+
as an external context (`option is external`). Scheduling owns
95+
the operational shift data while HR owns the master employee
96+
records. This separation means scheduling works independently
97+
even if the HR system is down.
7298

73-
## Source Code
99+
## Source
74100

75-
See the Back Office subdomain implementation:
76-
[backoffice/domain.riddl](https://github.com/ossuminc/riddl-examples/tree/main/src/riddl/ReactiveBBQ/backoffice)
101+
[`backoffice/domain.riddl`](https://github.com/ossuminc/riddl-models/tree/main/hospitality/food-service/reactive-bbq/backoffice)
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
---
2+
title: "Inventory Context"
3+
description: "Stock level tracking with automated kitchen integration"
4+
---
5+
6+
# Inventory Context
7+
8+
The Inventory context manages stock levels, receiving,
9+
consumption tracking, manual adjustments, and reorder
10+
thresholds. It integrates with the Kitchen context to
11+
automatically track consumption as items are prepared.
12+
13+
## Purpose
14+
15+
Every restaurant location tracks hundreds of ingredients and
16+
supplies. The Inventory context provides the operational
17+
foundation: receiving shipments, tracking consumption,
18+
triggering reorder alerts, and creating purchase orders when
19+
stock runs low.
20+
21+
## Types
22+
23+
```riddl
24+
type InventoryItemId is Id(Inventory.InventoryItem) with {
25+
briefly "Inventory item identifier"
26+
described by "Unique identifier for an inventory item."
27+
}
28+
29+
type UnitOfMeasure is any of {
30+
Each,
31+
Pound,
32+
Ounce,
33+
Gallon,
34+
Liter,
35+
Case,
36+
Box
37+
} with {
38+
briefly "Unit of measure"
39+
described by "Measurement unit for inventory quantities."
40+
}
41+
42+
type InventoryItemStatus is any of {
43+
InStock,
44+
LowStock,
45+
OutOfStock,
46+
Discontinued
47+
} with {
48+
briefly "Inventory item status"
49+
described by "Current stock status of an inventory item."
50+
}
51+
52+
type StockAdjustmentReason is any of {
53+
Spoilage,
54+
Breakage,
55+
Theft,
56+
CountCorrection,
57+
Donation,
58+
OtherAdjustment
59+
} with {
60+
briefly "Stock adjustment reason"
61+
described by "Reason for a manual stock adjustment."
62+
}
63+
```
64+
65+
The `StockAdjustmentReason` enumeration captures why stock was
66+
manually adjusted — essential for loss tracking and audit
67+
compliance.
68+
69+
## Entity: InventoryItem
70+
71+
The `InventoryItem` entity has a 5-command lifecycle:
72+
73+
```riddl
74+
entity InventoryItem is {
75+
76+
command ReceiveStock is {
77+
inventoryItemId is InventoryItemId
78+
receivedQuantity is Decimal(10, 2)
79+
receivedUnit is UnitOfMeasure
80+
supplierRef is optional String(1, 100)
81+
stockReceivedAt is TimeStamp
82+
}
83+
84+
command ConsumeStock is {
85+
inventoryItemId is InventoryItemId
86+
consumedQuantity is Decimal(10, 2)
87+
consumedUnit is UnitOfMeasure
88+
consumptionRef is optional String(1, 100)
89+
}
90+
91+
command AdjustStock is {
92+
inventoryItemId is InventoryItemId
93+
adjustmentQuantity is Decimal(10, 2)
94+
adjustmentUnit is UnitOfMeasure
95+
adjustmentReason is StockAdjustmentReason
96+
adjustmentNotes is optional String(1, 500)
97+
}
98+
99+
command SetReorderThreshold is {
100+
inventoryItemId is InventoryItemId
101+
reorderThreshold is Decimal(10, 2)
102+
reorderUnit is UnitOfMeasure
103+
}
104+
105+
command CreatePurchaseOrder is {
106+
inventoryItemId is InventoryItemId
107+
orderQuantity is Decimal(10, 2)
108+
orderUnit is UnitOfMeasure
109+
preferredSupplier is optional String(1, 100)
110+
}
111+
112+
// Events: StockReceived, StockConsumed, StockAdjusted,
113+
// ReorderThresholdSet, PurchaseOrderCreated
114+
115+
state TrackedItem of InventoryItem.InventoryItemStateData
116+
117+
handler InventoryItemHandler is {
118+
on command ReceiveStock {
119+
morph entity Inventory.InventoryItem to state
120+
Inventory.InventoryItem.TrackedItem
121+
with command ReceiveStock
122+
tell event StockReceived to
123+
entity Inventory.InventoryItem
124+
}
125+
on command ConsumeStock {
126+
tell event StockConsumed to
127+
entity Inventory.InventoryItem
128+
}
129+
on command AdjustStock {
130+
tell event StockAdjusted to
131+
entity Inventory.InventoryItem
132+
}
133+
on command SetReorderThreshold {
134+
tell event ReorderThresholdSet to
135+
entity Inventory.InventoryItem
136+
}
137+
on command CreatePurchaseOrder {
138+
tell event PurchaseOrderCreated to
139+
entity Inventory.InventoryItem
140+
}
141+
}
142+
}
143+
```
144+
145+
Note that `ReceiveStock` uses `morph` — this is where an
146+
inventory item first enters the system. Subsequent commands use
147+
the standard `tell` pattern.
148+
149+
The `StockConsumed` event includes a `remainingStockLevel`
150+
field, enabling downstream systems (like the Reporting context's
151+
`InventoryReport` projector) to track stock levels without
152+
querying the entity directly.
153+
154+
## Repository
155+
156+
```riddl
157+
repository InventoryItemRepository is {
158+
schema InventoryItemData is relational
159+
of items as InventoryItem
160+
index on field InventoryItem.inventoryItemId
161+
index on field InventoryItem.inventoryItemStatus
162+
}
163+
```
164+
165+
The index on `inventoryItemStatus` enables quick queries for
166+
low-stock and out-of-stock items.
167+
168+
## Adaptor: FromKitchen
169+
170+
The most interesting part of the Inventory context is its
171+
cross-context integration with the Kitchen:
172+
173+
```riddl
174+
adaptor FromKitchen from context Restaurant.Kitchen is {
175+
handler KitchenConsumptionIntake is {
176+
on event Restaurant.Kitchen.KitchenTicket.PreparationStarted {
177+
prompt "Consume stock for items being prepared"
178+
}
179+
}
180+
} with {
181+
briefly "Kitchen adaptor"
182+
described by {
183+
| Receives preparation events from the kitchen to
184+
| automatically track stock consumption.
185+
}
186+
}
187+
```
188+
189+
When the Kitchen starts preparing a ticket
190+
(`PreparationStarted` event), the Inventory context
191+
automatically issues `ConsumeStock` commands for the ingredients
192+
required. No manual tracking needed — stock consumption follows
193+
directly from kitchen activity.
194+
195+
This is a powerful example of cross-context integration via
196+
events. The Kitchen doesn't know about inventory. It just
197+
prepares food and emits events. Inventory reacts to those
198+
events to keep stock levels accurate.
199+
200+
## Design Decisions
201+
202+
**Why automatic consumption from Kitchen events?** Manual
203+
stock tracking is error-prone and labor-intensive. By
204+
listening to `PreparationStarted` events and looking up the
205+
recipe's ingredient list, the system can automatically deduct
206+
the right quantities. Discrepancies are handled through the
207+
`AdjustStock` command with explicit reasons.
208+
209+
**Why `Decimal(10, 2)` for quantities?** Inventory items are
210+
measured in fractional quantities (2.5 pounds of brisket,
211+
0.75 gallons of sauce). Using `Decimal` instead of `Natural`
212+
supports precise tracking with proper unit handling.
213+
214+
**Cross-domain relationship:** This context is in the
215+
BackOffice domain but listens to events from the Restaurant
216+
domain's Kitchen context. This cross-domain integration is
217+
exactly what adaptors are designed for — they bridge context
218+
boundaries cleanly.
219+
220+
## Source
221+
222+
- [`InventoryContext.riddl`](https://github.com/ossuminc/riddl-models/tree/main/hospitality/food-service/reactive-bbq/backoffice/InventoryContext.riddl)
223+
- [`inventory-types.riddl`](https://github.com/ossuminc/riddl-models/tree/main/hospitality/food-service/reactive-bbq/backoffice/inventory-types.riddl)
224+
- [`InventoryItem.riddl`](https://github.com/ossuminc/riddl-models/tree/main/hospitality/food-service/reactive-bbq/backoffice/InventoryItem.riddl)

0 commit comments

Comments
 (0)