@eventmodelers/cli 1.0.37 → 1.0.38

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 (25) hide show
  1. package/package.json +1 -1
  2. package/shared/skills/learn-eventmodelers-api/SKILL.md +10 -3
  3. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-applying-conways-law/SKILL.md +3 -61
  4. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/SKILL.md +24 -93
  5. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/SKILL.md +2 -0
  6. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-core-rules/SKILL.md +182 -0
  7. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-automation-chains/SKILL.md +23 -7
  8. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/SKILL.md +50 -223
  9. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/references/examples.md +30 -120
  10. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/SKILL.md +3 -78
  11. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/SKILL.md +3 -50
  12. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md +3 -54
  13. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-interview-protocol/SKILL.md +31 -0
  14. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/SKILL.md +27 -67
  15. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/domain-patterns.md +15 -15
  16. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/patterns.md +44 -52
  17. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/SKILL.md +14 -15
  18. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-plotting-events/SKILL.md +4 -0
  19. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/SKILL.md +3 -15
  20. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md +3 -50
  21. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-translating-external-events/SKILL.md +4 -56
  22. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/SKILL.md +58 -97
  23. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models-checklist/SKILL.md +72 -127
  24. package/stacks/modeling-kit/templates/.claude/skills/place-element/SKILL.md +15 -1
  25. package/stacks/modeling-kit/templates/.claude/skills/place-element/references/api-fallback.md +11 -1
@@ -11,14 +11,14 @@ allowed-tools:
11
11
 
12
12
  > **Before doing anything else**, invoke the `connect` skill — if not already connected — to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`. Do not proceed until it has completed. Consult `learn-eventmodelers-api` only if you need to look up a specific endpoint or field this file doesn't cover — don't load it eagerly.
13
13
 
14
+ This step applies the shared element rules in **`eventmodeling-core-rules`** — read it once per session if you haven't already; it defines what a COMMAND/EVENT/READMODEL/SCREEN/AUTOMATION is, how each is named, and the anti-patterns to reject, so this step doesn't restate them.
15
+
14
16
  Prefer `mcp__eventmodelers__*` tools when available (registered by the `connect` skill) — the curl blocks below are the fallback for sessions without MCP connected.
15
17
 
16
18
  ## Interview Phase (Optional)
17
19
 
18
20
  **When to Interview**: Skip if the user has already identified UI actions/commands and processor triggers. Interview when it's unclear which actions are user-initiated vs. processor-automated.
19
21
 
20
- **Interview Strategy**: Separate UI-driven commands from processor-driven commands before cataloging inputs. Mixing them leads to incorrect role attribution, which breaks the Role Catalog traceability that downstream steps depend on.
21
-
22
22
  ### Critical Questions
23
23
 
24
24
  1. **Automation Level** (Impact: Determines which commands are UI-triggered vs. processor-triggered)
@@ -31,54 +31,7 @@ Prefer `mcp__eventmodelers__*` tools when available (registered by the `connect`
31
31
  - Why it matters: External triggers are processor commands, not UI commands
32
32
  - Follow-up triggers: If (B) or (D) → ask which external systems send webhooks and what data they include
33
33
 
34
- ### Interview Flow
35
-
36
- **Conditional Entry**:
37
- ```
38
- If user has provided:
39
- - UI actions already listed per storyboard screen
40
- - AND processor triggers identified with source systems named
41
- - AND it's clear which role/actor initiates each action
42
-
43
- Then: Skip interview, proceed directly to command identification
44
-
45
- Else: Conduct interview
46
- ```
47
-
48
- **Phase 1: Trigger Classification** (Question 1)
49
- - Establish which commands come from human actors vs. automated processors
50
- - Confirm Role Catalog from Step 1 is available for attribution
51
-
52
- **Phase 2: External Triggers** (Question 2)
53
- - Identify all external system integrations that issue commands
54
- - Confirm whether scheduled jobs or event-driven processors exist
55
-
56
- ### Capturing Interview Findings
57
-
58
- Append findings to the project's event modeling file:
59
-
60
- **File**: `.trogonai/interviews/[project-name]/EVENTMODELING.md`
61
-
62
- Use Write tool to add/update this section:
63
-
64
- ```markdown
65
- ## 4. Identifying Inputs (eventmodeling-identifying-inputs)
66
-
67
- ### Automation Classification
68
- [From Q1: Which actions are user-initiated vs. processor-automated?]
69
-
70
- ### External System Triggers
71
- [From Q2: Which external systems trigger commands? Webhook formats?]
72
-
73
- ### Command Attribution Summary
74
- - UI-issued commands: [list with role from Role Catalog]
75
- - Processor-issued commands: [list with source system]
76
- ```
77
-
78
- Update Interview Trail:
79
- ```markdown
80
- | 4 | eventmodeling-identifying-inputs | Done | UI commands, processor commands, role attribution |
81
- ```
34
+ Follow **`eventmodeling-interview-protocol`** to run this interview and record its findings — label this step "**4. Identifying Inputs** (`eventmodeling-identifying-inputs`)". Findings should cover: automation classification (user-initiated vs. processor-automated), external system triggers, and a command attribution summary (UI-issued vs. processor-issued, each with its role/source).
82
35
 
83
36
  ---
84
37
 
@@ -11,14 +11,14 @@ allowed-tools:
11
11
 
12
12
  > **Before doing anything else**, invoke the `connect` skill — if not already connected — to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`. Do not proceed until it has completed. Consult `learn-eventmodelers-api` only if you need to look up a specific endpoint or field this file doesn't cover — don't load it eagerly.
