@eventmodelers/cli 0.0.1

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.
Files changed (220) hide show
  1. package/README.md +175 -0
  2. package/cli.js +676 -0
  3. package/package.json +35 -0
  4. package/shared/build-kit/code-export.mjs +560 -0
  5. package/shared/build-kit/lib/ollama-agent.js +147 -0
  6. package/shared/build-kit/package.json +11 -0
  7. package/shared/build-kit/ralph-ollama.js +39 -0
  8. package/shared/build-kit/realtime-agent.js +18 -0
  9. package/stacks/axon/templates/.claude/skills/build-automation/SKILL.md +407 -0
  10. package/stacks/axon/templates/.claude/skills/build-automation/references/feature-flag-patterns.md +114 -0
  11. package/stacks/axon/templates/.claude/skills/build-automation-workflow/SKILL.md +496 -0
  12. package/stacks/axon/templates/.claude/skills/build-automation-workflow/references/axon-workflow-api.md +279 -0
  13. package/stacks/axon/templates/.claude/skills/build-automation-workflow/references/feature-flag-patterns.md +114 -0
  14. package/stacks/axon/templates/.claude/skills/build-state-change/SKILL.md +396 -0
  15. package/stacks/axon/templates/.claude/skills/build-state-change/references/axon-test-fixture-patterns.md +162 -0
  16. package/stacks/axon/templates/.claude/skills/build-state-change/references/feature-flag-patterns.md +56 -0
  17. package/stacks/axon/templates/.claude/skills/build-state-change/references/rest-api-patterns.md +115 -0
  18. package/stacks/axon/templates/.claude/skills/build-state-view/SKILL.md +282 -0
  19. package/stacks/axon/templates/.claude/skills/connect/SKILL.md +178 -0
  20. package/stacks/axon/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +611 -0
  21. package/stacks/axon/templates/.claude/skills/load-slice/SKILL.md +141 -0
  22. package/stacks/axon/templates/.claude/skills/update-slice-status/SKILL.md +105 -0
  23. package/stacks/axon/templates/build-kit/lib/AGENT.md +47 -0
  24. package/stacks/axon/templates/build-kit/lib/agent.sh +20 -0
  25. package/stacks/axon/templates/build-kit/lib/backend-prompt.md +158 -0
  26. package/stacks/axon/templates/build-kit/lib/prompt.md +126 -0
  27. package/stacks/axon/templates/build-kit/lib/ralph.js +369 -0
  28. package/stacks/axon/templates/build-kit/ralph-claude.js +44 -0
  29. package/stacks/axon/templates/build-kit/ralph.sh +98 -0
  30. package/stacks/axon/templates/root/.env.example +5 -0
  31. package/stacks/axon/templates/root/CLAUDE.md +60 -0
  32. package/stacks/axon/templates/root/README.md +44 -0
  33. package/stacks/axon/templates/root/docker-compose.yml +64 -0
  34. package/stacks/axon/templates/root/mvnw +259 -0
  35. package/stacks/axon/templates/root/mvnw.cmd +149 -0
  36. package/stacks/axon/templates/root/pom.xml +125 -0
  37. package/stacks/axon/templates/root/src/main/java/io/axoniq/quickstart/QuickstartApplication.java +128 -0
  38. package/stacks/axon/templates/root/src/main/java/io/axoniq/quickstart/config/WebConfig.java +155 -0
  39. package/stacks/axon/templates/root/src/main/resources/application.properties +2 -0
  40. package/stacks/axon/templates/root/src/main/resources/static/bg-body.png +0 -0
  41. package/stacks/axon/templates/root/src/main/resources/static/bg-header.png +0 -0
  42. package/stacks/axon/templates/root/src/main/resources/static/index.html +596 -0
  43. package/stacks/cratis-csharp/templates/.claude/skills/_shared/cratis-conventions.md +251 -0
  44. package/stacks/cratis-csharp/templates/.claude/skills/build-automation/SKILL.md +99 -0
  45. package/stacks/cratis-csharp/templates/.claude/skills/build-automation/references/patterns.md +115 -0
  46. package/stacks/cratis-csharp/templates/.claude/skills/build-state-change/SKILL.md +163 -0
  47. package/stacks/cratis-csharp/templates/.claude/skills/build-state-change/references/patterns.md +234 -0
  48. package/stacks/cratis-csharp/templates/.claude/skills/build-state-view/SKILL.md +120 -0
  49. package/stacks/cratis-csharp/templates/.claude/skills/build-state-view/references/patterns.md +166 -0
  50. package/stacks/cratis-csharp/templates/.claude/skills/connect/SKILL.md +169 -0
  51. package/stacks/cratis-csharp/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +609 -0
  52. package/stacks/cratis-csharp/templates/.claude/skills/load-slice/SKILL.md +141 -0
  53. package/stacks/cratis-csharp/templates/.claude/skills/update-slice-status/SKILL.md +105 -0
  54. package/stacks/cratis-csharp/templates/build-kit/lib/AGENT.md +58 -0
  55. package/stacks/cratis-csharp/templates/build-kit/lib/agent.sh +20 -0
  56. package/stacks/cratis-csharp/templates/build-kit/lib/backend-prompt.md +129 -0
  57. package/stacks/cratis-csharp/templates/build-kit/lib/prompt.md +124 -0
  58. package/stacks/cratis-csharp/templates/build-kit/lib/ralph.js +302 -0
  59. package/stacks/cratis-csharp/templates/build-kit/ralph-claude.js +37 -0
  60. package/stacks/cratis-csharp/templates/build-kit/ralph.sh +98 -0
  61. package/stacks/cratis-csharp/templates/root/.frontend/index.css +29 -0
  62. package/stacks/cratis-csharp/templates/root/.frontend/index.html +17 -0
  63. package/stacks/cratis-csharp/templates/root/.frontend/main.tsx +18 -0
  64. package/stacks/cratis-csharp/templates/root/.frontend/tsconfig.json +42 -0
  65. package/stacks/cratis-csharp/templates/root/.frontend/tsconfig.node.json +11 -0
  66. package/stacks/cratis-csharp/templates/root/.frontend/vite.config.ts +56 -0
  67. package/stacks/cratis-csharp/templates/root/App.tsx +23 -0
  68. package/stacks/cratis-csharp/templates/root/CLAUDE.md +62 -0
  69. package/stacks/cratis-csharp/templates/root/CratisApp.csproj +25 -0
  70. package/stacks/cratis-csharp/templates/root/CratisApp.sln +18 -0
  71. package/stacks/cratis-csharp/templates/root/GlobalUsings.cs +3 -0
  72. package/stacks/cratis-csharp/templates/root/Home.tsx +102 -0
  73. package/stacks/cratis-csharp/templates/root/Program.cs +26 -0
  74. package/stacks/cratis-csharp/templates/root/README.md +192 -0
  75. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/AllListings.ts +47 -0
  76. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/Listing.cs +11 -0
  77. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/Listing.ts +12 -0
  78. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/ListingDataTable.tsx +17 -0
  79. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/index.ts +1 -0
  80. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/Register.ts +51 -0
  81. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/RegisterDialog.tsx +18 -0
  82. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/Registration.cs +27 -0
  83. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/index.ts +1 -0
  84. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/SomeFeature.tsx +22 -0
  85. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/SomeName.cs +3 -0
  86. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/index.ts +1 -0
  87. package/stacks/cratis-csharp/templates/root/appsettings.Development.json +9 -0
  88. package/stacks/cratis-csharp/templates/root/appsettings.json +26 -0
  89. package/stacks/cratis-csharp/templates/root/docker-compose.yml +23 -0
  90. package/stacks/cratis-csharp/templates/root/package.json +33 -0
  91. package/stacks/cratis-csharp/templates/root/tsconfig.json +3 -0
  92. package/stacks/modeling-kit/templates/.claude/settings.local.json +13 -0
  93. package/stacks/modeling-kit/templates/.claude/skills/analyze-existing-model/SKILL.md +215 -0
  94. package/stacks/modeling-kit/templates/.claude/skills/attributes/SKILL.md +176 -0
  95. package/stacks/modeling-kit/templates/.claude/skills/connect/SKILL.md +182 -0
  96. package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/SKILL.md +383 -0
  97. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-applying-conways-law/SKILL.md +465 -0
  98. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/SKILL.md +587 -0
  99. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/references/facilitating-event-modeling-workshops.md +626 -0
  100. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/SKILL.md +542 -0
  101. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/SKILL.md +497 -0
  102. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/SKILL.md +783 -0
  103. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/SKILL.md +604 -0
  104. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md +699 -0
  105. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-integrating-legacy-systems/SKILL.md +674 -0
  106. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/SKILL.md +231 -0
  107. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/domain-patterns.md +150 -0
  108. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/patterns.md +329 -0
  109. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/snapshotting.md +204 -0
  110. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/SKILL.md +352 -0
  111. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/references/project-planning-with-event-modeling.md +341 -0
  112. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-plotting-events/SKILL.md +153 -0
  113. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/SKILL.md +136 -0
  114. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/examples.md +78 -0
  115. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/patterns.md +85 -0
  116. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md +655 -0
  117. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-translating-external-events/SKILL.md +479 -0
  118. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/SKILL.md +234 -0
  119. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models-checklist/SKILL.md +353 -0
  120. package/stacks/modeling-kit/templates/.claude/skills/examples/SKILL.md +200 -0
  121. package/stacks/modeling-kit/templates/.claude/skills/handle-comment/SKILL.md +94 -0
  122. package/stacks/modeling-kit/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +441 -0
  123. package/stacks/modeling-kit/templates/.claude/skills/place-element/SKILL.md +290 -0
  124. package/stacks/modeling-kit/templates/.claude/skills/storyboard/SKILL.md +212 -0
  125. package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/SKILL.md +123 -0
  126. package/stacks/modeling-kit/templates/.claude/skills/timeline/SKILL.md +353 -0
  127. package/stacks/modeling-kit/templates/.claude/skills/update-slice-status/SKILL.md +110 -0
  128. package/stacks/modeling-kit/templates/.claude/skills/wdyt/SKILL.md +134 -0
  129. package/stacks/modeling-kit/templates/kit/lib/agent.sh +20 -0
  130. package/stacks/modeling-kit/templates/kit/lib/ollama-agent.js +147 -0
  131. package/stacks/modeling-kit/templates/kit/lib/ralph.js +286 -0
  132. package/stacks/modeling-kit/templates/kit/package.json +12 -0
  133. package/stacks/modeling-kit/templates/kit/ralph-claude.js +50 -0
  134. package/stacks/modeling-kit/templates/kit/ralph-ollama.js +38 -0
  135. package/stacks/modeling-kit/templates/kit/ralph.sh +61 -0
  136. package/stacks/modeling-kit/templates/kit/realtime-agent.js +18 -0
  137. package/stacks/modeling-kit/templates/root/CLAUDE.md +56 -0
  138. package/stacks/node/templates/.claude/skills/build-automation/SKILL.md +266 -0
  139. package/stacks/node/templates/.claude/skills/build-state-change/SKILL.md +344 -0
  140. package/stacks/node/templates/.claude/skills/build-state-view/SKILL.md +412 -0
  141. package/stacks/node/templates/.claude/skills/connect/SKILL.md +178 -0
  142. package/stacks/node/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +628 -0
  143. package/stacks/node/templates/.claude/skills/load-slice/SKILL.md +143 -0
  144. package/stacks/node/templates/.claude/skills/update-slice-status/SKILL.md +110 -0
  145. package/stacks/node/templates/build-kit/README.md +86 -0
  146. package/stacks/node/templates/build-kit/lib/AGENT.md +47 -0
  147. package/stacks/node/templates/build-kit/lib/agent.sh +20 -0
  148. package/stacks/node/templates/build-kit/lib/backend-prompt.md +152 -0
  149. package/stacks/node/templates/build-kit/lib/prompt.md +122 -0
  150. package/stacks/node/templates/build-kit/lib/ralph.js +369 -0
  151. package/stacks/node/templates/build-kit/ralph-claude.js +44 -0
  152. package/stacks/node/templates/build-kit/ralph.sh +98 -0
  153. package/stacks/node/templates/root/.env.example +15 -0
  154. package/stacks/node/templates/root/CLAUDE.md +60 -0
  155. package/stacks/node/templates/root/docker-compose.yml +15 -0
  156. package/stacks/node/templates/root/flyway.conf +17 -0
  157. package/stacks/node/templates/root/migrations/V1__schema.sql.example +12 -0
  158. package/stacks/node/templates/root/package.json +50 -0
  159. package/stacks/node/templates/root/server.ts +130 -0
  160. package/stacks/node/templates/root/setup-env.sh +53 -0
  161. package/stacks/node/templates/root/src/common/assertions.ts +6 -0
  162. package/stacks/node/templates/root/src/common/db.ts +32 -0
  163. package/stacks/node/templates/root/src/common/loadPostgresEventstore.ts +23 -0
  164. package/stacks/node/templates/root/src/common/parseEndpoint.ts +51 -0
  165. package/stacks/node/templates/root/src/common/processorDlq.ts +28 -0
  166. package/stacks/node/templates/root/src/common/realtimeBroadcast.ts +12 -0
  167. package/stacks/node/templates/root/src/common/replay.ts +16 -0
  168. package/stacks/node/templates/root/src/common/routes.ts +19 -0
  169. package/stacks/node/templates/root/src/common/testHelpers.ts +44 -0
  170. package/stacks/node/templates/root/src/swagger.ts +34 -0
  171. package/stacks/node/templates/root/src/util/assertions.ts +6 -0
  172. package/stacks/node/templates/root/src/util/hash.ts +9 -0
  173. package/stacks/node/templates/root/src/util/sanitize.ts +23 -0
  174. package/stacks/node/templates/root/tsconfig.json +32 -0
  175. package/stacks/node/templates/root/vercel.json +8 -0
  176. package/stacks/supabase/templates/.claude/skills/build-automation/SKILL.md +266 -0
  177. package/stacks/supabase/templates/.claude/skills/build-state-change/SKILL.md +344 -0
  178. package/stacks/supabase/templates/.claude/skills/build-state-view/SKILL.md +390 -0
  179. package/stacks/supabase/templates/.claude/skills/build-webhook/SKILL.md +303 -0
  180. package/stacks/supabase/templates/.claude/skills/connect/SKILL.md +178 -0
  181. package/stacks/supabase/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +628 -0
  182. package/stacks/supabase/templates/.claude/skills/load-slice/SKILL.md +143 -0
  183. package/stacks/supabase/templates/.claude/skills/update-slice-status/SKILL.md +110 -0
  184. package/stacks/supabase/templates/build-kit/README.md +86 -0
  185. package/stacks/supabase/templates/build-kit/lib/AGENT.md +47 -0
  186. package/stacks/supabase/templates/build-kit/lib/agent.sh +20 -0
  187. package/stacks/supabase/templates/build-kit/lib/backend-prompt.md +152 -0
  188. package/stacks/supabase/templates/build-kit/lib/prompt.md +123 -0
  189. package/stacks/supabase/templates/build-kit/lib/ralph.js +369 -0
  190. package/stacks/supabase/templates/build-kit/ralph-claude.js +44 -0
  191. package/stacks/supabase/templates/build-kit/ralph.sh +98 -0
  192. package/stacks/supabase/templates/root/.env.example +22 -0
  193. package/stacks/supabase/templates/root/CLAUDE.md +61 -0
  194. package/stacks/supabase/templates/root/flyway.conf +17 -0
  195. package/stacks/supabase/templates/root/package.json +52 -0
  196. package/stacks/supabase/templates/root/server.ts +177 -0
  197. package/stacks/supabase/templates/root/setup-env.sh +53 -0
  198. package/stacks/supabase/templates/root/src/common/assertions.ts +6 -0
  199. package/stacks/supabase/templates/root/src/common/db.ts +32 -0
  200. package/stacks/supabase/templates/root/src/common/loadPostgresEventstore.ts +23 -0
  201. package/stacks/supabase/templates/root/src/common/parseEndpoint.ts +51 -0
  202. package/stacks/supabase/templates/root/src/common/processorDlq.ts +28 -0
  203. package/stacks/supabase/templates/root/src/common/realtimeBroadcast.ts +19 -0
  204. package/stacks/supabase/templates/root/src/common/replay.ts +16 -0
  205. package/stacks/supabase/templates/root/src/common/routes.ts +23 -0
  206. package/stacks/supabase/templates/root/src/common/testHelpers.ts +54 -0
  207. package/stacks/supabase/templates/root/src/supabase/README.md +141 -0
  208. package/stacks/supabase/templates/root/src/supabase/api.ts +56 -0
  209. package/stacks/supabase/templates/root/src/supabase/requireOrgaAdmin.ts +32 -0
  210. package/stacks/supabase/templates/root/src/supabase/requireSysUser.ts +40 -0
  211. package/stacks/supabase/templates/root/src/supabase/requireUser.ts +72 -0
  212. package/stacks/supabase/templates/root/src/swagger.ts +34 -0
  213. package/stacks/supabase/templates/root/src/util/assertions.ts +6 -0
  214. package/stacks/supabase/templates/root/src/util/hash.ts +9 -0
  215. package/stacks/supabase/templates/root/src/util/sanitize.ts +23 -0
  216. package/stacks/supabase/templates/root/supabase/config.toml +295 -0
  217. package/stacks/supabase/templates/root/supabase/migrations/V1__schema.sql.example +12 -0
  218. package/stacks/supabase/templates/root/supabase/seed.sql +1 -0
  219. package/stacks/supabase/templates/root/tsconfig.json +32 -0
  220. package/stacks/supabase/templates/root/vercel.json +8 -0
