@eventmodelers/cli 1.0.35 → 1.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/shared/skills/learn-eventmodelers-api/SKILL.md +12 -10
- package/stacks/modeling-kit/templates/.claude/skills/add-next-slice/SKILL.md +2 -23
- package/stacks/modeling-kit/templates/.claude/skills/add-next-slice/references/api-fallback.md +11 -0
- package/stacks/modeling-kit/templates/.claude/skills/analyze-existing-model/SKILL.md +6 -57
- package/stacks/modeling-kit/templates/.claude/skills/analyze-existing-model/references/api-fallback.md +68 -0
- package/stacks/modeling-kit/templates/.claude/skills/attributes/SKILL.md +4 -61
- package/stacks/modeling-kit/templates/.claude/skills/attributes/references/api-fallback.md +39 -0
- package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/SKILL.md +9 -53
- package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/references/api-fallback.md +63 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-applying-conways-law/SKILL.md +9 -319
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-applying-conways-law/references/examples.md +329 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/SKILL.md +23 -199
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/references/api-fallback.md +97 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/references/examples.md +35 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/SKILL.md +13 -410
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/references/api-fallback.md +22 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/references/examples.md +397 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-automation-chains/SKILL.md +132 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-automation-chains/references/api-fallback.md +21 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/SKILL.md +9 -236
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/references/examples.md +257 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/SKILL.md +28 -302
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/references/api-fallback.md +31 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/references/examples.md +216 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/SKILL.md +30 -343
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/references/api-fallback.md +79 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/references/examples.md +282 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md +51 -399
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/references/api-fallback.md +67 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/references/examples.md +273 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/SKILL.md +45 -152
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/domain-patterns.md +49 -90
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/patterns.md +64 -137
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/SKILL.md +74 -65
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/references/api-fallback.md +51 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-plotting-events/SKILL.md +1 -5
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-plotting-events/references/api-fallback.md +10 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/SKILL.md +19 -36
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/api-fallback.md +41 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/examples.md +12 -9
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/patterns.md +1 -10
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md +26 -332
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/references/api-fallback.md +77 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/references/examples.md +271 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-translating-external-events/SKILL.md +9 -294
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-translating-external-events/references/examples.md +306 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/SKILL.md +12 -11
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/references/api-fallback.md +14 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models-checklist/SKILL.md +6 -36
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models-checklist/references/api-fallback.md +14 -0
- package/stacks/modeling-kit/templates/.claude/skills/examples/SKILL.md +3 -110
- package/stacks/modeling-kit/templates/.claude/skills/examples/references/api-fallback.md +118 -0
- package/stacks/modeling-kit/templates/.claude/skills/handle-comment/SKILL.md +5 -25
- package/stacks/modeling-kit/templates/.claude/skills/handle-comment/references/api-fallback.md +35 -0
- package/stacks/modeling-kit/templates/.claude/skills/html-screen/SKILL.md +9 -44
- package/stacks/modeling-kit/templates/.claude/skills/html-screen/references/api-fallback.md +51 -0
- package/stacks/modeling-kit/templates/.claude/skills/place-element/SKILL.md +23 -183
- package/stacks/modeling-kit/templates/.claude/skills/place-element/references/api-fallback.md +193 -0
- package/stacks/modeling-kit/templates/.claude/skills/storyboard/SKILL.md +14 -81
- package/stacks/modeling-kit/templates/.claude/skills/storyboard/references/api-fallback.md +74 -0
- package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/SKILL.md +4 -45
- package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/references/api-fallback.md +44 -0
- package/stacks/modeling-kit/templates/.claude/skills/timeline/SKILL.md +19 -88
- package/stacks/modeling-kit/templates/.claude/skills/timeline/references/api-fallback.md +91 -0
- package/stacks/modeling-kit/templates/.claude/skills/update-prompt-status/SKILL.md +1 -9
- package/stacks/modeling-kit/templates/.claude/skills/update-prompt-status/references/api-fallback.md +14 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-integrating-legacy-systems/SKILL.md +0 -674
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/snapshotting.md +0 -204
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Identifying Outputs — curl Fallback Calls
|
|
2
|
+
|
|
3
|
+
Only needed when MCP is not connected. Every call below has an MCP equivalent in the main SKILL.md — always prefer that.
|
|
4
|
+
|
|
5
|
+
## Step 5f — Placing a READMODEL node (full manual sequence)
|
|
6
|
+
|
|
7
|
+
1. Find the column where the consumer SCREEN or AUTOMATION lives. For an AUTOMATION, the read model's target column is always the one immediately **before** it (skip straight to inserting that column — its interaction row is guaranteed occupied by the automation's own COMMAND). For a SCREEN, target the screen's own column. Fetch the timeline to get the interaction row ID:
|
|
8
|
+
```bash
|
|
9
|
+
curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
10
|
+
"$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/$CHAPTER_ID"
|
|
11
|
+
# → timelineData.rows — find the row where type === "interaction"
|
|
12
|
+
```
|
|
13
|
+
2. Check if the target interaction cell is already occupied (existing COMMAND):
|
|
14
|
+
```bash
|
|
15
|
+
curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?cellId=<interactionRowId>-<columnId>" \
|
|
16
|
+
-H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID"
|
|
17
|
+
```
|
|
18
|
+
If a COMMAND occupies that cell, insert a new column immediately **before** it (`{"index": currentIndex}` — this shifts the consumer's column, and everything after it, one to the right) and use that new column's ID instead. The read model must end up upstream of (to the left of) its consumer, never downstream of it.
|
|
19
|
+
3. `cellId = interactionRow.id + "-" + columnId`
|
|
20
|
+
4. Create the READMODEL:
|
|
21
|
+
```bash
|
|
22
|
+
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
|
|
23
|
+
-H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: identifying-outputs" \
|
|
24
|
+
-H "Content-Type: application/json" \
|
|
25
|
+
-d '[{
|
|
26
|
+
"id": "<event-uuid>",
|
|
27
|
+
"eventType": "node:created",
|
|
28
|
+
"nodeId": "<node-uuid>",
|
|
29
|
+
"boardId": "<BOARD_ID>",
|
|
30
|
+
"timestamp": 1234567890,
|
|
31
|
+
"chapterId": "<CHAPTER_ID>",
|
|
32
|
+
"cellId": "<interactionRowId>-<columnId>",
|
|
33
|
+
"meta": {"type": "READMODEL", "title": "ActiveReservationView", "fields": [...]}
|
|
34
|
+
}]'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Step 5h.1 — Wire EVENT → READMODEL
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?cellId=<swimlaneRowId>-<columnId>" \
|
|
41
|
+
-H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: eventmodeling-identifying-outputs"
|
|
42
|
+
```
|
|
43
|
+
Connect it:
|
|
44
|
+
```bash
|
|
45
|
+
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/connections" \
|
|
46
|
+
-H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: eventmodeling-identifying-outputs" \
|
|
47
|
+
-H "Content-Type: application/json" \
|
|
48
|
+
-d '{"source":"<eventNodeId>","target":"<readmodelNodeId>"}'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Step 5h.2 — Wire READMODEL → SCREEN
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/connections" \
|
|
55
|
+
-H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: eventmodeling-identifying-outputs" \
|
|
56
|
+
-H "Content-Type: application/json" \
|
|
57
|
+
-d '{"source":"<readmodelNodeId>","target":"<screenNodeId>"}'
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Step 5h.3 — Wire READMODEL → AUTOMATION
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/connections" \
|
|
64
|
+
-H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: eventmodeling-identifying-outputs" \
|
|
65
|
+
-H "Content-Type: application/json" \
|
|
66
|
+
-d '{"source":"<readmodelNodeId>","target":"<automationNodeId>"}'
|
|
67
|
+
```
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# Identifying Outputs — Worked Examples
|
|
2
|
+
|
|
3
|
+
These are conceptual worked examples of the read-model design thinking this step applies — useful for understanding the reasoning, but the actual mechanics live in the numbered Step 5a–5i sections of the main SKILL.md (placing nodes on the board via the API), not in writing a document like this.
|
|
4
|
+
|
|
5
|
+
## Conceptual walkthrough — mapping events to a read model (Order domain)
|
|
6
|
+
|
|
7
|
+
### 1. Map Event Data to UI Screens
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Screen: Order Status View
|
|
11
|
+
Displays data from events:
|
|
12
|
+
orderId ← OrderCreated event
|
|
13
|
+
customerId ← OrderCreated event
|
|
14
|
+
items ← OrderCreated event
|
|
15
|
+
total ← OrderCreated event
|
|
16
|
+
status ← OrderConfirmed event (or OrderCancelled)
|
|
17
|
+
confirmedAt ← OrderConfirmed event
|
|
18
|
+
paymentId ← PaymentAuthorized event
|
|
19
|
+
shipmentId ← OrderShipped event
|
|
20
|
+
shippedAt ← OrderShipped event
|
|
21
|
+
|
|
22
|
+
This screen is a projection of these events:
|
|
23
|
+
- OrderCreated
|
|
24
|
+
- OrderConfirmed
|
|
25
|
+
- PaymentAuthorized
|
|
26
|
+
- OrderShipped
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Define Read Models
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
ReadModel: OrderStatusView
|
|
33
|
+
Purpose: UI displays current order status
|
|
34
|
+
Events subscribed: OrderCreated, OrderConfirmed, PaymentAuthorized, OrderShipped, OrderCancelled
|
|
35
|
+
Data:
|
|
36
|
+
{
|
|
37
|
+
orderId: string (from OrderCreated)
|
|
38
|
+
customerId: string (from OrderCreated)
|
|
39
|
+
status: enum (from events: Draft → Confirmed → Authorized → Shipped → Delivered)
|
|
40
|
+
createdAt: Date (from OrderCreated)
|
|
41
|
+
confirmedAt: Date (from OrderConfirmed)
|
|
42
|
+
paymentId: string (from PaymentAuthorized)
|
|
43
|
+
shipmentId: string (from OrderShipped)
|
|
44
|
+
shippedAt: Date (from OrderShipped)
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 3. Document Event → Data Mapping
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
Event: OrderCreated
|
|
52
|
+
Provides to UI/Processors:
|
|
53
|
+
orderId
|
|
54
|
+
customerId
|
|
55
|
+
items[]
|
|
56
|
+
total
|
|
57
|
+
shippingAddress
|
|
58
|
+
createdAt
|
|
59
|
+
|
|
60
|
+
Event: OrderConfirmed
|
|
61
|
+
Provides to UI/Processors:
|
|
62
|
+
orderId (link to stream)
|
|
63
|
+
paymentMethod (user selected method)
|
|
64
|
+
confirmedAt (timestamp)
|
|
65
|
+
paymentId (payment system reference)
|
|
66
|
+
|
|
67
|
+
Event: PaymentAuthorized
|
|
68
|
+
Provides to UI/Processors:
|
|
69
|
+
orderId (link to stream)
|
|
70
|
+
paymentId
|
|
71
|
+
authCode
|
|
72
|
+
authorizedAt (timestamp)
|
|
73
|
+
amount (verified amount)
|
|
74
|
+
|
|
75
|
+
Event: OrderShipped
|
|
76
|
+
Provides to UI/Processors:
|
|
77
|
+
orderId (link to stream)
|
|
78
|
+
shipmentId
|
|
79
|
+
shippedAt (timestamp)
|
|
80
|
+
carrier (shipping company)
|
|
81
|
+
trackingNumber (for delivery tracking)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 4. Create Output Catalog
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
ReadModel Catalog: Order System
|
|
88
|
+
|
|
89
|
+
1. OrderStatusReadModel
|
|
90
|
+
Purpose: UI shows current order status
|
|
91
|
+
Events: OrderCreated, OrderConfirmed, PaymentAuthorized, OrderShipped, OrderCancelled
|
|
92
|
+
Data: orderId, status, createdAt, confirmedAt, paymentId, shipmentId
|
|
93
|
+
Consumed by:
|
|
94
|
+
- Order Status screen (UI)
|
|
95
|
+
- Customer Dashboard (UI)
|
|
96
|
+
- Order Processing Processor (decides if can ship)
|
|
97
|
+
|
|
98
|
+
2. OrderListReadModel
|
|
99
|
+
Purpose: UI lists all orders for a customer
|
|
100
|
+
Events: OrderCreated, OrderConfirmed, OrderCancelled
|
|
101
|
+
Data: orderId, customerId, total, status, createdAt
|
|
102
|
+
Consumed by:
|
|
103
|
+
- Customer Order History (UI)
|
|
104
|
+
- Order Search/Filter (UI)
|
|
105
|
+
|
|
106
|
+
3. PaymentStatusReadModel
|
|
107
|
+
Purpose: UI shows payment status
|
|
108
|
+
Events: OrderConfirmed, PaymentAuthorized, PaymentFailed
|
|
109
|
+
Data: orderId, paymentId, status, authCode, failureReason, timestamp
|
|
110
|
+
Consumed by:
|
|
111
|
+
- Payment Status screen (UI)
|
|
112
|
+
- Accounting Processor (reconciliation)
|
|
113
|
+
|
|
114
|
+
4. ShipmentTrackingReadModel
|
|
115
|
+
Purpose: UI shows tracking information
|
|
116
|
+
Events: OrderShipped, DeliveryConfirmed
|
|
117
|
+
Data: orderId, shipmentId, trackingNumber, carrier, shippedAt, estimatedDelivery
|
|
118
|
+
Consumed by:
|
|
119
|
+
- Order Tracking screen (UI)
|
|
120
|
+
- Customer notifications (Processor)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 5. Identify Missing Data
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
Question: What if UI needs "estimated delivery date"?
|
|
127
|
+
Event: OrderShipped has carrier + trackingNumber
|
|
128
|
+
Action needed: Add estimatedDelivery to OrderShipped event
|
|
129
|
+
(or compute from carrier info)
|
|
130
|
+
|
|
131
|
+
Question: What if UI needs to show "payment method" on status?
|
|
132
|
+
Event: OrderConfirmed has paymentMethod
|
|
133
|
+
Action needed: Include paymentMethod in relevant read models
|
|
134
|
+
|
|
135
|
+
Question: What if UI needs "item descriptions"?
|
|
136
|
+
Event: OrderCreated has items[]
|
|
137
|
+
But: items[] only has productId
|
|
138
|
+
Action needed: Enrich with product descriptions from catalog
|
|
139
|
+
(via join with product service)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 6. Processor Outputs
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
Processor: Inventory System
|
|
146
|
+
Consumes from read models:
|
|
147
|
+
- Orders in "PaymentAuthorized" status
|
|
148
|
+
- Items and quantities needed
|
|
149
|
+
Produces commands:
|
|
150
|
+
- ReserveInventory
|
|
151
|
+
|
|
152
|
+
Processor: Fulfillment System
|
|
153
|
+
Consumes from read models:
|
|
154
|
+
- Orders in "InventoryReserved" status
|
|
155
|
+
- Items and quantities
|
|
156
|
+
- Shipping address
|
|
157
|
+
Produces commands:
|
|
158
|
+
- CreateShipment
|
|
159
|
+
|
|
160
|
+
Processor: Notification System
|
|
161
|
+
Consumes from read models:
|
|
162
|
+
- OrderCreated (sends confirmation)
|
|
163
|
+
- OrderConfirmed (sends receipt)
|
|
164
|
+
- OrderShipped (sends tracking)
|
|
165
|
+
- DeliveryConfirmed (sends thank you)
|
|
166
|
+
Does not produce commands (info-only)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Legacy markdown-document format (superseded — kept for reference only)
|
|
170
|
+
|
|
171
|
+
Older versions of this skill wrote the read model catalog as a markdown document instead of placing nodes on the board. The actual mechanism today is the board API (Step 5a–5i in the main SKILL.md) — this template is kept only so the shape of the information (what a complete read-model catalog covers) stays documented somewhere.
|
|
172
|
+
|
|
173
|
+
```markdown
|
|
174
|
+
# Outputs: [Domain Name]
|
|
175
|
+
|
|
176
|
+
## Read Models Summary
|
|
177
|
+
|
|
178
|
+
| ReadModel | Purpose | Events | Consumed By |
|
|
179
|
+
|-----------|---------|--------|-------------|
|
|
180
|
+
| OrderStatus | Show order state | OrderCreated, OrderConfirmed | UI, Processor |
|
|
181
|
+
| OrderList | List orders | OrderCreated, OrderCancelled | UI |
|
|
182
|
+
| PaymentStatus | Payment info | OrderConfirmed, PaymentAuthorized | UI, Accounting |
|
|
183
|
+
| Shipment Tracking | Track delivery | OrderShipped, DeliveryConfirmed | UI, Notifications |
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Detailed Read Models
|
|
188
|
+
|
|
189
|
+
### ReadModel: OrderStatusView
|
|
190
|
+
|
|
191
|
+
**Purpose**: Order Status screen displays current order state
|
|
192
|
+
|
|
193
|
+
**Events subscribed**:
|
|
194
|
+
- OrderCreated
|
|
195
|
+
- OrderConfirmed
|
|
196
|
+
- PaymentAuthorized
|
|
197
|
+
- OrderShipped
|
|
198
|
+
- OrderCancelled
|
|
199
|
+
- DeliveryConfirmed
|
|
200
|
+
|
|
201
|
+
**Data**:
|
|
202
|
+
```
|
|
203
|
+
{
|
|
204
|
+
orderId: string
|
|
205
|
+
customerId: string
|
|
206
|
+
status: 'Draft' | 'Confirmed' | 'Authorized' | 'Shipped' | 'Delivered' | 'Cancelled'
|
|
207
|
+
items: Array<{productId, quantity, unitPrice}>
|
|
208
|
+
total: number
|
|
209
|
+
shippingAddress: Address
|
|
210
|
+
|
|
211
|
+
createdAt: Date
|
|
212
|
+
confirmedAt: Date
|
|
213
|
+
paymentId: string
|
|
214
|
+
paymentMethod: 'card' | 'transfer'
|
|
215
|
+
authorizedAt: Date
|
|
216
|
+
|
|
217
|
+
shipmentId: string
|
|
218
|
+
carrier: string
|
|
219
|
+
trackingNumber: string
|
|
220
|
+
shippedAt: Date
|
|
221
|
+
estimatedDelivery: Date
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Update Logic**:
|
|
226
|
+
- OrderCreated: Insert with status='Draft'
|
|
227
|
+
- OrderConfirmed: Update status='Confirmed'
|
|
228
|
+
- PaymentAuthorized: Update status='Authorized', set paymentId
|
|
229
|
+
- OrderShipped: Update status='Shipped', set shipmentId, carrier, trackingNumber
|
|
230
|
+
- DeliveryConfirmed: Update status='Delivered'
|
|
231
|
+
- OrderCancelled: Update status='Cancelled'
|
|
232
|
+
|
|
233
|
+
**Consumed By**:
|
|
234
|
+
- Order Status Screen (displays)
|
|
235
|
+
- Order Processing Processor (checks status)
|
|
236
|
+
- Notification System (sends updates)
|
|
237
|
+
|
|
238
|
+
--- [Repeat for each read model]
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Data Completeness Check
|
|
243
|
+
|
|
244
|
+
### Events → UI Needs
|
|
245
|
+
|
|
246
|
+
Verify all UI needs have event sources:
|
|
247
|
+
|
|
248
|
+
| UI Need | Event Source | Status |
|
|
249
|
+
|---------|-------------|--------|
|
|
250
|
+
| Order status | OrderConfirmed, OrderShipped | |
|
|
251
|
+
| Tracking number | OrderShipped | |
|
|
252
|
+
| Order items | OrderCreated | |
|
|
253
|
+
| Estimated delivery | OrderShipped | |
|
|
254
|
+
| Cancellation reason | OrderCancelled | |
|
|
255
|
+
|
|
256
|
+
### Missing Data
|
|
257
|
+
|
|
258
|
+
Identify UI needs without event sources:
|
|
259
|
+
- None identified
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Processor Consumption
|
|
264
|
+
|
|
265
|
+
### Processors and their reads:
|
|
266
|
+
|
|
267
|
+
| Processor | Reads From | Writes Commands |
|
|
268
|
+
|-----------|-----------|-----------------|
|
|
269
|
+
| Inventory | OrderStatusView (Authorized) | ReserveInventory |
|
|
270
|
+
| Fulfillment | OrderStatusView (InventoryReserved) | CreateShipment |
|
|
271
|
+
| Notification | OrderStatusView (all) | None (info-only) |
|
|
272
|
+
| Accounting | PaymentStatusView | None (reporting) |
|
|
273
|
+
```
|
package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: eventmodeling-optimizing-stream-design
|
|
3
|
-
description: "
|
|
3
|
+
description: "Validate and fix event stream boundaries — is each stream anchored on a single business identity, or is it secretly a collection/log that will grow unbounded? Use when concerned about stream length, reviewing stream design before implementation, or when a stream feels like it's absorbing unrelated events. Do not use for: designing the initial event model structure (use eventmodeling-designing-event-models) or general architectural validation (use eventmodeling-validating-event-models)."
|
|
4
4
|
allowed-tools:
|
|
5
5
|
- AskUserQuestion
|
|
6
6
|
- Write
|
|
@@ -10,45 +10,16 @@ allowed-tools:
|
|
|
10
10
|
|
|
11
11
|
## Interview Phase (Optional)
|
|
12
12
|
|
|
13
|
-
**When to Interview**: Skip if the user has
|
|
13
|
+
**When to Interview**: Skip if the user has already named the entity each stream is anchored on and confirmed every event in it belongs to that entity's own lifecycle. Interview when a stream's boundary feels unclear or it seems to be absorbing events from more than one concern.
|
|
14
14
|
|
|
15
|
-
**Interview Strategy**:
|
|
15
|
+
**Interview Strategy**: This is a boundary question, not a performance question — establish what single business identity a stream is supposed to represent before judging whether it's well-designed.
|
|
16
16
|
|
|
17
|
-
### Critical
|
|
17
|
+
### Critical Question
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
2. **Performance SLAs** (Impact: Determines acceptable latency and snapshotting decisions)
|
|
25
|
-
- Question: "Performance requirements? (A) <100ms read latency, (B) <1s acceptable, (C) Eventual consistency OK?"
|
|
26
|
-
- Why it matters: Strict SLAs might need snapshotting; loose SLAs often don't
|
|
27
|
-
- Follow-up triggers: If (A) → ask "Which commands specifically need sub-100ms replay? Are those commands reading from a read model or replaying the stream directly?"
|
|
28
|
-
|
|
29
|
-
### Interview Flow
|
|
30
|
-
|
|
31
|
-
**Conditional Entry**:
|
|
32
|
-
```
|
|
33
|
-
If user has provided:
|
|
34
|
-
- Event frequency estimate (per entity per day or per transaction)
|
|
35
|
-
- AND stream lifetime estimate (months or years)
|
|
36
|
-
- AND read latency SLA (or confirmation that eventual consistency is acceptable)
|
|
37
|
-
|
|
38
|
-
Then: Skip interview, proceed directly to stream analysis
|
|
39
|
-
|
|
40
|
-
Else: Conduct interview
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
**Phase 1: Growth Estimation** (Question 1)
|
|
44
|
-
- Establish per-entity event volume
|
|
45
|
-
- Project lifetime stream length using the estimation formula
|
|
46
|
-
- Determine whether redesign or snapshotting analysis is warranted
|
|
47
|
-
|
|
48
|
-
**Phase 2: SLA Requirements** (Question 2)
|
|
49
|
-
- Identify read latency requirements per command
|
|
50
|
-
- Determine whether read models or direct stream replay satisfies the SLA
|
|
51
|
-
- Establish whether snapshotting is justified by SLA alone
|
|
19
|
+
**Stream Identity** (Impact: Determines whether the stream is a real aggregate or a disguised collection/log)
|
|
20
|
+
- Question: "What one business entity does this stream represent the history of? Does every event in it belong to that entity's own lifecycle, or does it also pick up events from a broader category?"
|
|
21
|
+
- Why it matters: A stream with no single identity, or one that mixes in events belonging to other entities, is the root cause behind almost every stream-design complaint — not stream length itself.
|
|
22
|
+
- Follow-up triggers: If the answer names a category ("all orders", "system events") rather than one entity → that's Pattern 3/4 in `references/patterns.md` (Collection/Event Log anti-patterns) — walk through the fix directly.
|
|
52
23
|
|
|
53
24
|
### Capturing Interview Findings
|
|
54
25
|
|
|
@@ -61,171 +32,93 @@ Use Write tool to add/update this section:
|
|
|
61
32
|
```markdown
|
|
62
33
|
## Optimizing Stream Design (eventmodeling-optimizing-stream-design)
|
|
63
34
|
|
|
64
|
-
###
|
|
65
|
-
[
|
|
66
|
-
|
|
67
|
-
### Performance SLAs
|
|
68
|
-
[From Q2: Latency requirements per command or view]
|
|
35
|
+
### Stream Identity Review
|
|
36
|
+
[Which streams were reviewed? What entity does each represent? Any that turned out to be a disguised collection/log?]
|
|
69
37
|
|
|
70
|
-
###
|
|
38
|
+
### Boundary Decisions
|
|
71
39
|
- Streams requiring redesign: [list or "None"]
|
|
72
|
-
- Streams
|
|
73
|
-
- Streams within acceptable bounds: [list]
|
|
40
|
+
- Streams confirmed well-bounded: [list]
|
|
74
41
|
```
|
|
75
42
|
|
|
76
43
|
Update Interview Trail:
|
|
77
44
|
```markdown
|
|
78
|
-
| Optimization | eventmodeling-optimizing-stream-design | Done | Stream
|
|
45
|
+
| Optimization | eventmodeling-optimizing-stream-design | Done | Stream identity review, boundary decisions |
|
|
79
46
|
```
|
|
80
47
|
|
|
81
48
|
---
|
|
82
49
|
|
|
83
50
|
## Stream Design Optimization
|
|
84
51
|
|
|
85
|
-
**Purpose**:
|
|
52
|
+
**Purpose**: Validate stream boundaries — confirm each stream is anchored on a single business entity's own lifecycle, and catch the two common anti-patterns (an unbounded collection, or an unrelated event log) before they get built.
|
|
86
53
|
|
|
87
|
-
**Applies To**: Any domain
|
|
54
|
+
**Applies To**: Any domain — e-commerce, banking, SaaS, marketplace, healthcare, etc.
|
|
88
55
|
|
|
89
56
|
**When to Use**:
|
|
90
57
|
- After defining event streams in domain analysis
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
-
|
|
94
|
-
- When redesigning streams for scalability
|
|
58
|
+
- Before implementing, to validate stream design
|
|
59
|
+
- When a stream feels like it's growing for reasons unrelated to one entity's own story
|
|
60
|
+
- When redesigning a stream whose boundary turned out to be wrong
|
|
95
61
|
|
|
96
62
|
**What It Does**:
|
|
97
|
-
1.
|
|
98
|
-
2.
|
|
99
|
-
3.
|
|
100
|
-
4.
|
|
101
|
-
5. Balances performance optimization against complexity
|
|
102
|
-
6. Provides snapshotting strategy without over-engineering
|
|
63
|
+
1. Checks that each stream has a single, natural business identity
|
|
64
|
+
2. Identifies streams that are actually collections or logs in disguise
|
|
65
|
+
3. Recommends the correct stream boundary when one is wrong
|
|
66
|
+
4. Distinguishes "this stream is long because the entity has a long history" (fine) from "this stream is long because it's absorbing events that don't belong to it" (a boundary bug)
|
|
103
67
|
|
|
104
68
|
---
|
|
105
69
|
|
|
106
|
-
## Core Principle:
|
|
70
|
+
## Core Principle: Get the Identity Right
|
|
107
71
|
|
|
108
72
|
**Golden Rule**:
|
|
109
|
-
> If
|
|
73
|
+
> If a stream feels like it's growing for the wrong reasons, first ask: "Does this stream actually have one business identity, or is it a collection/log wearing an aggregate's name?"
|
|
110
74
|
|
|
111
|
-
|
|
75
|
+
A long stream is not, by itself, evidence of a design problem — an account open for thirty years is correctly one long stream. What *is* always a design problem is a stream whose events don't all belong to the same entity's own lifecycle.
|
|
112
76
|
|
|
113
77
|
---
|
|
114
78
|
|
|
115
|
-
## Stream
|
|
79
|
+
## Stream Boundary Review
|
|
116
80
|
|
|
117
|
-
|
|
81
|
+
For each stream in scope, work through:
|
|
118
82
|
|
|
119
|
-
|
|
120
|
-
```
|
|
121
|
-
Estimated Stream Length (total events/instance) =
|
|
122
|
-
Events Per Aggregate Instance Per Year (events/instance/year)
|
|
123
|
-
× Lifetime of Instance (years)
|
|
124
|
-
× Annual Growth Factor (dimensionless year-over-year multiplier ≥ 1.0)
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
**Quick Examples**:
|
|
83
|
+
### 1. Name the identity
|
|
128
84
|
|
|
129
|
-
|
|
85
|
+
What single business entity does this stream represent the history of? Write it down explicitly (e.g. `orderId`, not "orders").
|
|
130
86
|
|
|
131
|
-
|
|
87
|
+
### 2. Check every event against that identity
|
|
132
88
|
|
|
133
|
-
|
|
89
|
+
Does each event in the stream describe something that happened to *this* entity — not to a category of entities, not to the system in general? If any event fails this test, the boundary is wrong (see `references/patterns.md`'s Red Flags).
|
|
134
90
|
|
|
135
|
-
|
|
91
|
+
### 3. Classify the result
|
|
136
92
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
|
140
|
-
|
|
141
|
-
|
|
|
142
|
-
|
|
|
143
|
-
| 100-300 events | ACCEPTABLE | Review boundary | CONSIDER if replayed |
|
|
144
|
-
| 300-1000 events | LONG | REDESIGN first | Only last resort |
|
|
145
|
-
| 1000+ events | CRITICAL | REDESIGN required | Won't help |
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
## Quick Decision Matrix
|
|
150
|
-
|
|
151
|
-
| Stream Length | Read Pattern | Frequency | Action |
|
|
152
|
-
|---|---|---|---|
|
|
153
|
-
| < 50 | Any | Any | IDEAL - Keep as-is |
|
|
154
|
-
| 50-100 | Any | Any | Good - Monitor |
|
|
155
|
-
| 100-300 | From Model | Any | OK - No snapshot |
|
|
156
|
-
| 100-300 | Stream Replay | Low | OK - Monitor |
|
|
157
|
-
| 100-300 | Stream Replay | High | REDESIGN |
|
|
158
|
-
| 300-1000 | From Model | Any | OK - No snapshot |
|
|
159
|
-
| 300-1000 | Stream Replay | Any | REDESIGN |
|
|
160
|
-
| 1000+ | Any | Any | CRITICAL - REDESIGN |
|
|
93
|
+
| Result | Meaning | Action |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| Every event belongs to one clear entity | Boundary is correct | Keep as-is, regardless of how long the history gets |
|
|
96
|
+
| Events span a category or "all X" | Pattern 3 (Collection) anti-pattern | Re-scope to the real per-entity identity; the category becomes a read model/query, not a stream |
|
|
97
|
+
| Events span unrelated concerns (users, orders, payments mixed) | Pattern 4 (Event Log) anti-pattern | Split into one stream per concern |
|
|
98
|
+
| Stream conflates an entity's active life with its historical record | Missing the Pattern 5 split | Separate active vs. archived/historical streams |
|
|
161
99
|
|
|
162
100
|
---
|
|
163
101
|
|
|
164
102
|
## Reference Files
|
|
165
103
|
|
|
166
104
|
**Aggregate Boundary Design**: See [patterns.md](references/patterns.md) for:
|
|
167
|
-
- 5 aggregate patterns (single entity, composite,
|
|
168
|
-
-
|
|
169
|
-
- Red flags that indicate
|
|
170
|
-
- Tips for
|
|
171
|
-
|
|
172
|
-
**Snapshotting Strategy**: See [snapshotting.md](references/snapshotting.md) for:
|
|
173
|
-
- Criteria for when snapshotting is truly needed
|
|
174
|
-
- Context-based decision thresholds
|
|
175
|
-
- Snapshot frequency, versioning, and cleanup strategies
|
|
176
|
-
- Cost-benefit analysis
|
|
105
|
+
- 5 aggregate boundary patterns (single entity, composite, collection anti-pattern, event-log anti-pattern, historical)
|
|
106
|
+
- The stream boundary decision tree
|
|
107
|
+
- Red flags that indicate the boundary — not the volume — is wrong
|
|
108
|
+
- Tips for finding the right boundary
|
|
177
109
|
|
|
178
110
|
**Domain-Specific Guidance**: See [domain-patterns.md](references/domain-patterns.md) for:
|
|
179
111
|
- E-commerce patterns (orders, carts, accounts)
|
|
180
112
|
- Banking patterns (accounts, transactions, loans)
|
|
181
113
|
- SaaS patterns (subscriptions, workspaces, data collections)
|
|
182
|
-
- Implementation checklist
|
|
183
|
-
|
|
184
|
-
---
|
|
185
|
-
|
|
186
|
-
## Key Insights
|
|
187
|
-
|
|
188
|
-
### Why Snapshotting Usually Isn't the Answer
|
|
189
|
-
|
|
190
|
-
```
|
|
191
|
-
Before implementing snapshotting, ask:
|
|
192
|
-
|
|
193
|
-
1. Can I split this aggregate into smaller ones?
|
|
194
|
-
→ YES: Do that instead. Simpler, better design.
|
|
195
|
-
|
|
196
|
-
2. Can I reduce event granularity?
|
|
197
|
-
→ YES: Batch events or create coarser state changes.
|
|
198
|
-
|
|
199
|
-
3. Am I using a read model for this aggregate?
|
|
200
|
-
→ NO: Create a read model (cached projection).
|
|
201
|
-
Stream size becomes irrelevant.
|
|
202
|
-
|
|
203
|
-
4. Have I measured actual replay latency?
|
|
204
|
-
→ NO: Measure first. Most systems exceed expectations.
|
|
205
|
-
|
|
206
|
-
If ANY of these is YES, do that before snapshotting.
|
|
207
|
-
Only after exhausting design improvements, consider snapshots.
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### The Snapshotting Trade-off
|
|
211
|
-
|
|
212
|
-
```
|
|
213
|
-
Snapshotting Complexity ≈ 2-3x Complexity of Better Design
|
|
214
|
-
|
|
215
|
-
Before snapshot: 50 lines of code, simple, testable
|
|
216
|
-
With snapshots: 150+ lines, versioning, recovery logic, testing matrix
|
|
217
|
-
|
|
218
|
-
Better to redesign and keep streams < 300 events.
|
|
219
|
-
```
|
|
220
114
|
|
|
221
115
|
---
|
|
222
116
|
|
|
223
117
|
## Quality Checklist
|
|
224
118
|
|
|
225
119
|
- [ ] Each stream is identified by a business entity identity (e.g., `orderId`), not a category or type
|
|
226
|
-
- [ ]
|
|
227
|
-
- [ ]
|
|
228
|
-
- [ ] If snapshotting is proposed, all simpler alternatives (split stream, shorter lifetime) have been eliminated first
|
|
120
|
+
- [ ] Every event in a stream belongs to that one entity's own lifecycle — none of them describe a different entity or an unrelated system concern
|
|
121
|
+
- [ ] No stream is secretly a collection ("all X") or a log ("everything that happened") wearing an aggregate's name
|
|
229
122
|
- [ ] Command handler state is reconstructed from stream events — no persistent state stored outside the stream
|
|
230
123
|
- [ ] Each stream can be independently versioned and replayed without affecting other streams
|
|
231
|
-
|
|
124
|
+
- [ ] A stream that conflates an entity's active life with its historical record has been split (active vs. archived)
|