13
13
 
14
+ This step applies the shared element rules in **`eventmodeling-core-rules`** — read it once per session if you haven't already; it defines what a COMMAND/EVENT/READMODEL/SCREEN/AUTOMATION is, how each is named, and the anti-patterns to reject, so this step doesn't restate them.
15
+
14
16
  Prefer `mcp__eventmodelers__*` tools when available (registered by the `connect` skill) — the curl blocks below are the fallback for sessions without MCP connected.
15
17
 
16
18
  ## Interview Phase (Optional)
17
19
 
18
20
  **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.
19
21
 
20
- **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.
21
-
22
22
  ### Critical Questions
23
23
 
24
24
  1. **Query Patterns** (Impact: Determines which read models are needed and their update frequency)
@@ -31,58 +31,7 @@ Prefer `mcp__eventmodelers__*` tools when available (registered by the `connect`
31
31
  - Why it matters: Common mistake to model calculations as events; identifying them upfront prevents architecture errors
32
32
  - 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?"
33
33
 
34
- ### Interview Flow
35
-
36
- **Conditional Entry**:
37
- ```
38
- If user has provided:
39
- - UI screens with data needs mapped to event sources
40
- - AND processor query needs documented
41
- - AND calculated/aggregated fields identified as read models (not events)
42
-
43
- Then: Skip interview, proceed directly to read model design
44
-
45
- Else: Conduct interview
46
- ```
47
-
48
- **Phase 1: Query Pattern Mapping** (Question 1)
49
- - Identify which UI screens and processors need which data
50
- - Typically every screen needs some kind of data, same for automations.
51
- - Establish freshness requirements per consumer
52
- - Determine if any queries require real-time consistency
53
-
54
- **Phase 2: Calculation Detection** (Question 2)
55
- - Surface any aggregated or computed values
56
- - Confirm they are projections, not events
57
- - Prevent the calculation-as-event anti-pattern before design begins
58
-
59
- ### Capturing Interview Findings
60
-
61
- Append findings to the project's event modeling file:
62
-
63
- **File**: `.trogonai/interviews/[project-name]/EVENTMODELING.md`
64
-
65
- Use Write tool to add/update this section:
66
-
67
- ```markdown
68
- ## 5. Identifying Outputs (eventmodeling-identifying-outputs)
69
-
70
- ### Query Patterns
71
- [From Q1: Which consumers need what freshness? Real-time vs. periodic?]
72
-
73
- ### Calculated Fields Identified
74
- [From Q2: Which fields are aggregated/calculated? Confirmed as read models?]
75
-
76
- ### Read Model Summary
77
- - Real-time read models: [list]
78
- - Near-real-time read models: [list]
79
- - Calculation-as-event anti-patterns caught: [list or "None"]
80
- ```
81
-
82
- Update Interview Trail:
83
- ```markdown
84
- | 5 | eventmodeling-identifying-outputs | Done | Read model catalog, query patterns, calculation classification |
85
- ```
34
+ Follow **`eventmodeling-interview-protocol`** to run this interview and record its findings — label this step "**5. Identifying Outputs** (`eventmodeling-identifying-outputs`)". Findings should cover: query patterns (which consumers need what freshness), calculated/aggregated fields identified (and confirmed as read models, not events), and a read model summary by freshness tier.
86
35
 
87
36
  ---
88
37
 
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: eventmodeling-interview-protocol
3
+ description: Shared procedure for deciding whether to ask the user clarifying questions before an event-modeling step proceeds, and how to record what was decided. Not a step of its own — referenced by other eventmodeling-* skills' Interview Phase section. Do not use standalone.
4
+ ---
5
+
6
+ # Interview Protocol
7
+
8
+ Shared by every event-modeling step that has an "Interview Phase" section. A step's own SKILL.md defines only what's specific to it — when to interview and its Critical Questions. Everything below is common to all of them.
9
+
10
+ ## When to ask
11
+
12
+ Missing information, or something ambiguous that this step needs? Ask the user — using the step's own Critical Questions as a guide, via `AskUserQuestion` where appropriate. Follow any listed follow-up trigger based on the answer.
13
+
14
+ Already have everything the step needs? Skip straight to the step's own workflow — don't ask questions whose answers you already have.
15
+
16
+ **Unless told not to ask** (an autonomous/unattended run, or the user has said not to stop for questions): don't block. Proceed with the most reasonable assumption for anything missing, and say so plainly in this step's findings below — visibly, so it can be corrected later. Never silently guess.
17
+
18
+ ## Recording the outcome
19
+
20
+ Append to the project's event modeling file: `.trogonai/interviews/[project-name]/EVENTMODELING.md`, under a section for this step:
21
+
22
+ ```markdown
23
+ ## <Step Number>. <Step Name> (<skill-name>)
24
+ [What was asked and decided — or, if nothing was asked, what was assumed and why]
25
+ ```
26
+
27
+ Then add or update this step's row in the `## Interview Trail` table (create it if this is the first step to run):
28
+
29
+ ```markdown
30
+ | <Step Number> | <skill-name> | Done | <one-line summary of key outputs> |
31
+ ```
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: eventmodeling-optimizing-stream-design
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)."
3
+ description: "Validate and fix an entity's event timeline boundary — is it anchored on a single business identity, or is it secretly a collection/log that will grow unbounded? Use when concerned about a timeline mixing concerns, reviewing timeline boundaries, or when a timeline feels like it's absorbing unrelated events. Do not use for: designing the initial event model structure (use eventmodeling-designing-event-models) or general model validation (use eventmodeling-validating-event-models)."
4
4
  allowed-tools:
5
5
  - AskUserQuestion
6
6
  - Write
@@ -8,102 +8,64 @@ allowed-tools:
8
8
 
9
9
  # Optimizing Stream Design
10
10
 
11
- ## Interview Phase (Optional)
11
+ This step applies the shared element rules in **`eventmodeling-core-rules`** — read it once per session if you haven't already; it defines what a COMMAND/EVENT/READMODEL/SCREEN/AUTOMATION is, how each is named, and the anti-patterns to reject, so this step doesn't restate them.
12
12
 
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.
13
+ ## Timeline Boundary Optimization
14
14
 
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
-
17
- ### Critical Question
18
-
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.
23
-
24
- ### Capturing Interview Findings
25
-
26
- Append findings to the project's event modeling file:
27
-
28
- **File**: `.trogonai/interviews/[project-name]/EVENTMODELING.md`
29
-
30
- Use Write tool to add/update this section:
31
-
32
- ```markdown
33
- ## Optimizing Stream Design (eventmodeling-optimizing-stream-design)
34
-
35
- ### Stream Identity Review
36
- [Which streams were reviewed? What entity does each represent? Any that turned out to be a disguised collection/log?]
37
-
38
- ### Boundary Decisions
39
- - Streams requiring redesign: [list or "None"]
40
- - Streams confirmed well-bounded: [list]
41
- ```
42
-
43
- Update Interview Trail:
44
- ```markdown
45
- | Optimization | eventmodeling-optimizing-stream-design | Done | Stream identity review, boundary decisions |
46
- ```
47
-
48
- ---
49
-
50
- ## Stream Design Optimization
51
-
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.
15
+ **Purpose**: Validate timeline boundaries confirm each entity's event timeline 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 modeled further.
53
16
 