@@ -0,0 +1,699 @@
1
+ ---
2
+ name: eventmodeling-identifying-outputs
3
+ description: "Step 5 of Event Modeling - Identify Outputs/Read Models from events. Show what data flows back to UI and Processors. Use after defining inputs. Do not use for: identifying commands or inputs (use eventmodeling-identifying-inputs) or verifying field completeness (use eventmodeling-checking-completeness)."
4
+ allowed-tools:
5
+ - AskUserQuestion
6
+ - Write
7
+ - Bash
8
+ ---
9
+
10
+ # Identifying Outputs
11
+
12
+ > **Before doing anything else**, invoke the `connect` skill to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`. Then invoke the `learn-eventmodelers-api` skill to load the full API reference. Do not proceed until both skills have been loaded.
13
+
14
+ ## Interview Phase (Optional)
15
+
16
+ **When to Interview**: Skip if the user has clearly identified: read model queries needed by UI, processor needs, and refresh patterns. Interview when unclear which data queries are critical or how frequently they're accessed.
17
+
18
+ **Interview Strategy**: Establish query patterns and identify any calculations before designing read models. The most common architecture error at this step is modeling recalculated state as an event — identifying calculated fields upfront prevents that anti-pattern.
19
+
20
+ ### Critical Questions
21
+
22
+ 1. **Query Patterns** (Impact: Determines which read models are needed and their update frequency)
23
+ - Question: "What data do users/processors need to query? (A) Real-time (sub-second), (B) Near-real-time (seconds), (C) Periodic (minutes/hours)?"
24
+ - Why it matters: Query frequency drives read model design and caching strategy
25
+ - Follow-up triggers: If (A) → ask which specific screens or processors require sub-second reads; these need dedicated, highly optimized read models
26
+
27
+ 2. **Event vs Read Model Clarification** (Impact: Ensures we don't model calculations as events)
28
+ - Question: "Are there calculated/aggregated fields? (e.g., average rating, total sales, inventory count) - These are read models, not events."
29
+ - Why it matters: Common mistake to model calculations as events; identifying them upfront prevents architecture errors
30
+ - Follow-up triggers: For each calculated field mentioned → confirm "This recalculates as source data changes, so it belongs in a read model projection — does that match your expectation?"
31
+
32
+ ### Interview Flow
33
+
34
+ **Conditional Entry**:
35
+ ```
36
+ If user has provided:
37
+ - UI screens with data needs mapped to event sources
38
+ - AND processor query needs documented
39
+ - AND calculated/aggregated fields identified as read models (not events)
40
+
41
+ Then: Skip interview, proceed directly to read model design
42
+
43
+ Else: Conduct interview
44
+ ```
45
+
46
+ **Phase 1: Query Pattern Mapping** (Question 1)
47
+ - Identify which UI screens and processors need which data
48
+ - Typically every screen needs some kind of data, same for automations.
49
+ - Establish freshness requirements per consumer
50
+ - Determine if any queries require real-time consistency
51
+
52
+ **Phase 2: Calculation Detection** (Question 2)
53
+ - Surface any aggregated or computed values
54
+ - Confirm they are projections, not events
55
+ - Prevent the calculation-as-event anti-pattern before design begins
56
+
57
+ ### Capturing Interview Findings
58
+
59
+ Append findings to the project's event modeling file:
60
+
61
+ **File**: `.trogonai/interviews/[project-name]/EVENTMODELING.md`
62
+
63
+ Use Write tool to add/update this section:
64
+
65
+ ```markdown
66
+ ## 5. Identifying Outputs (eventmodeling-identifying-outputs)
67
+
68
+ ### Query Patterns
69
+ [From Q1: Which consumers need what freshness? Real-time vs. periodic?]
70
+
71
+ ### Calculated Fields Identified
72
+ [From Q2: Which fields are aggregated/calculated? Confirmed as read models?]
73
+
74
+ ### Read Model Summary
75
+ - Real-time read models: [list]
76
+ - Near-real-time read models: [list]
77
+ - Calculation-as-event anti-patterns caught: [list or "None"]
78
+ ```
79
+
80
+ Update Interview Trail:
81
+ ```markdown
82
+ | 5 | eventmodeling-identifying-outputs | Done | Read model catalog, query patterns, calculation classification |
83
+ ```
84
+
85
+ ---
86
+
87
+ ## CRITICAL: Events vs Read Models
88
+
89
+ **This is the most important distinction in event sourcing.** Many architectures fail because this line gets blurred.
90
+
91
+ ### Events = Immutable Domain Facts
92
+ Things that actually happened in the domain. Once created, they never change:
93
+ - CustomerCreated (a customer actually signed up)
94
+ - OrderPlaced (someone actually placed an order)
95
+ - PaymentAuthorized (payment gateway actually authorized)
96
+ - OrderShipped (fulfillment actually shipped the order)
97
+
98
+ **Characteristics**:
99
+ - Represents an action someone took
100
+ - Immutable once recorded
101
+ - Can be replayed to rebuild state
102
+ - Provides audit trail
103
+ - Independent of other events
104
+
105
+ ### Read Models = Derived Projections
106
+ Optimized views calculated FROM events. They recalculate multiple times:
107
+ - CustomerDashboard (projects current customer data)
108
+ - OrderStatusView (projects order state)
109
+ - InventoryLevelView (projects available stock from receipt/sale events)
110
+ - InventoryLevel (projects available stock)
111
+
112
+ **Characteristics**:
113
+ - Calculated/aggregated state
114
+ - Recalculates when source events change
115
+ - Derived from other events
116
+ - Query optimization
117
+ - Can be regenerated from events
118
+
119
+ ### The Test: Is It an Event or Read Model?
120
+
121
+ Ask these questions in order:
122
+
123
+ | Question | Answer | Type | Example |
124
+ |----------|--------|------|---------|
125
+ | Did an actor perform an action? | YES | EVENT | Customer confirmed the order |
126
+ | Is this pure calculation? | YES | READ MODEL | Inventory level total |
127
+ | Is it immutable once created? | YES | EVENT | PaymentAuthorized |
128
+ | Does it recalculate multiple times? | YES | READ MODEL | Total sales (updates as orders change) |
129
+ | Is it independent (causes no other events)? | YES | EVENT | OrderFlagged (flagged for manual review) |
130
+ | Is it derived FROM other events? | YES | READ MODEL | OrderStatus (derived from multiple events) |
131
+
132
+ ### Common Anti-Patterns
133
+
134
+ **DON'T model these as EVENTS**:
135
+ - Inventory level totals (calculation from stock events)
136
+ - Inventory totals (sum of transactions)
137
+ - Account balances (calculation from transactions)
138
+ - Search indexes (derived from documents)
139
+ - Aggregated metrics (sums, counts, averages)
140
+ - Scheduled calculations (processor outputs that are pure calculation)
141
+
142
+ **DO model them as READ MODELS**:
143
+
144
+ WRONG: Modeling as Event
145
+ ```
146
+ InventoryLevelRecalculated
147
+ productId: product-456
148
+ currentStock: 84 (This recalculates!)
149
+ reservedStock: 12 (Derived, not a fact)
150
+ ```
151
+
152
+ CORRECT: Model as Read Model
153
+ ```
154
+ InventoryLevelView
155
+ productId: product-456
156
+ totalReceived: 200
157
+ totalSold: 116
158
+ currentStock: 84
159
+ lastUpdated: 2025-01-24T10:30:00Z
160
+ history:
161
+ - 2024-12-01: stock 150 (200 received)
162
+ - 2024-12-15: stock 110 (40 sold)
163
+ - 2025-01-24: stock 84 (26 sold)
164
+ ```
165
+
166
+ **WHY**:
167
+ - Events should capture facts (what happened)
168
+ - Calculations should be projections (how we view the facts)
169
+ - Otherwise you end up with circular dependencies and replay issues
170
+
171
+ ---
172
+
173
+ ## Workflow
174
+
175
+ Given commands and events, identify all outputs:
176
+
177
+ ### 1. Map Event Data to UI Screens
178
+ For each screen, identify source events:
179
+
180
+ ```
181
+ Screen: Order Status View
182
+ Displays data from events:
183
+ orderId ← OrderCreated event
184
+ customerId ← OrderCreated event
185
+ items ← OrderCreated event
186
+ total ← OrderCreated event
187
+ status ← OrderConfirmed event (or OrderCancelled)
188
+ confirmedAt ← OrderConfirmed event
189
+ paymentId ← PaymentAuthorized event
190
+ shipmentId ← OrderShipped event
191
+ shippedAt ← OrderShipped event
192
+
193
+ This screen is a projection of these events:
194
+ - OrderCreated
195
+ - OrderConfirmed
196
+ - PaymentAuthorized
197
+ - OrderShipped
198
+ ```
199
+
200
+ ### 2. Define Read Models
201
+ Create optimized views from event data:
202
+
203
+ ```
204
+ ReadModel: OrderStatusView
205
+ Purpose: UI displays current order status
206
+ Events subscribed: OrderCreated, OrderConfirmed, PaymentAuthorized, OrderShipped, OrderCancelled
207
+ Data:
208
+ {
209
+ orderId: string (from OrderCreated)
210
+ customerId: string (from OrderCreated)
211
+ status: enum (from events: Draft → Confirmed → Authorized → Shipped → Delivered)
212
+ createdAt: Date (from OrderCreated)
213
+ confirmedAt: Date (from OrderConfirmed)
214
+ paymentId: string (from PaymentAuthorized)
215
+ shipmentId: string (from OrderShipped)
216
+ shippedAt: Date (from OrderShipped)
217
+ }
218
+ ```
219
+
220
+ ### 3. Document Event → Data Mapping
221
+ Show exactly what data each event provides:
222
+
223
+ ```
224
+ Event: OrderCreated
225
+ Provides to UI/Processors:
226
+ orderId
227
+ customerId
228
+ items[]
229
+ total
230
+ shippingAddress
231
+ createdAt
232
+
233
+ Event: OrderConfirmed
234
+ Provides to UI/Processors:
235
+ orderId (link to stream)
236
+ paymentMethod (user selected method)
237
+ confirmedAt (timestamp)
238
+ paymentId (payment system reference)
239
+
240
+ Event: PaymentAuthorized
241
+ Provides to UI/Processors:
242
+ orderId (link to stream)
243
+ paymentId
244
+ authCode
245
+ authorizedAt (timestamp)
246
+ amount (verified amount)
247
+
248
+ Event: OrderShipped
249
+ Provides to UI/Processors:
250
+ orderId (link to stream)
251
+ shipmentId
252
+ shippedAt (timestamp)
253
+ carrier (shipping company)
254
+ trackingNumber (for delivery tracking)
255
+ ```
256
+
257
+ ### 4. Create Output Catalog
258
+ List all read models:
259
+
260
+ ```
261
+ ReadModel Catalog: Order System
262
+
263
+ 1. OrderStatusReadModel
264
+ Purpose: UI shows current order status
265
+ Events: OrderCreated, OrderConfirmed, PaymentAuthorized, OrderShipped, OrderCancelled
266
+ Data: orderId, status, createdAt, confirmedAt, paymentId, shipmentId
267
+ Consumed by:
268
+ - Order Status screen (UI)
269
+ - Customer Dashboard (UI)
270
+ - Order Processing Processor (decides if can ship)
271
+
272
+ 2. OrderListReadModel
273
+ Purpose: UI lists all orders for a customer
274
+ Events: OrderCreated, OrderConfirmed, OrderCancelled
275
+ Data: orderId, customerId, total, status, createdAt
276
+ Consumed by:
277
+ - Customer Order History (UI)
278
+ - Order Search/Filter (UI)
279
+
280
+ 3. PaymentStatusReadModel
281
+ Purpose: UI shows payment status
282
+ Events: OrderConfirmed, PaymentAuthorized, PaymentFailed
283
+ Data: orderId, paymentId, status, authCode, failureReason, timestamp
284
+ Consumed by:
285
+ - Payment Status screen (UI)
286
+ - Accounting Processor (reconciliation)
287
+
288
+ 4. ShipmentTrackingReadModel
289
+ Purpose: UI shows tracking information
290
+ Events: OrderShipped, DeliveryConfirmed
291
+ Data: orderId, shipmentId, trackingNumber, carrier, shippedAt, estimatedDelivery
292
+ Consumed by:
293
+ - Order Tracking screen (UI)
294
+ - Customer notifications (Processor)
295
+ ```
296
+
297
+ ### 5. Identify Missing Data
298
+ Check if all UI needs are covered:
299
+
300
+ ```
301
+ Question: What if UI needs "estimated delivery date"?
302
+ Event: OrderShipped has carrier + trackingNumber
303
+ Action needed: Add estimatedDelivery to OrderShipped event
304
+ (or compute from carrier info)
305
+
306
+ Question: What if UI needs to show "payment method" on status?
307
+ Event: OrderConfirmed has paymentMethod
308
+ Action needed: Include paymentMethod in relevant read models
309
+
310
+ Question: What if UI needs "item descriptions"?
311
+ Event: OrderCreated has items[]
312
+ But: items[] only has productId
313
+ Action needed: Enrich with product descriptions from catalog
314
+ (via join with product service)
315
+ ```
316
+
317
+ ### 6. Processor Outputs
318
+ Identify what processors consume:
319
+
320
+ ```
321
+ Processor: Inventory System
322
+ Consumes from read models:
323
+ - Orders in "PaymentAuthorized" status
324
+ - Items and quantities needed
325
+ Produces commands:
326
+ - ReserveInventory
327
+
328
+ Processor: Fulfillment System
329
+ Consumes from read models:
330
+ - Orders in "InventoryReserved" status
331
+ - Items and quantities
332
+ - Shipping address
333
+ Produces commands:
334
+ - CreateShipment
335
+
336
+ Processor: Notification System
337
+ Consumes from read models:
338
+ - OrderCreated (sends confirmation)
339
+ - OrderConfirmed (sends receipt)
340
+ - OrderShipped (sends tracking)
341
+ - DeliveryConfirmed (sends thank you)
342
+ Does not produce commands (info-only)
343
+ ```
344
+
345
+ ## Output Format
346
+
347
+ Instead of writing a markdown document, **place each READMODEL (and any missing AUTOMATION) on the board** using the `node:created` API. Screens are typically already placed from Step 3 (storyboarding) — do not re-place them unless one is clearly missing. Automations are placed here when analysis reveals a processor that reads state and issues commands but is not yet on the board.
348
+
349
+ > **CRITICAL: Every READMODEL node MUST include `meta.fields` with a `mapping` on every field.** A read model without fields — or with fields that lack `mapping` — has no data lineage and cannot be traced back to its source events.
350
+
351
+ ### The typical slice pattern
352
+
353
+ The standard pattern for a screen in an event model is:
354
+
355
+ ```
356
+ READ MODEL → SCREEN → COMMAND → EVENT
357
+ ```
358
+
359
+ **Most screens need a read model on their left** — not only view/status screens, but also command/input screens that show current state before the user acts (e.g., a booking form that displays a bike's current availability, a checkout screen that shows the cart). The read model feeds the screen; the screen triggers a command; the command produces an event.
360
+
361
+ Pure view screens (no outgoing command) follow a shorter pattern:
362
+ ```
363
+ READ MODEL → SCREEN
364
+ ```
365
+
366
+ Automations follow:
367
+ ```
368
+ READ MODEL → AUTOMATION → COMMAND → EVENT
369
+ ```
370
+
371
+ Treat any screen or automation without an incoming read model as a gap unless it provably needs no prior state at all (e.g., a blank registration form).
372
+
373
+ ### Read models serve existing screens and automations
374
+
375
+ **Before designing any read model, enumerate every SCREEN and AUTOMATION already placed on the board** (from Step 3 — Storyboarding). Read models exist to serve those elements:
376
+
377
+ - Every **view screen** (output/read model screen) needs at least one read model to supply its data.
378
+ - Every **automation** that makes a decision based on system state needs at least one read model to read from.
379
+ - Every **command/input screen** needs a read model unless it is a blank creation form with no prior state to display (this is the rare exception, not the rule).
380
+
381
+ After the step is done, **every SCREEN and every AUTOMATION on the board must be connected to at least one read model** via a `READMODEL → SCREEN` or `READMODEL → AUTOMATION` connection. If a screen or automation has no incoming read model connection, it is a gap — either a read model is missing or the connection arrow is missing.
382
+
383
+ > **Placement rule**: A read model must be placed in a column that already contains a SCREEN or AUTOMATION it serves. Do not place read models in columns with no screen or automation — doing so creates orphaned read models that will never have a consumer.
384
+
385
+ ### Field data lineage — the `mapping` attribute on READMODEL fields
386
+
387
+ Every field on a READMODEL must carry a `mapping` that says exactly which event (or command) field it is projected from. Use one of these forms:
388
+
389
+ | `mapping` format | Meaning | `generated` | Example |
390
+ |---|---|---|---|
391
+ | `"<EventTitle>.<fieldName>"` | Projected directly from an event field | `false` | `"BikeReserved.customerId"` |
392
+ | `"latest:<EventTitle>.<fieldName>"` | Latest value from the most recent event of this type | `false` | `"latest:BikeStatusChanged.toStatus"` |
393
+ | `"aggregate:<EventTitle>.<fieldName>"` | Aggregated across multiple events of this type | `true` | `"aggregate:RentalEnded.durationMinutes"` |
394
+ | `"derived:<expression>"` | Calculated from other read model fields | `true` | `"derived:sum(lineItems.amount)"` |
395
+
396
+ Set the field's `generated` property according to this table. Fields projected directly from events are not generated — they carry a real domain value. Fields that are aggregated or calculated by the system are generated.
397
+
398
+ **Field traceability rule**: Every field in a read model must trace back to at least one source event. If a field cannot be mapped to any event in the timeline, it is either:
399
+ - A calculated/derived field — document the derivation expression, or
400
+ - A missing event field — add it to the source event before proceeding.
401
+
402
+ > **Connected-element rule**: A read model's field `mapping` may only reference EVENTs that are connected to this READMODEL via a board `EVENT → READMODEL` arrow. If a field needs data from an event that is not connected, either add the connection or flag it as a gap. **If a mapping cannot be defined for a field, it signals missing data in the model, a missing event, or a modeling error.** Do not leave unmapped fields without a note.
403
+
404
+ Every field must also set `"cardinality"` — use `"Single"` unless the field genuinely holds a list of values (e.g. line items, a collection projected from multiple events), in which case use `"List"`. Default to `"Single"` when unsure. Include only the fields the consuming SCREEN or AUTOMATION actually displays or needs — do not add speculative fields; enrich later via `/attributes`.
405
+
406
+ ```json
407
+ {
408
+ "type": "READMODEL",
409
+ "title": "ActiveReservationView",
410
+ "fields": [
411
+ {"name": "reservationId", "type": "String", "example": "res-001", "mapping": "BikeReserved.reservationId", "generated": false},
412
+ {"name": "customerId", "type": "String", "example": "cust-42", "mapping": "BikeReserved.customerId", "generated": false},
413
+ {"name": "bikeId", "type": "String", "example": "bike-17", "mapping": "BikeReserved.bikeId", "generated": false},
414
+ {"name": "stationId", "type": "String", "example": "stn-03", "mapping": "BikeReserved.stationId", "generated": false},
415
+ {"name": "expiresAt", "type": "Date", "example": "2026-06-01T09:30:00Z", "mapping": "ReservationConfirmed.expiresAt", "generated": false},
416
+ {"name": "status", "type": "String", "example": "confirmed", "mapping": "latest:ReservationConfirmed.status", "generated": false}
417
+ ]
418
+ }
419
+ ```
420
+
421
+ Read models go in the `interaction` lane — **in the same column as the SCREEN or AUTOMATION they serve** (READMODEL in interaction row, SCREEN in actor row of the same column).
422
+
423
+ > **Timeline alignment rule**: Place the read model in the same column as its consumer screen/automation. If that column already holds a COMMAND (state-change slice occupies the interaction row), insert a new column immediately after (`{"index": N+1}`) and place both the READMODEL and any new SCREEN there. Do not append read model columns to the end of the timeline — doing so severs the visual left→right flow from data projection to UI consumption.
424
+
425
+ ### Placing READMODEL and AUTOMATION nodes with `cellId` (Mandatory)
426
+
427
+ **Every `node:created` call MUST include `cellId`.** Without it the node has no cell reference and will appear stranded at position 0,0 — not in any timeline column.
428
+
429
+ **For a READMODEL** (interaction lane):
430
+
431
+ 1. Find the column where the consumer SCREEN or AUTOMATION lives. Fetch the timeline to get the interaction row ID:
432
+ ```bash
433
+ curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
434
+ "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/$CHAPTER_ID"
435
+ # → timelineData.rows — find the row where type === "interaction"
436
+ ```
437
+ 2. Check if the interaction cell is already occupied (existing COMMAND):
438
+ ```bash
439
+ curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?cellId=<interactionRowId>-<columnId>" \
440
+ -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID"
441
+ ```
442
+ If a COMMAND occupies that cell, insert a new column immediately after (`{"index": currentIndex + 1}`) and use that column's ID instead.
443
+ 3. `cellId = interactionRow.id + "-" + columnId`
444
+ 4. Create the READMODEL:
445
+ ```bash
446
+ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
447
+ -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: identifying-outputs" \
448
+ -H "Content-Type: application/json" \
449
+ -d '[{
450
+ "id": "<event-uuid>",
451
+ "eventType": "node:created",
452
+ "nodeId": "<node-uuid>",
453
+ "boardId": "<BOARD_ID>",
454
+ "timestamp": 1234567890,
455
+ "chapterId": "<CHAPTER_ID>",
456
+ "cellId": "<interactionRowId>-<columnId>",
457
+ "meta": {"type": "READMODEL", "title": "ActiveReservationView", "fields": [...]}
458
+ }]'
459
+ ```
460
+
461
+ **For an AUTOMATION** (actor lane, same column as its READMODEL):
462
+
463
+ 1. Get the actor row ID from the same timeline fetch (row where `type === "actor"`).
464
+ 2. `cellId = actorRow.id + "-" + columnId`
465
+ 3. Create the AUTOMATION node using the same `node:created` pattern above with `"type": "AUTOMATION"` in `meta`.
466
+
467
+ > **Never call `drop` after using `cellId` in `node:created`.** The drop endpoint adds a second cell reference without removing the first. `node:created + cellId` is the only placement step needed.
468
+
469
+ ### Preventing backward arrows (mandatory pre-placement check)
470
+
471
+ The timeline must always progress left-to-right. A `READMODEL → SCREEN` connection going right-to-left is a layout error.
472
+
473
+ The correct layout is: **READMODEL in column N, SCREEN in column N+1** (the screen is always one column to the right of its read model). Before placing each read model, find the view screen it serves and verify the column order:
474
+
475
+ ```
476
+ For each view screen S that queries this read model:
477
+ If column(S) <= intended column(READMODEL):
478
+ → The screen is not to the right of the read model. Fix before placing.
479
+ Option A: Insert a new column immediately after the read model's column
480
+ and move screen S there.
481
+ Use POST /timelines/:tl/columns {"index": N} to insert,
482
+ then node:changed to update the screen node's cell.
483
+ If column(S) == intended column(READMODEL) + 1:
484
+ → Screen is already in the correct column directly to the right. No adjustment needed.
485
+ If column(S) > intended column(READMODEL) + 1:
486
+ → Gap between read model and screen. Move the read model to column(S) - 1, or move the screen to column(READMODEL) + 1.
487
+ ```
488
+
489
+ **View screens go in the column immediately to the right of the read model they display** — either because they were placed there in Step 3, or because you move them here now.
490
+
491
+ ### Wire connections after placing each READMODEL (and its SCREEN)
492
+
493
+ After `place-element` returns the READMODEL node ID, create the arrows that complete the slice:
494
+
495
+ 1. **EVENT → READMODEL** — find the primary source EVENT node in the swimlane row of the same column:
496
+ ```bash
497
+ curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?cellId=<swimlaneRowId>-<columnId>" \
498
+ -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: eventmodeling-identifying-outputs"
499
+ ```
500
+ Connect it:
501
+ ```bash
502
+ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/connections" \
503
+ -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: eventmodeling-identifying-outputs" \
504
+ -H "Content-Type: application/json" \
505
+ -d '{"source":"<eventNodeId>","target":"<readmodelNodeId>"}'
506
+ ```
507
+
508
+ 2. **READMODEL → SCREEN** — connect to the existing SCREEN node in the actor row of the next column (screens are typically already placed from Step 3):
509
+ ```bash
510
+ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/connections" \
511
+ -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: eventmodeling-identifying-outputs" \
512
+ -H "Content-Type: application/json" \
513
+ -d '{"source":"<readmodelNodeId>","target":"<screenNodeId>"}'
514
+ ```
515
+
516
+ 3. **READMODEL → AUTOMATION** — if the read model is consumed by an automatic process (scheduler, background job, external trigger), place the AUTOMATION node and connect it:
517
+ - Place the AUTOMATION in the automation lane, in the column immediately to the right of its read model (same rule as screens).
518
+ - Then connect:
519
+ ```bash
520
+ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/connections" \
521
+ -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: eventmodeling-identifying-outputs" \
522
+ -H "Content-Type: application/json" \
523
+ -d '{"source":"<readmodelNodeId>","target":"<automationNodeId>"}'
524
+ ```
525
+
526
+ Skip a connection silently if the target cell is empty. Log each created arrow: `→ connected EVENT→READMODEL "OrderPlaced"→"OrderStatusView"`, `→ connected READMODEL→SCREEN "OrderStatusView"→"Order Status Screen"`, or `→ connected READMODEL→AUTOMATION "OrderStatusView"→"Fulfillment Processor"`.
527
+
528
+ After all read models, screens, automations, and connections are in place, present the Read Model Catalog summary as text to the user.
529
+
530
+ ---
531
+
532
+ For reference, the full markdown structure is:
533
+
534
+ ```markdown
535
+ # Outputs: [Domain Name]
536
+
537
+ ## Read Models Summary
538
+
539
+ | ReadModel | Purpose | Events | Consumed By |
540
+ |-----------|---------|--------|-------------|
541
+ | OrderStatus | Show order state | OrderCreated, OrderConfirmed | UI, Processor |
542
+ | OrderList | List orders | OrderCreated, OrderCancelled | UI |
543
+ | PaymentStatus | Payment info | OrderConfirmed, PaymentAuthorized | UI, Accounting |
544
+ | Shipment Tracking | Track delivery | OrderShipped, DeliveryConfirmed | UI, Notifications |
545
+
546
+ ---
547
+
548
+ ## Detailed Read Models
549
+
550
+ ### ReadModel: OrderStatusView
551
+
552
+ **Purpose**: Order Status screen displays current order state
553
+
554
+ **Events subscribed**:
555
+ - OrderCreated
556
+ - OrderConfirmed
557
+ - PaymentAuthorized
558
+ - OrderShipped
559
+ - OrderCancelled
560
+ - DeliveryConfirmed
561
+
562
+ **Data**:
563
+ ```
564
+ {
565
+ orderId: string
566
+ customerId: string
567
+ status: 'Draft' | 'Confirmed' | 'Authorized' | 'Shipped' | 'Delivered' | 'Cancelled'
568
+ items: Array<{productId, quantity, unitPrice}>
569
+ total: number
570
+ shippingAddress: Address
571
+
572
+ createdAt: Date
573
+ confirmedAt: Date
574
+ paymentId: string
575
+ paymentMethod: 'card' | 'transfer'
576
+ authorizedAt: Date
577
+
578
+ shipmentId: string
579
+ carrier: string
580
+ trackingNumber: string
581
+ shippedAt: Date
582
+ estimatedDelivery: Date
583
+ }
584
+ ```
585
+
586
+ **Update Logic**:
587
+ - OrderCreated: Insert with status='Draft'
588
+ - OrderConfirmed: Update status='Confirmed'
589
+ - PaymentAuthorized: Update status='Authorized', set paymentId
590
+ - OrderShipped: Update status='Shipped', set shipmentId, carrier, trackingNumber
591
+ - DeliveryConfirmed: Update status='Delivered'
592
+ - OrderCancelled: Update status='Cancelled'
593
+
594
+ **Consumed By**:
595
+ - Order Status Screen (displays)
596
+ - Order Processing Processor (checks status)
597
+ - Notification System (sends updates)
598
+
599
+ --- [Repeat for each read model]
600
+
601
+ ---
602
+
603
+ ## Data Completeness Check
604
+
605
+ ### Events → UI Needs
606
+
607
+ Verify all UI needs have event sources:
608
+
609
+ | UI Need | Event Source | Status |
610
+ |---------|-------------|--------|
611
+ | Order status | OrderConfirmed, OrderShipped | |
612
+ | Tracking number | OrderShipped | |
613
+ | Order items | OrderCreated | |
614
+ | Estimated delivery | OrderShipped | |
615
+ | Cancellation reason | OrderCancelled | |
616
+
617
+ ### Missing Data
618
+
619
+ Identify UI needs without event sources:
620
+ - None identified
621
+
622
+ ---
623
+
624
+ ## Processor Consumption
625
+
626
+ ### Processors and their reads:
627
+
628
+ | Processor | Reads From | Writes Commands |
629
+ |-----------|-----------|-----------------|
630
+ | Inventory | OrderStatusView (Authorized) | ReserveInventory |
631
+ | Fulfillment | OrderStatusView (InventoryReserved) | CreateShipment |
632
+ | Notification | OrderStatusView (all) | None (info-only) |
633
+ | Accounting | PaymentStatusView | None (reporting) |
634
+ ```
635
+
636
+ ## Quality Checklist
637
+
638
+ ### Read Model Design
639
+ - [ ] **Typical pattern applied**: most screens follow `READ MODEL → SCREEN → COMMAND → EVENT`
640
+ - [ ] **Every SCREEN from storyboarding is connected to at least one read model** (via `READMODEL → SCREEN`); only blank creation forms may be exempt
641
+ - [ ] **Every AUTOMATION from storyboarding is connected to at least one read model** (via `READMODEL → AUTOMATION`)
642
+ - [ ] **No read model is placed without a connected SCREEN or AUTOMATION consumer**
643
+ - [ ] Every read model has clear purpose
644
+ - [ ] Every data field has event source
645
+ - [ ] Update logic for each event is explicit
646
+ - [ ] All UI needs are covered
647
+ - [ ] Processor reads are identified
648
+ - [ ] Read model access patterns clear
649
+ - [ ] No undocumented data sources
650
+ - [ ] Compensation/cancellation handled
651
+ - [ ] Error states shown
652
+
653
+ ### CRITICAL: Event vs Read Model Validation
654
+ - [ ] **Reviewed each read model**: "Is this pure calculation or an actual domain fact?"
655
+ - [ ] **No aggregations modeled as events**: (totals, averages, counts are read models)
656
+ - [ ] **No recalculated state modeled as events**: (if value changes multiple times, it's a read model)
657
+ - [ ] **Processor outputs are categorized**:
658
+ - [ ] Produces NEW EVENT = actual domain fact (e.g., PaymentAuthorized)
659
+ - [ ] Updates READ MODEL = calculation (e.g., SellerRatingCalculated)
660
+ - [ ] Sends NOTIFICATION = info-only (no event or model)
661
+ - [ ] **History tracking is clear**: Derived state keeps history in read model `history[]`, not as separate events
662
+
663
+ ## Key Principles
664
+
665
+ 1. **Event-Driven**: All data comes from events
666
+ 2. **Projection-Based**: Read models are projections, not persistent
667
+ 3. **UI-Focused**: Optimized for UI display needs
668
+ 4. **Processor-Friendly**: Enough data for processor decisions
669
+ 5. **Completeness**: All needed data available
670
+
671
+ ## Common Patterns
672
+
673
+ ### Status View Pattern
674
+ ```
675
+ Events: Create, Confirm, Process, Ship
676
+ ReadModel: Accumulates data from all events
677
+ Displayed: Current state reflecting all events
678
+ ```
679
+
680
+ ### List View Pattern
681
+ ```
682
+ Events: Create, Update, Delete (Cancel)
683
+ ReadModel: Summary of each item
684
+ Used for: Filtering, sorting, searching
685
+ ```
686
+
687
+ ### Timeline View Pattern
688
+ ```
689
+ Events: Any event with timestamp
690
+ ReadModel: Chronological list
691
+ Used for: History, audit trail
692
+ ```
693
+
694
+ ### Processor Decision Pattern
695
+ ```
696
+ Events: State-changing events
697
+ ReadModel: Current state only
698
+ Processor reads to decide next action
699
+ ```