54
17
  **Applies To**: Any domain — e-commerce, banking, SaaS, marketplace, healthcare, etc.
55
18
 
56
19
  **When to Use**:
57
- - After defining event streams in domain analysis
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
20
+ - After defining events in domain analysis
21
+ - When a timeline feels like it's growing for reasons unrelated to one entity's own story
22
+ - When redesigning a timeline whose boundary turned out to be wrong
61
23
 
62
24
  **What It Does**:
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)
25
+ 1. Checks that each timeline has a single, natural business identity
26
+ 2. Identifies timelines that are actually collections or logs in disguise
27
+ 3. Recommends the correct boundary when one is wrong
28
+ 4. Distinguishes "this timeline is long because the entity has a long history" (fine) from "this timeline is long because it's absorbing events that don't belong to it" (a boundary bug)
67
29
 
68
30
  ---
69
31
 
70
32
  ## Core Principle: Get the Identity Right
71
33
 
72
34
  **Golden Rule**:
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?"
35
+ > If a timeline feels like it's growing for the wrong reasons, first ask: "Does this timeline actually have one business identity, or is it a collection/log wearing an entity's name?"
74
36
 
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.
37
+ A long timeline is not, by itself, evidence of a design problem — an account open for thirty years is correctly one long timeline. What *is* always a design problem is a timeline whose events don't all belong to the same entity's own lifecycle.
76
38
 
77
39
  ---
78
40
 
79
- ## Stream Boundary Review
41
+ ## Timeline Boundary Review
80
42
 
81
- For each stream in scope, work through:
43
+ For each entity's timeline in scope, work through:
82
44
 
83
45
  ### 1. Name the identity
84
46
 
85
- What single business entity does this stream represent the history of? Write it down explicitly (e.g. `orderId`, not "orders").
47
+ What single business entity does this timeline represent the history of? Write it down explicitly (e.g. `orderId`, not "orders").
86
48
 
87
49
  ### 2. Check every event against that identity
88
50
 
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).
51
+ Does each event on the timeline 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).
90
52
 
91
53
  ### 3. Classify the result
92
54
 
93
55
  | Result | Meaning | Action |
94
56
  |---|---|---|
95
57
  | 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 |
58
+ | 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 an event timeline |
59
+ | Events span unrelated concerns (users, orders, payments mixed) | Pattern 4 (Event Log) anti-pattern | Split into one timeline per concern |
60
+ | Timeline conflates an entity's active life with its historical record | Missing the Pattern 5 split | Separate active vs. archived/historical timelines |
99
61
 
100
62
  ---
101
63
 
102
64
  ## Reference Files
103
65
 
104
- **Aggregate Boundary Design**: See [patterns.md](references/patterns.md) for:
105
- - 5 aggregate boundary patterns (single entity, composite, collection anti-pattern, event-log anti-pattern, historical)
106
- - The stream boundary decision tree
66
+ **Timeline Boundary Design**: See [patterns.md](references/patterns.md) for:
67
+ - 5 boundary patterns (single entity, composite, collection anti-pattern, event-log anti-pattern, historical)
68
+ - The timeline boundary decision tree
107
69
  - Red flags that indicate the boundary — not the volume — is wrong
108
70
  - Tips for finding the right boundary
109
71
 
@@ -116,9 +78,7 @@ Does each event in the stream describe something that happened to *this* entity
116
78
 
117
79
  ## Quality Checklist
118
80
 
119
- - [ ] Each stream is identified by a business entity identity (e.g., `orderId`), not a category or type
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
122
- - [ ] Command handler state is reconstructed from stream events no persistent state stored outside the stream
123
- - [ ] Each stream can be independently versioned and replayed without affecting other streams
124
- - [ ] A stream that conflates an entity's active life with its historical record has been split (active vs. archived)
81
+ - [ ] Each timeline is identified by a business entity identity (e.g., `orderId`), not a category or type
82
+ - [ ] Every event on a timeline belongs to that one entity's own lifecycle — none of them describe a different entity or an unrelated system concern
83
+ - [ ] No timeline is secretly a collection ("all X") or a log ("everything that happened") wearing an entity's name
84
+ - [ ] A timeline that conflates an entity's active life with its historical record has been split (active vs. archived)
@@ -1,4 +1,4 @@
1
- # Domain-Specific Stream Boundary Patterns
1
+ # Domain-Specific Timeline Boundary Patterns
2
2
 
3
3
  ## Contents
4
4
  - E-commerce patterns
@@ -11,7 +11,7 @@ Each entry shows a well-scoped boundary for that domain: what identity it's anch
11
11
 
12
12
  ## E-commerce Domain
13
13
 
14
- **Order Aggregate**:
14
+ **Order Entity**:
15
15
  ```
16
16
  Identity: orderId
17
17
  Lifetime: 1-3 years
@@ -20,17 +20,17 @@ Reason for this boundary: the order has a clear owner (one customer,
20
20
  one checkout) and a natural end (delivered, cancelled, refunded)
21
21
  ```
22
22
 
23
- **Shopping Cart Aggregate**:
23
+ **Shopping Cart Entity**:
24
24
  ```
25
25
  Identity: cartId (or customerId, if a customer has exactly one active cart)
26
26
  Lifetime: 30 minutes to 2 years (varies widely by product)
27
27
  Boundary: Items added/removed for this one cart
28
28
  Watch for: an "abandoned" cart and an "active" cart are different
29
- lifecycles — split into separate streams if their behavior diverges
29
+ lifecycles — split into separate timelines if their behavior diverges
30
30
  (e.g. abandoned-cart recovery vs. active checkout flow)
31
31
  ```
32
32
 
33
- **User Account Aggregate**:
33
+ **User Account Entity**:
34
34
  ```
35
35
  Identity: userId
36
36
  Lifetime: 5-10+ years
@@ -44,26 +44,26 @@ different concerns with different change frequency — split them
44
44
 
45
45
  ## Banking Domain
46
46
 
47
- **Account Aggregate**:
47
+ **Account Entity**:
48
48
  ```
49
49
  Identity: accountId
50
50
  Lifetime: 10-50+ years
51
51
  Boundary: Deposits, withdrawals, and fees for this one account
52
52
  Watch for: an account spanning decades is still one identity — the
53
- boundary is correct even though the stream is long-lived; don't
53
+ boundary is correct even though the timeline is long-lived; don't
54
54
  split it just because it accumulates many events over a long life
55
55
  ```
56
56
 
57
- **Transaction Aggregate**:
57
+ **Transaction Entity**:
58
58
  ```
59
59
  Identity: transactionId
60
60
  Lifetime: 1-2 months (then archived)
61
61
  Boundary: Requested → Processing → Settled, for this one transaction
62
62
  Reason for this boundary: a transaction is a short, self-contained
63
- lifecycle — treat it as its own stream, not folded into the account
63
+ lifecycle — treat it as its own timeline, not folded into the account
64
64
  ```
65
65
 
66
- **Loan Aggregate**:
66
+ **Loan Entity**:
67
67
  ```
68
68
  Identity: loanId
69
69
  Lifetime: 5-30 years
@@ -77,7 +77,7 @@ ActiveLoan vs. CompletedLoan if their consumers genuinely differ
77
77
 
78
78
  ## SaaS Domain
79
79
 
80
- **Subscription Aggregate**:
80
+ **Subscription Entity**:
81
81
  ```
82
82
  Identity: subscriptionId
83
83
  Lifetime: 1-5+ years
@@ -86,17 +86,17 @@ Reason for this boundary: a subscription has one clear owner and a
86
86
  well-defined lifecycle
87
87
  ```
88
88
 
89
- **User Workspace Aggregate**:
89
+ **User Workspace Entity**:
90
90
  ```
91
91
  Identity: workspaceId
92
92
  Lifetime: 2-5+ years
93
93
  Boundary: Members added, roles changed, settings updated — for this one workspace
94
94
  Watch for: workspace-level settings and individual member activity
95
- are different concerns — keep member activity in its own stream if
95
+ are different concerns — keep member activity in its own timeline if
96
96
  it needs independent access patterns
97
97
  ```
98
98
 
99
- **Data Collection Aggregate**:
99
+ **Data Collection Entity**:
100
100
  ```
101
101
  Identity: depends on what's actually being tracked as one thing
102
102
  Watch for: this is the domain most likely to hide a Pattern 3
@@ -104,6 +104,6 @@ Watch for: this is the domain most likely to hide a Pattern 3
104
104
  points about the same business entity?"
105
105
  → If NO, the boundary is wrong: split by whatever entity each
106
106
  data point actually belongs to.
107
- → If YES, the boundary is fine even if the stream accumulates a
107
+ → If YES, the boundary is fine even if the timeline accumulates a
108
108
  lot of events — that's a volume question, not a boundary one.
109
109
  ```
@@ -1,25 +1,24 @@
1
- # Stream Boundary Design Patterns
1
+ # Timeline Boundary Design Patterns
2
2
 
3
3
  ## Contents
4
- - Aggregate Boundary Design Patterns (5 patterns with examples)
5
- - Stream Boundary Decision Tree
4
+ - Entity Boundary Design Patterns (5 patterns with examples)
5
+ - Timeline Boundary Decision Tree
6
6
  - Red Flags: Boundary Is Wrong
7
7
  - Tips for Finding the Right Boundary
8
8
 
9
9
  ---
10
10
 
11
- ## Aggregate Boundary Design Patterns
11
+ ## Entity Boundary Design Patterns
12
12
 
13
13
  ### Pattern 1: Single Entity (Most Common)
14
14
 
15
- CORRECT: One aggregate per entity
15
+ CORRECT: One timeline boundary per business entity
16
16
  ```
17
- Aggregate: Order
17
+ Entity: Order
18
18
  Root Identity: orderId (e.g., 'order-123')
19
- Entity: The specific order
20
19
  Lifetime: 1-2 years
21
20
 
22
- Events in stream:
21
+ Events in timeline:
23
22
  1. OrderCreated (2024-01-15)
24
23
  2. OrderLineAdded (2024-01-15)
25
24
  3. OrderLineAdded (2024-01-15)
@@ -30,16 +29,15 @@ Events in stream:
30
29
 
31
30
  Identity Principle: orderId is the natural business key
32
31
  Boundary: Everything about THIS specific order, nothing else
33
- Consistency: Only one order being modified at a time
34
32
  ```
35
33
 
36
34
  ---
37
35
 
38
36
  ### Pattern 2: Composite Entity (Proper Composition)
39
37
 
40
- CORRECT: Aggregate contains related child entities
38
+ CORRECT: Entity contains related child entities
41
39
  ```
42
- Aggregate: Order
40
+ Entity: Order
43
41
  Root Identity: orderId (e.g., 'order-456')
44
42
 
45
43
  Contains related children (same lifetime):
@@ -54,7 +52,7 @@ Contains related children (same lifetime):
54
52
  - PaymentInfo:
55
53
  method: credit_card, amount: $400
56
54
 
57
- Events in stream:
55
+ Events in timeline:
58
56
  1. OrderCreated (customer-789, 3 items)
59
57
  2. OrderLineAdded (item 1)
60
58
  3. OrderLineAdded (item 2)
@@ -65,16 +63,16 @@ Events in stream:
65
63
 
66
64
  Pattern: Small, bounded number of children per parent
67
65
  Lifetime: Parent and all children created/destroyed together
68
- Consistency: All modified as a unit (can't ship without payment, etc.)
66
+ Together: they change as a unit (can't ship without payment, etc.)
69
67
  ```
70
68
 
71
69
  ---
72
70
 
73
71
  ### Pattern 3: Collection (ANTI-PATTERN - DO NOT USE)
74
72
 
75
- WRONG: Treating a collection as an aggregate
73
+ WRONG: Treating a collection as an entity
76
74
  ```
77
- Bad Aggregate: AllOrders
75
+ Bad Entity: AllOrders
78
76
  Root Identity: "all-orders-collection" (artificial, meaningless)
79
77
 
80
78
  Contains: Every order ever created
@@ -87,23 +85,21 @@ Events:
87
85
 
88
86
  Problems with this approach:
89
87
  - No single business identity (it's a collection, not an entity)
90
- - Stream grows unbounded — no natural end to its lifetime
91
- - Can't split or scale
92
- - Every write goes to the same stream (contention)
88
+ - Timeline grows unbounded — no natural end to its lifetime
93
89
 
94
- Solution: Use a projection/read model query instead, not an aggregate
90
+ Solution: Use a projection/read model query instead, not an entity
95
91
  - Query: "GetAllOrdersByCustomer(customer-id)"
96
92
  - Query: "GetOrdersByStatus(status)"
97
- - Rebuild from individual Order streams on-demand
93
+ - Rebuild from individual Order timelines on-demand
98
94
  ```
99
95
 
100
96
  ---
101
97
 
102
98
  ### Pattern 4: Event Log (ANTI-PATTERN - DO NOT USE)
103
99
 
104
- WRONG: Using an aggregate as an event log
100
+ WRONG: Using an entity as an event log
105
101
  ```
106
- Bad Aggregate: SystemLog
102
+ Bad Entity: SystemLog
107
103
  Root Identity: "system-log" (meaningless placeholder)
108
104
 
109
105
  Contains: Every system event imaginable
@@ -119,23 +115,19 @@ Events:
119
115
  Problems with this approach:
120
116
  - No business identity (log of everything)
121
117
  - Events unrelated to each other (mixing user, order, payment, inventory)
122
- - No consistency boundary (user login != order creation)
123
118
  - Can't answer "what's the state of X?" (too mixed)
124
- - Contention: every subsystem writing to the same stream
125
- - Can't replay meaningfully (mixed concerns)
126
119
 
127
- Solution: Use separate event streams per business entity
128
- - Keep dedicated event streams: Order, Payment, Inventory, User
129
- - Use a time-series database for metrics/logs, not a domain stream
120
+ Solution: Use separate event timelines per business entity
121
+ - Keep dedicated event timelines: Order, Payment, Inventory, User
130
122
  ```
131
123
 
132
124
  ---
133
125
 
134
- ### Pattern 5: Historical Aggregate (GOOD - When Needed)
126
+ ### Pattern 5: Historical Entity (GOOD - When Needed)
135
127
 
136
128
  CORRECT: Keep historical data for audit/compliance as its own boundary
137
129
  ```
138
- Aggregate: ArchivedOrder
130
+ Entity: ArchivedOrder
139
131
  Root Identity: archivedOrderId (e.g., 'archived-order-001')
140
132
  Purpose: Regulatory compliance (7-year retention)
141
133
 
@@ -157,8 +149,8 @@ Events:
157
149
 
158
150
  Lifetime: 7 years (regulatory requirement)
159
151
 
160
- Key architectural principles:
161
- - Completely separate from the active Order aggregate
152
+ Key principles:
153
+ - Completely separate from the active Order entity
162
154
  - Active Order is for current business operations
163
155
  - Archived Order is an immutable historical record
164
156
  - Different access patterns, different lifecycles
@@ -166,16 +158,16 @@ Key architectural principles:
166
158
 
167
159
  ---
168
160
 
169
- ## Stream Boundary Decision Tree
161
+ ## Timeline Boundary Decision Tree
170
162
 
171
- Use this to decide whether a stream is bounded around the right business identity:
163
+ Use this to decide whether a timeline is bounded around the right business identity:
172
164
 
173
165
  ```
174
- Does your stream have a natural business identity?
175
- NO → This is not an aggregate, it's a log/report
176
- SOLUTION: Use a read model/projection, not an aggregate
166
+ Does your timeline have a natural business identity?
167
+ NO → This is not an entity, it's a log/report
168
+ SOLUTION: Use a read model/projection, not an entity
177
169
 
178
- YES → Does every event in the stream belong to that one entity's lifecycle?
170
+ YES → Does every event in the timeline belong to that one entity's lifecycle?
179
171
 
180
172
  YES → GOOD: Boundary is correctly scoped to one identity
181
173
 
@@ -191,28 +183,28 @@ Does your stream have a natural business identity?
191
183
 
192
184
  ## Red Flags: Boundary Is Wrong
193
185
 
194
- If your stream exhibits ANY of these, the fix is a narrower or different identity — not a technical workaround:
186
+ If your timeline exhibits ANY of these, the fix is a narrower or different identity — not a technical workaround:
195
187
 
196
188
  ```
197
- Red Flag 1: Stream growing continuously with no natural end
198
- Cause: The stream identity spans an unbounded population, not one entity
189
+ Red Flag 1: Timeline growing continuously with no natural end
190
+ Cause: The timeline identity spans an unbounded population, not one entity
199
191
  Solution: Re-scope to a single business entity's lifecycle
200
- Example: "AllOrders" stream → "Order" per customer order
192
+ Example: "AllOrders" timeline → "Order" per customer order
201
193
 
202
194
  Red Flag 2: Events with no shared business meaning
203
- Cause: Treating a log as an aggregate
204
- Solution: Use a read model/query instead of an aggregate
195
+ Cause: Treating a log as an entity
196
+ Solution: Use a read model/query instead of an entity
205
197
  Example: "SystemMetricRecorded" → use a metrics/observability system
206
198
 
207
- Red Flag 3: Stream contains unrelated entities
208
- Cause: Aggregate boundary is wrong
209
- Solution: Split into separate aggregates
199
+ Red Flag 3: Timeline contains unrelated entities
200
+ Cause: Entity boundary is wrong
201
+ Solution: Split into separate entities
210
202
  Example: "AllOrders" → "Order" per customer
211
203
 
212
- Red Flag 4: Can't explain what single business question the stream answers
213
- Cause: Not a real aggregate — probably a collection or log
204
+ Red Flag 4: Can't explain what single business question the timeline answers
205
+ Cause: Not a real entity — probably a collection or log
214
206
  Solution: Convert to a read model/projection
215
- Example: "SystemEvents" → query specific per-entity streams instead
207
+ Example: "SystemEvents" → query specific per-entity timelines instead
216
208
  ```
217
209
 
218
210
  ---
@@ -221,7 +213,7 @@ Red Flag 4: Can't explain what single business question the stream answers
221
213
 
222
214
  ### 1. Anchor on a Single Business Identity
223
215
  ```
224
- Every stream should answer: "the history of exactly which entity?"
216
+ Every timeline should answer: "the history of exactly which entity?"
225
217
  If the answer is "a category of things" or "everything," the
226
218
  boundary is wrong — it's describing a collection, not an entity.
227
219
  ```
@@ -248,7 +240,7 @@ UserAccount (everything about a user, several unrelated concerns)
248
240
 
249
241
  ### 4. Separate Active From Historical Concerns
250
242
  ```
251
- Keeping everything in one aggregate forever conflates two different
243
+ Keeping everything in one entity forever conflates two different
252
244
  lifecycles: the entity while it's active, and its record afterward.
253
245
  Example:
254
246
  - ActiveSubscription (current state)