diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index cd1e009..48e8b5f 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -42,6 +42,12 @@ "description": "OpenTelemetry skills for naming metrics and spans following OTel Semantic Conventions", "source": "./plugins/trogonstack-otel", "category": "development" + }, + { + "name": "trogonstack-eventmodeling", + "description": "Event Modeling skills for brainstorming, designing, slicing, and validating software systems following the Event Modeling methodology", + "source": "./plugins/trogonstack-eventmodeling", + "category": "development" } ] } diff --git a/.github/release-please-config.json b/.github/release-please-config.json index bc3502e..382b179 100644 --- a/.github/release-please-config.json +++ b/.github/release-please-config.json @@ -41,6 +41,9 @@ }, "plugins/trogonstack-otel": { "component": "trogonstack-otel" + }, + "plugins/trogonstack-eventmodeling": { + "component": "trogonstack-eventmodeling" } }, "plugins": [ diff --git a/.github/release-please-manifest.json b/.github/release-please-manifest.json index a7e86a8..5dbeb21 100644 --- a/.github/release-please-manifest.json +++ b/.github/release-please-manifest.json @@ -4,5 +4,6 @@ "plugins/trogonstack-nats": "0.1.0", "plugins/trogonstack-datadog": "0.2.0", "plugins/trogonstack-ask": "0.1.1", - "plugins/trogonstack-otel": "0.1.0" + "plugins/trogonstack-otel": "0.1.0", + "plugins/trogonstack-eventmodeling": "0.0.1" } diff --git a/plugins/trogonstack-eventmodeling/.claude-plugin/plugin.json b/plugins/trogonstack-eventmodeling/.claude-plugin/plugin.json new file mode 100644 index 0000000..24ec6b9 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/.claude-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "trogonstack-eventmodeling", + "description": "Event Modeling skills for brainstorming, designing, slicing, and validating software systems following the Event Modeling methodology", + "version": "0.0.1", + "author": { + "name": "TrogonStack", + "url": "https://github.com/TrogonStack" + } +} diff --git a/plugins/trogonstack-eventmodeling/README.md b/plugins/trogonstack-eventmodeling/README.md new file mode 100644 index 0000000..3da0998 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/README.md @@ -0,0 +1,7 @@ +# trogonstack-eventmodeling + +Event Modeling skills for brainstorming, designing, slicing, and validating software systems following the Event Modeling methodology. + +```bash +claude plugin install trogonstack-eventmodeling@trogonstack +``` diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-applying-conways-law/SKILL.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-applying-conways-law/SKILL.md new file mode 100644 index 0000000..c804d8a --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-applying-conways-law/SKILL.md @@ -0,0 +1,465 @@ +--- +name: eventmodeling-applying-conways-law +description: >- + Step 6 of Event Modeling - Apply Conway's Law with swimlanes. Organize events + into autonomous system parts that different teams can independently own. Use + after defining inputs/outputs. Do not use for: planning feature slice + implementation order (use eventmodeling-slicing-event-models) or defining + command/read model boundaries (use eventmodeling-designing-event-models). +allowed-tools: AskUserQuestion, Write +--- + +# Applying Conway's Law + +## Interview Phase (Optional) + +**When to Interview**: Skip if the user has already specified: existing team structure, team responsibilities, and autonomous boundary preferences. Interview when team structure is unclear or organizational alignment hasn't been discussed. + +**Interview Strategy**: Understand team organization and decision-making to design system boundaries that teams can own independently. Misalignment here creates bottlenecks and tight coupling later. + +### Critical Questions + +When team structure or boundaries are unclear: + +1. **Team Structure & Ownership** (Impact: Determines how many swimlanes/systems to create) + - Question: "How is your organization structured? (A) Single team owns everything, (B) Separate teams by domain (payments, inventory, etc.), (C) Separate teams by function (backend, frontend, etc.)" + - Why it matters: Team structure directly shapes system boundaries; aligning them reduces coordination overhead + - Follow-up triggers: If (B) → ask what each team owns; if (C) → discuss how to organize by domain instead + +2. **Boundary Autonomy Level** (Impact: Determines coupling and inter-team communication patterns) + - Question: "How much autonomy should each team have? (A) Very high (minimal cross-team communication), (B) Moderate (coordinate via events), (C) Low (frequent coupling acceptable)" + - Why it matters: Highly autonomous teams need clean event-based boundaries; low autonomy might accept more coupling + - Follow-up triggers: If (A) → strict event-driven design; if (C) → discuss why coupling is needed + +3. **External System Integrations** (Impact: Determines if integrations become separate swimlanes or embedded in existing ones) + - Question: "Do you need to integrate with external systems? (A) Payment processor, (B) Shipping provider, (C) Multiple external systems, (D) No external integrations?" + - Why it matters: External systems often become separate swimlanes; knowing which ones matters for boundary design + - Follow-up triggers: For each integration → ask "Who owns the integration—existing team or new team?" + +### Interview Flow + +**Conditional Entry**: +``` +If user has provided: + - Clear team structure (who owns what) + - AND specified desired level of autonomy + - AND identified external integrations + +Then: Skip interview, proceed directly to swimlanes + +Else: Conduct interview +``` + +**Phase 1: Organization Assessment** (Questions 1-2) +- Understand team structure +- Determine autonomy expectations +- Establish boundary philosophy + +**Phase 2: Integration Mapping** (Question 3) +- Identify external systems +- Plan integration boundaries +- Finalize swimlane count + +### Capturing Interview Findings + +Append findings to the project's event modeling file: + +**File**: `.trogonai/interviews/[project-name]/EVENTMODELING.md` + +Use Write tool to add/update this section: + +```markdown +## 6. Conway's Law (eventmodeling-applying-conways-law) + +### Team Structure +- Team 1: [Name] - Owns [domain] +- Team 2: [Name] - Owns [domain] +- Team 3: [Name] - Owns [domain] + +### Autonomy Goals +[High / Moderate / Low] + +### Swimlanes +- [Swimlane 1]: [Team] owns [events] +- [Swimlane 2]: [Team] owns [events] +- [Swimlane 3]: [Team] owns [events] + +### Cross-Team Communication +- [Team A] → [Team B] via [event] +- [Team B] → [Team C] via [event] +``` + +Update Interview Trail: +```markdown +| 6 | eventmodeling-applying-conways-law | [today] | Swimlanes defined, team boundaries confirmed | +``` + +--- + +## Workflow + +Given all events, inputs, and outputs, organize by ownership: + +### 1. Identify System Boundaries +Determine what constitutes a separate system/bounded context: + +``` +System Boundaries: + + + Order Management System + - Owns: Order entity and its lifecycle + - Events: OrderCreated, OrderConfirmed, Cancelled + - Owns: Order state machine + + + + Payment Processing System + - Owns: Payment authorization and processing + - Events: PaymentAuthorized, PaymentFailed + - Owns: Payment state machine + + + + Inventory System + - Owns: Stock levels and reservations + - Events: InventoryReserved, InventoryAllocated + - Owns: Inventory state machine + + + + Fulfillment System + - Owns: Shipments and delivery + - Events: OrderShipped, DeliveryConfirmed + - Owns: Shipment state machine + +``` + +### 2. Create Swimlane Diagram +Visual representation of system boundaries: + +``` + Event Stream Timeline + → + +Order Team OrderCreated OrderConfirmed OrderCancelled + +Payment Team PaymentAuthorized PaymentFailed + +Inventory Team InventoryReserved + +Fulfillment Team OrderShipped DeliveryConfirmed + +Each team owns their swimlane events +Coordination via events crossing swimlanes +``` + +### 3. Map Team Responsibilities +Define what each team owns: + +``` +Order Management Team + Commands they handle: + - CreateOrder + - ConfirmOrder + - CancelOrder + Events they produce: + - OrderCreated + - OrderConfirmed + - OrderCancelled + Read Models they maintain: + - OrderStatusView + - OrderListView + Systems they call: + - Payment System (to confirm payment) + - Inventory System (to check stock) + +Payment Processing Team + Commands they handle: + - AuthorizePayment + - ProcessPayment + - RefundPayment + Events they produce: + - PaymentAuthorized + - PaymentFailed + - PaymentRefunded + Read Models they maintain: + - PaymentStatusView + - TransactionHistory + Systems they depend on: + - Payment Gateway (external) + - Order System (for context) + +Inventory Team + Commands they handle: + - ReserveInventory + - ReleaseReservation + - AllocateStock + Events they produce: + - InventoryReserved + - ReservationReleased + - StockAllocated + Read Models they maintain: + - InventoryLevelView + - ReservationView + Systems they depend on: + - Order System (triggers) + - Warehouse System (stock source) + +Fulfillment Team + Commands they handle: + - CreateShipment + - MarkShipped + - ConfirmDelivery + Events they produce: + - ShipmentCreated + - OrderShipped + - DeliveryConfirmed + Read Models they maintain: + - ShipmentTrackingView + - DeliveryScheduleView + Systems they depend on: + - Inventory System (items to ship) + - Carrier APIs (tracking) +``` + +### 4. Identify Inter-System Communication +Show how systems talk to each other: + +``` +Communication Patterns: + +Order System → Payment System + Order System produces: OrderConfirmed event + Payment System consumes: OrderConfirmed + Payment System reacts: Issues AuthorizePayment command + Payment System produces: PaymentAuthorized event + +Order System → Inventory System + Order System produces: PaymentAuthorized event (indirectly) + Inventory System consumes: PaymentAuthorized + Inventory System reacts: Issues ReserveInventory command + Inventory System produces: InventoryReserved event + +Inventory System → Fulfillment System + Inventory System produces: InventoryReserved event + Fulfillment System consumes: InventoryReserved + Fulfillment System reacts: Issues CreateShipment command + Fulfillment System produces: OrderShipped event +``` + +### 5. Define System Interfaces +What each system exposes: + +``` +Order System Interface + Commands it accepts: + - CreateOrder (from UI) + - ConfirmOrder (from UI) + - CancelOrder (from UI or Processors) + Events it produces: + - OrderCreated + - OrderConfirmed + - OrderCancelled + Read Models it provides: + - OrderStatusView + - OrderListView + +Payment System Interface + Commands it accepts: + - AuthorizePayment (from Payment Processor/Order System) + - ProcessPayment (from Order System) + Events it produces: + - PaymentAuthorized + - PaymentFailed + - PaymentProcessed + +Inventory System Interface + Commands it accepts: + - ReserveInventory (triggered by PaymentAuthorized event) + Events it produces: + - InventoryReserved + - InventoryFailed +``` + +### 6. Identify Processors vs Systems +Show where automation lives: + +``` +Processors (autonomous automation): + +1. PaymentProcessor + Triggered by: OrderConfirmed event + Logic: Calls external payment gateway + Produces: AuthorizePayment command + Lives in: Payment System + +2. InventoryProcessor + Triggered by: PaymentAuthorized event + Logic: Checks stock, reserves inventory + Produces: ReserveInventory command + Lives in: Inventory System + +3. FulfillmentProcessor + Triggered by: InventoryReserved event + Logic: Creates shipment records + Produces: CreateShipment command + Lives in: Fulfillment System + +4. NotificationProcessor + Triggered by: OrderCreated, OrderConfirmed, OrderShipped events + Logic: Sends emails/SMS + Produces: No commands (info-only) + Lives in: Notification System (cross-cutting) +``` + +## Output Format + +Present as: + +```markdown +# System Organization: [Domain Name] + +## System Boundaries + +### System: Order Management +- **Team**: Order Team +- **Responsibilities**: Create, confirm, cancel orders +- **Commands**: CreateOrder, ConfirmOrder, CancelOrder +- **Events Produced**: OrderCreated, OrderConfirmed, OrderCancelled +- **Events Consumed**: PaymentAuthorized, InventoryReserved (for state updates) +- **Read Models**: OrderStatusView, OrderListView +- **Scope**: One stream type (Order) + +### System: Payment Processing +- **Team**: Payment Team +- **Responsibilities**: Authorize and process payments +- **Commands**: AuthorizePayment, ProcessPayment, RefundPayment +- **Events Produced**: PaymentAuthorized, PaymentFailed, PaymentRefunded +- **Events Consumed**: OrderConfirmed (from Order System) +- **Read Models**: PaymentStatusView, TransactionHistory +- **Dependencies**: External payment gateway +- **Scope**: One stream type (Payment) + +### System: Inventory Management +- **Team**: Inventory Team +- **Responsibilities**: Stock management and reservations +- **Commands**: ReserveInventory, ReleaseReservation, AllocateStock +- **Events Produced**: InventoryReserved, ReservationReleased, StockAllocated +- **Events Consumed**: PaymentAuthorized (from Payment System) +- **Read Models**: InventoryLevelView, ReservationView +- **Dependencies**: Warehouse system +- **Scope**: One stream type (InventoryReservation) + +[Continue for each system] + +--- + +## Event Flow Across System Boundaries + +### Flow: Order → Payment → Inventory → Fulfillment + +``` +Time → + +Order System +OrderCreated → +OrderConfirmed → + (triggers) +Payment System +PaymentAuthorized → + (triggers) +Inventory System +InventoryReserved → + (triggers) +Fulfillment System +OrderShipped +DeliveryConfirmed +``` + +--- + +## Team Responsibilities Matrix + +| Team | Creates Commands | Produces Events | Owns Read Models | +|------|-----------------|-----------------|------------------| +| Order | CreateOrder, ConfirmOrder | OrderCreated, OrderConfirmed | OrderStatusView | +| Payment | AuthorizePayment | PaymentAuthorized | PaymentStatusView | +| Inventory | ReserveInventory | InventoryReserved | InventoryLevelView | +| Fulfillment | CreateShipment | OrderShipped | ShipmentTrackingView | + +--- + +## Inter-System Communication + +### Order → Payment +- Trigger: OrderConfirmed event +- Action: Payment System listens via Processor +- Result: AuthorizePayment command issued + +### Payment → Inventory +- Trigger: PaymentAuthorized event +- Action: Inventory System listens via Processor +- Result: ReserveInventory command issued + +[Document all communication patterns] + +--- + +## Dependencies + +### External Systems + +| System | Owns | Called By | Purpose | +|--------|------|-----------|---------| +| Payment Gateway | Payment provider | Payment System | Authorization | +| Warehouse | Inventory source | Inventory System | Stock info | +| Carrier API | Shipping | Fulfillment System | Tracking | + +--- + +## Independent Development + +Each system can: +- Develop independently +- Use different tech stacks +- Scale independently +- Deploy independently +- Own their events +- Maintain their read models + +Coordination via: +- Events (async messaging) +- Processors (listen and react) +- Read models (shared views) +``` + +## Quality Checklist + +- [ ] Each system has clear ownership +- [ ] System boundaries are well-defined +- [ ] Events map to systems +- [ ] Commands map to teams +- [ ] Cross-system communication is documented +- [ ] No circular dependencies +- [ ] Each team has independent scope +- [ ] Processors are explicitly assigned +- [ ] External systems identified +- [ ] System interfaces are clear + +## Conway's Law Principle + +**System architecture mirrors team structure**: +- Separate teams → Separate systems +- Each system owns events +- Communication through events +- Independent development possible +- Aligns with org chart + +## Key Benefits + +1. **Team Independence**: Each team owns their domain +2. **Clear Ownership**: No confusion about responsibility +3. **Scalable Architecture**: Systems can evolve independently +4. **Event-Driven**: Natural communication via events +5. **Deployment**: Each team deploys their system diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-brainstorming-events/SKILL.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-brainstorming-events/SKILL.md new file mode 100644 index 0000000..c84f4e5 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-brainstorming-events/SKILL.md @@ -0,0 +1,406 @@ +--- +name: eventmodeling-brainstorming-events +description: >- + Step 1 of Event Modeling - Brainstorm all domain events from requirements. + Extract every state-changing event the system could have. Use when starting + event modeling from requirements or a new domain. Do not use for: arranging + events in sequence (use eventmodeling-plotting-events), designing commands + or read models (use eventmodeling-designing-event-models), or when a complete + event list already exists. +allowed-tools: AskUserQuestion, Write +--- + +# Brainstorming Events + +## Interview Phase (Optional) + +**When to Interview**: Skip if the user has provided detailed, well-documented requirements (written user stories, feature specs, business rules). Interview when requirements are vague, incomplete, or when domain expertise is uncertain. + +**Interview Strategy**: Ensure requirements are complete and team understands domain well enough to brainstorm comprehensively. Identify hidden complexity areas upfront. + +### Critical Questions + +When requirements need clarification: + +1. **Requirements Completeness** (Impact: Determines if brainstorm is likely to be exhaustive) + - Question: "How complete are your requirements? Do you have: (A) Written user stories/specs, (B) Documented business rules, (C) Rough list, (D) Just verbal descriptions?" + - Why it matters: Incomplete requirements cause missed events; complete requirements enable comprehensive brainstorm + - Follow-up triggers: If (C) or (D) → probe for missing scenarios; if rules aren't documented → ask team to state them explicitly + +2. **Domain Expertise & Familiarity** (Impact: Shapes who should participate and what guidance is needed) + - Question: "Who understands this domain best? (A) Product/Domain expert leading brainstorm, (B) Engineering team figuring it out, (C) Mix of roles" + - Why it matters: Domain expert participation dramatically improves event completeness; solo engineering leads to gaps + - Follow-up triggers: If (B) → recommend inviting domain expert; if (C) → ask how decisions will be made + +3. **Known Complexity Areas** (Impact: Determines where to focus brainstorming effort and depth) + - Question: "Are there specific areas known to be complex or error-prone? (e.g., payment processing, state transitions, business rules)" + - Why it matters: Complex areas often have hidden events; identifying them upfront ensures they're covered + - Follow-up triggers: For each complex area → ask "What are the edge cases? What can go wrong?" + +4. **Explicit Business Rules & Constraints** (Impact: Ensures no implicit assumptions; may reveal missing events) + - Question: "What are critical business rules that govern this domain? (e.g., 'orders can only be cancelled within 24 hours', 'payments must be authorized before confirmation')" + - Why it matters: Business rules often generate specific events; documenting them prevents overlooking state changes + - Follow-up triggers: For each rule → ask "When this rule is violated, what event signals that?" + +### Interview Flow + +**Conditional Entry**: +```text +If user has provided: + - Written requirements or user stories (not just verbal) + - AND documented business rules or constraints + - AND named domain experts who will participate + +Then: Skip interview, proceed directly to brainstorming + +Else: Conduct interview +``` + +**Phase 1: Requirements Assessment** (Questions 1-2) +- Gauge requirements completeness +- Confirm domain expertise available +- Adjust brainstorm scope accordingly + +**Phase 2: Complexity Mapping** (Questions 3-4) +- Identify areas needing deep exploration +- Document rules that may generate events +- Plan brainstorm focus areas + +### Capturing Interview Findings + +Append findings to the project's event modeling file: + +**File**: `.trogonai/interviews/[project-name]/EVENTMODELING.md` + +Use Write tool to add/update this section: + +```markdown +## 2. Brainstormed Events (eventmodeling-brainstorming-events) + +### Requirements Assessment +[From Q1: Written requirements? Documented rules?] + +### Domain Expertise +[From Q2: Who understands domain? Available for participation?] + +### Role Catalog +#### Human Roles +- [Role 1]: [Description] → Actions: [list] +- [Role 2]: [Description] → Actions: [list] +#### System Actors +- [Actor 1]: [Description] → Triggers: [list] + +### Event Streams (Stream Roots) +- Stream: [Name] (Identity: [id field]) + - Events: [Event1, Event2, Event3] + - State changes: [State transitions] + +### Business Rules & Constraints +[From Q3 & Q4] +- Rule 1: [Statement] → [Events it generates] +- Rule 2: [Statement] → [Events it generates] +- Constraint 1: [Limitation] + +### Brainstorming Focus Areas +- [Focus area 1] +- [Focus area 2] +``` + +Update Interview Trail: +```markdown +| 2 | eventmodeling-brainstorming-events | [today] | Event streams, business rules, constraints | +``` + +This section feeds into subsequent steps (plotting, storyboarding, etc.) + +--- + +## Workshop Facilitation Guide + +**Setting**: This is a collaborative brainstorming workshop. The facilitator guides participants to envision the system and extract events rapidly. + +### The Brainstorming Flow + +**Phase 1: Understand Goals** (5-10 min) +- Someone explains project goals +- What problem are we solving? +- Who are the users? +- What are key outcomes? + +**Phase 2: Free Brainstorm** (15-20 min) +Facilitator asks: +> "What events could happen in this system? When something changes, what event occurs? Put down ANY event you think of." + +Participants call out events (sticky notes or digital cards): +```text +"Customer places order" +"Order confirmed" +"Payment received" +"Inventory updated" +"Order shipped" +"Delivery confirmed" +"Return requested" +"Refund issued" +``` + +**Phase 3: Gentle Filtering** (10-15 min) +Facilitator introduces state-changing concept gently: + +```text +Facilitator: "Now let's think about these events. An event is something that +CHANGED THE STATE of the system. It's something important that happened that +others need to know about. + +Let me ask: Does 'Customer viewed the catalog' change anything? +Participants: "Well... no, they just looked." +Facilitator: "Right, so it's not an event. But if they SELECTED an item + from catalog, that changes what's in their cart, so that's + a state change. Call that 'ItemAddedToCart'." + +Does 'Payment received' change something? +Participants: "Yes! Order goes from confirmed to paid." +Facilitator: "Exactly! That's an event—state changed." +``` + +**Key points to clarify**: +- "Customer logged in" → Maybe not state-changing (unless we track logins) +- "Customer created account" → State-changing event +- "System checked inventory" → Internal action, not state-changing +- "Inventory reserved" → State-changing event +- "Email sent" → Notification, not state-changing (unless we track email history) +- "Notification requested" → Could be state-changing if we track preferences + +### Tips for Facilitators + +**Make it conversational**: +- Don't say: "You identified a non-state-changing event" +- Say: "Interesting! Does that actually change anything in the system?" + +**Use examples from their world**: +- If e-commerce: "Like if someone just browsed but didn't buy?" +- If banking: "Like if they just checked balance but didn't withdraw?" + +**Don't be rigid**: +- If unsure whether something is state-changing, include it and refine later +- Some events seem minor now but matter in implementation +- Better to capture everything than miss important events + +**Capture the "why"**: +- Don't just list events, capture context +- Why would this event matter? +- Who cares about it? (Other systems, views, business rules) + +## Workflow + +When given domain requirements, perform the following analysis: + +### 1. Identify User Roles & Actors (MANDATORY) + +Before brainstorming events, define **who** interacts with the system. Every event model needs an explicit role catalog — without it, downstream steps (storyboarding, commands, scenarios) lack clarity on who does what. + +Identify all human roles and system actors: +- **Human roles**: Customer, Seller, Admin, Support Agent, Reviewer, etc. +- **System actors**: Payment Gateway, Inventory System, Notification Service, Scheduler, etc. + +For each role/actor, document: +- **Name**: Use domain language (e.g., "Seller" not "User Type B") +- **Description**: What this role does in the domain (1-2 sentences) +- **Key actions**: What state changes can this role initiate? +- **Permissions boundary**: What can this role NOT do? + +Present as a Role Catalog: + +```text +## Role Catalog + +### Human Roles + +1. **Customer** - Description: End user who browses, purchases, and tracks orders + - Key actions: Create order, confirm order, cancel order, submit review + - Cannot: Manage inventory, process refunds, respond to reviews as seller + +2. **Seller** - Description: Merchant who lists products and fulfills orders + - Key actions: List product, confirm stock, respond to reviews, update pricing + - Cannot: Place orders, approve own reviews, process payments + +3. **Support Agent** - Description: Internal staff handling escalations and manual overrides + - Key actions: Override order status, issue refunds, flag reviews + - Cannot: Place orders on behalf of customers (unless impersonating) + +### System Actors + +1. **Payment Gateway** (external) + - Triggers: Payment authorization, payment failure, refund confirmation + - Communication: Webhooks + +2. **Inventory System** (internal) + - Triggers: Reserve inventory, release reservation + - Communication: Event-driven +``` + +This catalog feeds directly into: +- **Step 3 (Storyboarding)**: One swimlane per human role +- **Step 4 (Inputs)**: Every command attributed to a specific role/actor +- **Step 7 (Scenarios)**: Scenarios reference roles by name +- **Step 8 (Completeness)**: Verify every role has at least one command path + +### 2. Identify Event Streams (Stream Roots) +Identify the main entities that will have event streams. These are NOT DDD aggregates—they're simply the logical roots of events: +- User/Account +- Order +- Payment +- Shipment +- etc. + +For each stream root, note: +- Name (use domain language, not technical terms) +- Identity key (what uniquely identifies instances: orderId, paymentId, customerId, etc.) +- What commands will affect it (we'll define state needs per command, not upfront) + +### 3. Identify Business Processes +Map out critical workflows: +- What steps does a user go through? +- What are the decision points? +- Where do systems integrate? + +### 4. Extract State Changes +For each process, identify what state changes occur: +- Customer places order → Order created +- Payment processed → Order confirmed +- Item shipped → Order status changed + +These become your domain events. + +### 5. Document Business Rules & Constraints +- What rules govern state transitions? +- What validations must pass? +- What are the invariants? + +Examples: +- "Order can only be shipped if payment is confirmed" +- "Inventory must be reserved before order confirmation" +- "Customer can only cancel within 24 hours" + +### 6. Create Analysis Document + +Present findings in this structure (include facilitation notes for future workshops): + +```markdown +## Workshop Notes + +**Participants**: [List roles: PO, Dev, QA, Domain Expert] +**Duration**: [Time spent] +**Key facilitation moments**: [What helped clarify understanding?] + +--- + +# Domain Analysis: [Domain Name] + +## Role Catalog + +### Human Roles +1. **[Role Name]**: [Description] + - Key actions: [What this role can do] + - Cannot: [Permission boundaries] + +### System Actors +1. **[Actor Name]** ([internal/external]): [Description] + - Triggers: [What events/commands it initiates] + - Communication: [Webhooks / Event-driven / API] + +## Event Streams (Stream Roots) +List each stream root and its identity: +- **Stream**: Review (Identity: reviewId) +- **Stream**: SellerResponse (Identity: responseId) +- **Stream**: Seller (Identity: sellerId) + +Note: These are just the logical groupings of events. The STATE needed for each command will be determined later—not all stream attributes are needed for all commands. + +## Business Processes +1. **Process Name**: Description + - Actor: Who initiates? + - Steps: 1. → 2. → 3. + - Outcomes: What changes? + +## Identified State Changes (Potential Events) +- [Stream] [Verb]: When? Why? (Use past tense: "ReviewPublished", "SellerResponseAdded") + +## Business Rules & Constraints +- Rule 1: Condition and consequence +- Rule 2: Constraint description + +## Questions for Domain Expert +- Any gaps in understanding? +- Unclear processes? +``` + +## Output Format +Present analysis in a clear markdown structure that can be directly used by the eventmodeling-designing-event-models skill. + +## Core Architectural Rule + + **NEVER use DDD Aggregate pattern for state design** Every command handler must have its own minimal state projection derived from events. This is non-negotiable. + +```text + ANTI-PATTERN (Do NOT do this): +OrderAggregate { orderId, customerId, items[], total, status, paymentId, address, shippedAt, cancelledAt, ... } +Used by: ConfirmOrder, ShipOrder, CancelOrder, ApproveReturn +Problem: Loads unused data, couples unrelated commands, violates minimal state principle + + CORRECT PATTERN: +ConfirmOrderState { status, orderId } +ShipOrderState { status, orderId, paymentId } +CancelOrderState { status, orderId, createdAt } +Each command loads ONLY what it needs. +``` + +## Key Principles +- Use **domain language**, not technical terms +- Focus on **what** happens, not **how** it's implemented +- Identify **state changes** as events, not actions (gently!) +- Document **constraints** and **rules** +- Be **specific** with examples from the requirements +- **Collaborative Process**: This is a group brainstorm, not a solo analysis +- **Rapid Iteration**: Capture quickly, refine later +- **Gentle Filtering**: Introduce "state-changing events" concept conversationally, not as rigid rule +- **Event Sourcing Mindset**: Think in terms of immutable events and stream roots, NOT DDD aggregates. The stream root is just a logical grouping of events; state is minimal and command-specific. +- **Defer State Design**: Don't list all entity attributes upfront. In the model designer step, we'll define minimal state projections needed for each specific command. +- **Command State Isolation**: Each command handler has its own state shape. Different commands = different state interfaces. + +## Best Practices for Requirements Analysis + +### 1. Be Specific with Requirements +Provide concrete examples and clear scope: +- "Handle orders" +- "Orders have items, pricing, delivery address, and can be cancelled within 24 hours" + +### 2. Use Domain Language +Use terms your business understands, not technical jargon: +- "obj1 references obj2" +- "Customer places Order with Products" + +### 3. Document Constraints Explicitly +Make implicit rules explicit: +- "Process payments" +- "Authorize payment before marking order confirmed; refund if shipment fails" + +### 4. Verify Role Catalog Completeness +Cross-check that the Role Catalog (from Step 1) covers all actors referenced in events and processes: +- "Orders can be created" (by whom?) +- "Customers can create orders; sellers can confirm stock; system can cancel if payment fails" + +### 5. Cover Edge Cases +Include error and boundary conditions: +- "What happens if payment is declined?" +- "Can an order be modified after shipping starts?" +- "What triggers order cancellation?" + +## Quality Checklist + +- [ ] Every event is past tense and names a completed state change (e.g., `OrderPlaced`, not `PlaceOrder`) +- [ ] Role Catalog lists every actor (human roles and system processors) with distinct responsibilities +- [ ] Each event can be traced back to a specific actor in the Role Catalog +- [ ] No CRUD events (`UserUpdated`, `RecordDeleted`) — events describe business moments, not database operations +- [ ] All known error and boundary conditions have corresponding events +- [ ] Events group into at least one recognizable business process flow +- [ ] No overlapping event semantics — two events don't mean the same thing diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-brainstorming-events/references/facilitating-event-modeling-workshops.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-brainstorming-events/references/facilitating-event-modeling-workshops.md new file mode 100644 index 0000000..0dd6b09 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-brainstorming-events/references/facilitating-event-modeling-workshops.md @@ -0,0 +1,626 @@ +# Facilitating Event Modeling Workshops + +## Overview + +Event Modeling is fundamentally a collaborative workshop process. This guide helps facilitators run efficient, effective workshops across all 7 steps. + +## Pre-Workshop Preparation + +### 1. Select Participants + +**Required Roles**: +- **Product Owner/Domain Expert**: Business rules, priorities, constraints +- **Developers** (2-3): Technical feasibility, implementation concerns +- **QA/Tester** (1-2): Test coverage, edge cases +- **Facilitator** (1): Keeps pace, ensures shared understanding + +**Optional Participants**: +- **UX Designer**: User workflows, interface considerations +- **Security Lead**: Sensitive data handling, compliance +- **Operations**: Deployment, monitoring, scaling +- **Customer/User**: Real-world perspective (for workshops with actual users) + +**Group Size**: 5-8 people is ideal +- Too small: Miss perspectives +- Too large: Hard to facilitate + +### 2. Pre-Workshop Communication + +Send to participants before workshop: +``` +Subject: Event Modeling Workshop - [Domain Name] + +Hi team, + +We're running an Event Modeling workshop to design the [Domain] system. + +Date: [Date] +Duration: [Hours] +Location: [Physical/Virtual] + +Please prepare by thinking about: + - What workflows happen in this system? + - What events could occur? + - What's important about state changes? + - Questions you have about requirements + +No prior Event Modeling experience needed! + +Looking forward to seeing you there. +``` + +### 3. Prepare Workspace + +**Physical Workshop**: +``` +Setup: + - Large whiteboard or wall space (8+ feet wide) + - Sticky notes (multiple colors for events, commands, views) + - Markers (bold colors) + - Timer visible + - Cameras for documentation + +Layout: + - Stand-up around board + - Facilitator at board + - Everyone can see and contribute +``` + +**Virtual Workshop**: +``` +Tools: + - Miro, Figma, or similar + - Video conference (Zoom, Teams, etc.) + - Shared document (for notes) + +Setup: + - Everyone can see canvas + - All can create/edit + - Recording enabled (for reference) + - Chat open for side discussions +``` + +### 4. Create Templates + +Prepare sticky note templates or digital shapes: + +``` +Physical sticky notes: +[Green] Event: ________________ + +[Blue] Command: ________________ + +[Orange] View: ________________ + +Virtual shapes: +Same colors with text fields +``` + +## Workshop Facilitation by Step + +### Step 1: Brainstorming Events (15-20 minutes) + +**Objective**: Identify all domain events (state changes) + +**Facilitation Flow**: + +1. **Set Context** (2 min) + ``` + "We're going to envision what this system does. Imagine it's running + for years—what events happen? What important state changes? + + An event is something that changed the state. Not just something + that happened, but something that MATTERS because it changed things. + + Everyone write down any events you think of." + ``` + +2. **Free Brainstorm** (8-10 min) + - Participants call out events + - You write on board or digital canvas + - No filtering yet! Capture everything + - Encourage "What about..." questions + - Example responses: + - "Customer placed order" → Write: "OrderCreated" + - "Order was confirmed" → Write: "OrderConfirmed" + - "What about customer viewed page?" → "Let's capture it for now, we'll refine" + +3. **Gentle Filtering** (5-7 min) + ``` + "Now let's think about these. An event is something that actually + changed the state. Let me ask about some: + + 'Customer viewed catalog' - did this change anything? + Person: Not really... + You: Right, viewing doesn't change anything. But if they SELECTED + an item, that changes their cart. That's 'ItemAddedToCart'. + + 'System checked inventory' - did this change system state? + Person: No, it's internal... + You: Exactly, internal checks don't count. But when we ACTUALLY + reserved inventory, that's a state change: 'InventoryReserved'. + ``` + +4. **Capture Insights** - Add notes on WHY events matter + - Identify stream roots (Order, Payment, Review, etc.) + - Document any questions for domain expert + +**Timing Guide**: +- Tight groups: 12-15 min +- Complex domains: 20-25 min +- Always watch time—keep moving + +### Step 2: Plotting Events (Timeline) + +**Objective**: Order events into a timeline (process flow) + +**Facilitation Flow**: + +1. **Establish Order** (5 min) + ``` + "Let's put these events in order. What happens first?" + + Guide conversation: + "Before we can confirm an order, what must happen?" + → "Order must be created first" + + "So the sequence is?" + → Lead to: OrderCreated → OrderConfirmed + ``` + +2. **Handle Branches** (5 min) + ``` + "Can different things happen from here?" + + "What if payment fails?" + → "PaymentFailed event" + → This creates branching paths + + Draw branching clearly: + OrderConfirmed + → PaymentAuthorized → (success path) + → PaymentFailed → (failure path) + ``` + +3. **Identify Parallel Flows** (5 min) + ``` + "Do these happen at the same time or one after another?" + + Example: + "Once payment is authorized, what happens?" + → "Inventory reserved" + → "Email sent" + → Can these happen in parallel? Usually yes! + ``` + +**Don't get stuck** on exact timing—the point is the logical flow. + +### Step 3: Storyboarding (UI Mockups) + +**Objective**: Visualize what users see + +**Facilitation Flow**: + +1. **Pick First Screen** (2 min) + ``` + "Let's think about the UI. What's the first screen the user sees?" + → "Order entry form" + + "Who draws?" + → Can be anyone, or facilitator + ``` + +2. **Draw and Label** (5 min) + ``` + Draw on board: + + Order Entry Form + + Customer: [_______] + Items: [___] [___] + [Submit] + + + Label each field: + Customer ← from CreateOrder command + Items ← user selection + ``` + +3. **Trace Data** (3 min) + ``` + "Where does this data go?" + → "Into the event" + → "Then what screen shows next?" + → Draw: Confirmation screen with same data + ``` + +4. **Identify Missing** (2 min) + ``` + "Can we see everything we need on this screen?" + → If missing: "We'll need to add that to the event" + → Add to list of clarifications + ``` + +**Time per screen**: 5-7 minutes (don't perfect, iterate) + +### Step 4: Identifying Inputs (Commands) + +**Objective**: Map user actions to commands + +**Facilitation Flow**: + +1. **Extract from Storyboards** (5 min) + ``` + "Looking at the screens, what are users doing?" + → "Clicking Submit" → "CreateOrder command" + → "Selecting payment" → "ConfirmOrder command" + + Write commands clearly + ``` + +2. **Identify Processor Inputs** (5 min) + ``` + "What does the system do automatically?" + → "Check payment gateway" → "AuthorizePayment command" + → "Reserve inventory" → "ReserveInventory command" + + Mark these as [ Automation] + ``` + +3. **Specify Data** (5 min) + ``` + "For each command, what data does it need?" + + CreateOrder needs: + - customerId (from form/session) + - items (from form selection) + - shippingAddress (from form) + + Write this clearly + ``` + +4. **Validation Questions** (5 min) + ``` + "What validation must pass?" + + CreateOrder: + - Customer must exist + - Items must not be empty + - Address must be complete + + Write these as business rules + ``` + +### Step 5: Identifying Outputs (Events & Views) + +**Objective**: Specify events and read models + +**Facilitation Flow**: + +1. **Events from Commands** (5 min) + ``` + "For each command, what event happens?" + + CreateOrder → OrderCreated (what fields?) + Specify exactly what fields: + - orderId (generated) + - customerId (from command) + - items (from command) + - total (calculated) + ``` + +2. **Read Models** (5 min) + ``` + "What views do users need?" + → "Order status view" + → "Order list view" + → "Order detail view" + + "What data in each?" + → Status view: All order details + → List view: Summary only + ``` + +3. **Event → View Mapping** (5 min) + ``` + "OrderCreated → Status View shows:" + - orderId + - items + - total + - status=Draft + + "OrderConfirmed → Status View updates:" + - status=Confirmed + - confirmedAt timestamp + ``` + +### Step 6: Apply Conway's Law (System Boundaries) + +**Objective**: Identify systems and responsibilities + +**Facilitation Flow**: + +1. **Ask the Question** (2 min) + ``` + "Who does what?" + + "Is payment something WE do or does an external system?" + → If external: PaymentGateway system + ``` + +2. **Draw Boundaries** (5 min) + ``` + Visually separate: + + Our System: + Order service + Inventory service + Notification service + + External: + Payment gateway + Fulfillment provider + ``` + +3. **Clarify Ownership** (5 min) + ``` + "Which system owns each event?" + + OrderCreated → Our Order system + PaymentAuthorized → Payment system (external) or our bridge? + InventoryReserved → Our Inventory system + ``` + +4. **Identify Team Structure** (5 min) + ``` + "Who builds what?" + + → Team A: Order service + → Team B: Payment processor + → Team C: Inventory management + + Boundaries = team boundaries (Conway's Law) + ``` + +### Step 7: Elaborating Scenarios (Given-When-Then) + +**Objective**: Specify behavior with Gherkin format + +**Facilitation Flow**: + +1. **Happy Path First** (8 min) + ``` + "Let's write the success case. What's the normal flow?" + + Scenario: Create order successfully + Given: Customer exists, products exist + When: Customer creates order with items + Then: OrderCreated event produced, status=Draft + + Write on board/doc with team reviewing + ``` + +2. **Failure Cases** (8 min) + ``` + "What can go wrong?" + + Scenario: Reject with invalid customer + Given: Customer ID doesn't exist + When: CreateOrder attempted + Then: Command rejected, no event + + → Quick, obvious failures + → Don't overthink + ``` + +3. **State Validation** (5 min) + ``` + "What if the order is in wrong state?" + + Scenario: Can't confirm already-confirmed order + Given: Order already in Confirmed state + When: Confirm attempted again + Then: Rejected + ``` + +4. **Alternative Paths** (5 min) + ``` + "Any different ways this could work?" + + Scenario: Can't confirm order with no payment method + Scenario: Can retry if payment fails + + Capture alternatives quickly + ``` + +**Time**: 5-7 min per command/view, don't perfect + +## Facilitation Techniques + +### Handling Different Personalities + +**Quiet developers**: +- Direct question: "Alex, what do you think about this?" +- Don't embarrass, just engage +- "Good point, add that" + +**Dominating voices**: +- Politely redirect: "Thanks, let me get input from others" +- "Interesting, let's capture that and check with the team" +- Keep energy high so they feel heard + +**Skeptics**: +- Take seriously: "What's your concern?" +- Don't dismiss: "That's valid, let's think about it" +- Sometimes reveal real issues + +**Idea-generators**: +- Capture everything: "Good ideas, adding them" +- Sort later: Don't slow momentum +- "We'll come back to that" + +### Keeping Energy & Pace + +``` +Good pacing: + - 5-7 min per item (not 20 min perfecting one detail) + - Move quickly between steps + - Regular breaks (every 45-60 min) + - Stand, don't sit (keeps energy up) + +Warning signs of bad pacing: + - People checking phones + - Someone talking endlessly + - "Um... let me think..." (too hard) + - Fatigue setting in + +Recovery: + - Take 10-min break + - Change activity (switch from drawing to writing) + - Refocus on goals: "We're 60% done, here's what we still need" +``` + +### Dealing with Disagreement + +``` +Situation: Two people disagree on event + +Option A: "Both are valid? Can we combine?" +Option B: "Let's see if later steps clarify?" +Option C: "Let's note both and revisit" + +Don't: Get stuck on one issue +Do: Keep moving, document decision + +Decision-making: + 1. If there's a clear right answer → Use it + 2. If reasonable people disagree → Document both, move on + 3. If it doesn't matter now → Defer to implementation team +``` + +## Remote Workshop Adaptations + +### Virtual vs. Physical + +**Advantages of virtual**: +- Can record (perfect reference) +- Can save digital artifacts +- Easier for distributed teams +- Can use video recordings in onboarding + +**Challenges**: +- Less natural interaction +- Harder to facilitate drawing +- Zoom fatigue +- Side conversations harder + +**Adaptations**: +``` +1. Shorter sessions (90 min instead of 4 hours) +2. More breaks (10 min every 30 min) +3. Structured input (everyone adds ideas before discussing) +4. Clearer roles (one person drawing, one taking notes) +5. Recording on (for those who can't attend live) +6. Async follow-up (give people time to digest) +``` + +## Post-Workshop + +### Immediate (Same Day) + +1. **Capture on Document** - Photograph/screenshot all artifacts + - Type up handwritten notes + - Create digital version of diagram + +2. **Share with Team** - Everyone gets copy + - Add notes: "Why did we choose this?" + - Link to recordings + +3. **Identify Gaps** - Note unclear items + - Schedule quick follow-up if needed + +### Follow-Up (1-2 Days) + +1. **Distribute Summary** - What we covered + - Key decisions + - Outstanding questions + +2. **Request Feedback** - Any clarifications needed? + - Anything we missed? + - Concerns? + +3. **Next Steps** - Next workshop scheduled? + - Who's doing design/implementation? + - When do we start? + +## Multi-Day Workshop Schedule + +For large or complex projects: + +``` +Day 1 (Steps 1-3): 4 hours + - 9am-10am: Brainstorming events (Step 1) + - 10am-11am: Plotting timeline (Step 2) + - Break: 11am-11:15am + - 11:15am-1pm: Storyboarding (Step 3) + - Lunch: 1pm-2pm + +Day 2 (Steps 4-7): 4 hours + - 9am-10am: Identifying inputs (Step 4) + - 10am-11am: Identifying outputs (Step 5) + - Break: 11am-11:15am + - 11:15am-12:30pm: System boundaries (Step 6) + - 12:30pm-1pm: Scenario planning (Step 7 intro) + - Lunch/break + +Day 3 (Scenarios & Polish): 3 hours + - 9am-12pm: Elaborate scenarios (Step 7, detailed) + - Document findings + - Plan next steps +``` + +## Facilitation Checklist + +### Before Workshop +- [ ] Invitations sent 1 week prior +- [ ] Right people confirmed attending +- [ ] Room/tech tested +- [ ] Materials prepared (sticky notes, markers, templates) +- [ ] Facilitator briefing done +- [ ] Objectives clear to all + +### During Workshop +- [ ] Started on time +- [ ] Explained purpose and format +- [ ] Each step has clear objective +- [ ] Captured everything (photo/digital) +- [ ] Timing maintained (didn't get stuck) +- [ ] Everyone participated +- [ ] Energy and engagement stayed high +- [ ] Decisions documented +- [ ] Ended on time + +### After Workshop +- [ ] Artifacts digitized and shared +- [ ] Summary created +- [ ] Gaps identified +- [ ] Feedback requested +- [ ] Next steps scheduled +- [ ] Team has clear deliverables + +## Success Indicators + +**Good workshop**: +- Everyone participated +- Decisions were made and documented +- Artifacts created and shared +- Team understands the model +- Clear next steps +- Energy was good throughout + +**Needs improvement**: +- Some people quiet the whole time +- Unclear what we decided +- No clear artifacts +- "Are we building this in Java or Python?" (forgotten basics) +- People left tired/frustrated diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-checking-completeness/SKILL.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-checking-completeness/SKILL.md new file mode 100644 index 0000000..c9cd3da --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-checking-completeness/SKILL.md @@ -0,0 +1,561 @@ +--- +name: eventmodeling-checking-completeness +description: >- + Step 8 of Event Modeling - Completeness Check. Verify every field has origin + and destination. Ensure complete event model before code generation. Use after + all scenarios defined. Do not use for: architectural validation against event sourcing + principles (use eventmodeling-validating-event-models) or elaborating + Given-When-Then specs (use eventmodeling-elaborating-scenarios). +allowed-tools: Write +--- + +# Checking Completeness + +## Workflow + +Perform comprehensive completeness check: + +### 1. Field Origin & Destination Matrix +For every field in every event, verify source and use: + +```text +Event: OrderCreated + +Field: orderId +Origin: Generated by system (UUID) +Destinations: + OrderConfirmed event (references) + OrderStatusView (displays) + OrderListView (displays) + OrderShipped event (references) +Status: Complete + +Field: customerId +Origin: CreateOrder command (from UI) +Destinations: + OrderStatusView (displays) + OrderListView (displays) + Inventory System (knows who ordered) +Status: Complete + +Field: items[] +Origin: CreateOrder command (user selects) +Destinations: + OrderStatusView (displays) + Inventory System (what to reserve) + Fulfillment System (what to ship) +Status: Complete + +Field: total +Origin: Calculated from items[] and unit prices +Destinations: + OrderStatusView (displays) + OrderListView (displays) + PaymentSystem (amount to charge) + Accounting (for reconciliation) +Status: Complete + +Field: shippingAddress +Origin: CreateOrder command (user enters) +Destinations: + OrderStatusView (displays) + Fulfillment System (where to ship) + Carrier (delivery address) +Status: Complete + +Field: createdAt +Origin: System timestamp when event created +Destinations: + OrderStatusView (displays) + OrderListView (displays) + Metrics (average order age) +Status: Complete +``` + +### 2. Check All Commands +Verify every command input is captured: + +```text +Command: CreateOrder +Input: customerId, items[], shippingAddress + customerId → OrderCreated.customerId + items[] → OrderCreated.items + shippingAddress → OrderCreated.shippingAddress +Status: All inputs captured + +Command: ConfirmOrder +Input: orderId, paymentMethod + orderId → OrderConfirmed.orderId (implicit) + paymentMethod → OrderConfirmed.paymentMethod +Status: All inputs captured + +Command: AuthorizePayment +Input: orderId, paymentId, authCode + orderId → PaymentAuthorized.orderId (implicit) + paymentId → PaymentAuthorized.paymentId + authCode → PaymentAuthorized.authCode +Status: All inputs captured +``` + +### 3. Check All Read Models +Verify read models have all needed data: + +```text +ReadModel: OrderStatusView +Needs to display: + orderId ← OrderCreated + customerId ← OrderCreated + status ← OrderConfirmed, PaymentAuthorized, etc. + items ← OrderCreated + total ← OrderCreated + createdAt ← OrderCreated + confirmedAt ← OrderConfirmed + paymentId ← PaymentAuthorized + paymentMethod ← OrderConfirmed + shipmentId ← OrderShipped + trackingNumber ← OrderShipped +Status: All fields sourced + +ReadModel: OrderListView +Needs to display: + orderId ← OrderCreated + customerId ← OrderCreated + total ← OrderCreated + status ← OrderConfirmed, OrderCancelled, etc. + createdAt ← OrderCreated +Status: All fields sourced +``` + +### 4. Check Event Stream Completeness +Verify no "missing" events: + +```text +Scenario: Order from creation to delivery + +Timeline: +1. OrderCreated (from CreateOrder command) +2. OrderConfirmed (from ConfirmOrder command) +3. PaymentAuthorized (from AuthorizePayment processor command) +4. InventoryReserved (from ReserveInventory processor command) +5. OrderShipped (from CreateShipment processor command) +6. DeliveryConfirmed (from MarkDelivered processor command) + +Missing events? None identified + +Alternative paths: +- OrderCancelled (can happen after OrderCreated or OrderConfirmed) +- PaymentFailed (can happen during PaymentAuthorized) +- RefundInitiated (can happen after PaymentFailed or OrderCancelled) + +Status: All paths covered +``` + +### 5. Check System Boundaries +Verify each system owns events: + +```text +Order System +Events: OrderCreated, OrderConfirmed, OrderCancelled +Processor: None (triggers other systems) +Status: Clean ownership + +Payment System +Events: PaymentAuthorized, PaymentFailed, PaymentRefunded +Processor: PaymentAuthorizer (listens to OrderConfirmed) +Status: Clean ownership + +Inventory System +Events: InventoryReserved, InventoryReleased +Processor: InventoryReserver (listens to PaymentAuthorized) +Status: Clean ownership + +Fulfillment System +Events: OrderShipped, DeliveryConfirmed +Processor: ShipmentCreator (listens to InventoryReserved) +Status: Clean ownership + +Notification System +Events: None (no persistence, info-only) +Processor: Notifier (listens to all events) +Status: Cross-cutting concern +``` + +### 6. Define Workflow Step Contracts +Each workflow step is a contract between the previous step and the next. Document preconditions and postconditions: + +```text +Workflow Step 1: CreateOrder (Step Owns: Order Creation) + +Preconditions (what must exist before this step): + - Customer must exist + - Products must exist in catalog + - User must be authenticated + +Postconditions (what exists after this step): + - OrderCreated event exists + - Event contains: orderId, customerId, items, total, shippingAddress, createdAt + - Order state: Draft + +Contract: Any system can assume if these postconditions are true, + the order has been properly created through this step. + +--- Workflow Step 2: ConfirmOrder (Step Owns: Order Confirmation) + +Preconditions (depends on Step 1 postcondition): + - OrderCreated event must exist ( from Step 1 contract) + - Order must be in Draft state + - Customer must select payment method + +Postconditions (what exists after this step): + - OrderConfirmed event exists + - Event contains: orderId, paymentMethod, confirmedAt + - Order state: Confirmed + +Contract: Any system can assume if these postconditions are true, + the order has been properly confirmed. + +--- Workflow Step 3: AuthorizePayment (Step Owns: Payment Authorization) + +Preconditions (depends on Step 2 postcondition): + - OrderConfirmed event must exist ( from Step 2 contract) + - Order must be in Confirmed state + - Payment method must be valid + +Postconditions (what exists after this step): + - PaymentAuthorized event exists + - Event contains: paymentId, authCode, amount + - Payment state: Authorized + +Contract: Once this postcondition is true, next steps can proceed + without re-checking payment (trust the contract). +``` + +**Why Contracts Matter for Parallel Development**: +```text +Team A: Works on CreateOrder (Step 1) + → Knows postcondition: OrderCreated with specific fields + → Knows other teams depend on this + +Team B: Works on ConfirmOrder (Step 2) + → Can start immediately, doesn't wait for Step 1 implementation + → Just needs to know: "I expect OrderCreated event with these fields" + → Writes tests that mock the OrderCreated event + → When Step 1 is done, tests pass immediately + +Team C: Works on AuthorizePayment (Step 3) + → Can start immediately + → Expects: OrderConfirmed event with these fields + → When Step 2 is done, tests pass immediately + +Result: 3 teams working in parallel instead of waiting sequentially! +``` + +### 7. Check Role Coverage + +Verify that the **Role Catalog** (from Step 1) is fully exercised: + +```text +Role Coverage Matrix: + +Human Roles: +Customer + Has swimlane in storyboard (Step 3) + Commands attributed: CreateOrder, ConfirmOrder, CancelOrder + Read models consumed: OrderStatusView, OrderListView + Scenarios reference this role + Status: Complete + +Seller + Has swimlane in storyboard (Step 3) + Commands attributed: RespondToReview, ConfirmStock + Read models consumed: SellerDashboardView + Scenarios reference this role + Status: Complete + +Support Agent + Has swimlane in storyboard (Step 3) + Commands attributed: OverrideOrderStatus + No read models identified + No scenarios reference this role + Status: Incomplete — needs read models and scenarios + +System Actors: +Payment Gateway + Commands attributed: AuthorizePayment, FailPayment + Status: Complete + +Inventory System + Commands attributed: ReserveInventory + Status: Complete +``` + +**Validation rules**: +- Every human role MUST have at least one command +- Every human role MUST have at least one read model/view +- Every human role MUST appear in at least one scenario (Step 7) +- Every system actor MUST have at least one command or processor trigger + +If a role has zero commands → either the role is unnecessary (remove from catalog) or commands are missing (add them). + +### 8. Check Field Traceability +Matrix of all fields origin → destination: + +```markdown +| Field | Event | Command | Read Model | Processor | +|-------|-------|---------|-----------|-----------| +| orderId | OrderCreated | - | All views | All | +| customerId | OrderCreated | CreateOrder | OrderStatusView | - | +| items | OrderCreated | CreateOrder | List/Status views | Inventory | +| total | OrderCreated | - | List/Status views | - | +| paymentId | PaymentAuthorized | AuthorizePayment | StatusView | Inventory | +| shipmentId | OrderShipped | CreateShipment | StatusView | Notification | +| trackingNumber | OrderShipped | - | TrackingView | Notification | + +Status: All fields traceable +``` + +### 9. Identify Gaps +Document any missing pieces: + +```text +Analysis: Are there any missing fields? + - Estimated delivery date? + → Need to add to OrderShipped event + → Can be calculated from carrier + → Add to ShipmentTrackingView + + - Cancellation reason? + → Already in OrderCancelled event + + - Payment failure reason? + → Already in PaymentFailed event + + - Refund status? + → Need to track in RefundInitiated event + → Add to PaymentStatusView + +Actions taken: + Add estimatedDelivery to OrderShipped + Add refundStatus to PaymentStatusView + Add refundInitiatedAt to OrderStatusView +``` + +## Output Format + +Present as: + +```markdown +# Completeness Check: [Domain Name] + +## Workflow Step Contracts + +### Step 1: CreateOrder + +**Preconditions**: +- Customer exists in system +- Products exist in catalog + +**Postconditions**: +- OrderCreated event exists with fields: [list] +- Order state is Draft + +**Teams that depend on this contract**: [All downstream teams] + +--- + +### Step 2: ConfirmOrder + +**Preconditions** (depends on Step 1): +- OrderCreated event exists +- Order in Draft state + +**Postconditions**: +- OrderConfirmed event exists with fields: [list] +- Order state is Confirmed + +--- [Continue for each workflow step] + +--- + +## Field Traceability Matrix + +### Events + +| Event | Field | Origin | Destinations | Status | +|-------|-------|--------|-------------|--------| +| OrderCreated | orderId | System | ConfirmOrder, Views | | +| OrderCreated | customerId | CreateOrder | All views | | +| OrderCreated | items | CreateOrder | Inventory, Views | | +| OrderCreated | total | Calculated | Views, Payment | | +| OrderConfirmed | paymentId | AuthorizePayment | Views, Accounting | | +| OrderShipped | trackingNumber | Carrier | TrackingView | | + +--- + +## System Ownership Verification + +### Order System +- Events owned: OrderCreated, OrderConfirmed, OrderCancelled +- Completeness: All order lifecycle events present + +### Payment System +- Events owned: PaymentAuthorized, PaymentFailed, PaymentRefunded +- Completeness: All payment states covered + +--- + +## Command → Event Verification + +| Command | Input | Event | Captured | +|---------|-------|-------|----------| +| CreateOrder | customerId, items, address | OrderCreated | | +| ConfirmOrder | paymentMethod | OrderConfirmed | | +| AuthorizePayment | paymentId, authCode | PaymentAuthorized | | + +--- + +## Read Model Coverage + +### OrderStatusView +- All relevant event data included +- All user display needs met +- All processor decision fields present + +### OrderListView +- Summary fields captured +- Filtering/sorting fields present +- Linked to OrderStatusView for details + +--- + +## Role Coverage + +### Human Roles + +| Role | Swimlane | Commands | Read Models | Scenarios | Status | +|------|----------|----------|-------------|-----------|--------| +| Customer | | CreateOrder, ConfirmOrder, CancelOrder | OrderStatusView, OrderListView | 5 scenarios | Complete | +| Seller | | RespondToReview | SellerDashboardView | 2 scenarios | Complete | +| Support Agent | | OverrideOrderStatus | None | None | Incomplete | + +### System Actors + +| Actor | Commands/Triggers | Status | +|-------|-------------------|--------| +| Payment Gateway | AuthorizePayment, FailPayment | | +| Inventory System | ReserveInventory | | + +--- + +## Gap Analysis + +### Issues Found +1. Estimated delivery date missing + - Fix: Add to OrderShipped event + - Type: string (ISO 8601 date) + - Source: Calculated from carrier API + - Status: Will add in next iteration + +2. Refund tracking incomplete + - Fix: Add RefundInitiated event timestamp + - Fix: Add refund status to PaymentStatusView + - Status: Will add in next iteration + +### No Critical Gaps +- All events properly sourced +- All command inputs captured +- All read models have data +- Event flow complete +- System boundaries clear + +--- + +## Readiness Assessment + +**Overall Completeness**: 95% + +**Blockers**: None + +**Ready for Code Generation**: YES + +**Minor Improvements**: +- Add estimated delivery date (non-blocking) +- Enhance refund tracking (non-blocking) + +**Recommendation**: Proceed to code generation phase. +``` + +## Quality Checklist + +- [ ] Every field has clear origin +- [ ] Every field has identified destinations +- [ ] All command inputs are captured +- [ ] All read models have sources +- [ ] Event flow is complete +- [ ] No events are missing +- [ ] System boundaries are clear +- [ ] Alternative paths covered +- [ ] Error paths documented +- [ ] Processors are identified +- [ ] No circular dependencies +- [ ] All scenarios have data sources +- [ ] **Workflow step contracts defined for each step** +- [ ] **Each contract has explicit preconditions** +- [ ] **Each contract has explicit postconditions** +- [ ] **Dependencies between steps documented** +- [ ] **Teams can work in parallel based on contracts** +- [ ] **Every human role from the Role Catalog has at least one command** +- [ ] **Every human role has at least one read model/view** +- [ ] **Every human role appears in at least one scenario** +- [ ] **Every system actor has at least one command or processor trigger** +- [ ] **No role in the catalog is orphaned (zero usage across the model)** + +### CRITICAL: Event vs Read Model Validation +- [ ] **Reviewed every "calculated event"**: Is it a domain fact or pure calculation? +- [ ] **No aggregation events**: Totals, averages, counts are read models, NOT events +- [ ] **Recalculated state identified**: If a value changes multiple times, it's a read model +- [ ] **Processor outputs categorized**: + - [ ] Facts → Events (e.g., PaymentAuthorized) + - [ ] Calculations → Read Models (e.g., SellerRatingCalculated) + - [ ] Notifications → No event/model (info-only) +- [ ] **History tracking correct**: Read models track history in `history[]`, not as separate events + +## Completeness Criteria + +The model is **complete** when: + Every event field has a source (command or system) + Every command input becomes event/state data + Every read model field has event source + All state transitions are covered + Alternative flows are documented + Error conditions are handled + System boundaries are clear + No "magic" data appears without source + Data flows logically end-to-end + All stakeholder needs are met + **Events are facts (immutable domain actions)** **Read models are projections (derived/calculated state)** **No calculated events exist** (aggregations/totals are read models) + **Every role in the Role Catalog is exercised** (has commands, views, and scenarios) + +## Common Incompleteness Issues + +| Issue | Example | Fix | +|-------|---------|-----| +| Missing event | "No event for failure" | Add failure event | +| Orphaned data | "Field in view, not in event" | Add field to event | +| Circular flow | "A needs B, B needs A" | Redesign boundary | +| Missing field | "View needs date, event has none" | Add field to event | +| Unclear origin | "Where does this come from?" | Trace back to source | +| **Calculated event** | SellerRatingCalculated, InventoryTotal | **Move to read model** (recalculated state is projection) | + +## Reference Documentation + +- **[Security Analysis with Event Modeling](references/security-analysis-with-event-modeling.md)** — How to use the field traceability matrix and data flow visibility from this step to conduct a systematic security review: identifying trust boundaries, privilege escalation paths, and data exposure risks across the event model. + +## Next Steps + +If completeness check passes: +→ Proceed to code generation + +If gaps found: +→ Return to appropriate step to fix +→ Re-run completeness check diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-checking-completeness/references/security-analysis-with-event-modeling.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-checking-completeness/references/security-analysis-with-event-modeling.md new file mode 100644 index 0000000..db39ba6 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-checking-completeness/references/security-analysis-with-event-modeling.md @@ -0,0 +1,430 @@ +# Security Analysis with Event Modeling + +## Overview + +Event Modeling makes security analysis uniquely transparent. By visualizing exactly where data flows through the system and which boundaries data crosses, security reviews become systematic instead of ad-hoc. + +The article notes: + +> "With an event model, the solution shows exactly where, and equally importantly, when sensitive data crosses boundaries. With traditional audits, the number of interviews with staff was time consuming and at risk of missing important areas." + +## The Security Transparency Problem + +### Traditional Security Review + +``` +Traditional approach: + 1. Meet with team members + 2. Ask: "Where does sensitive data go?" + 3. Answers vary, incomplete, hard to verify + 4. Risk: Miss important data flows + 5. Cost: Many interviews, hours of analysis + 6. Result: Uncertainty about coverage + +Problems: + - Different people have different mental models + - Data flows not written down + - Discoverable only through interviews + - Risk of missing critical flows + - Hard to audit compliance +``` + +### Event Modeling Security Review + +``` +Event Modeling approach: + 1. Review event model (visual, written) + 2. Identify which fields are sensitive + 3. Trace sensitive data flow + 4. Identify boundaries it crosses + 5. Specify encryption/protection requirements + 6. Verify against compliance + 7. Result: Complete, auditable, visual + +Advantages: + - All flows visible in one place + - Data marked as sensitive/public + - Boundaries explicit + - Changes trackable + - Compliance verification straightforward +``` + +## Identifying Sensitive Data + +### Data Classification + +``` +In your event model, classify all fields: + + Highly Sensitive: + - Social Security Number + - Credit card number + - Bank account number + - Authentication tokens + - Passwords + - Medical records + - Biometric data + +🟡 Sensitive: + - Email address + - Phone number + - Home address + - Date of birth + - IP address + - Transaction history + - Browsing history + +🟢 Public: + - Product names + - Prices + - Order status + - Timestamps + - User preferences (non-personal) +``` + +### Marking Data in Events + +``` +Event: CreateOrder + +Fields and sensitivity: + orderId: 🟢 Public (needed for display) + customerId: 🟡 Sensitive (personal identifier) + items: 🟢 Public (what they ordered) + total: 🟢 Public (order amount) + shippingAddress: 🟡 Sensitive (personal location) + billingAddress: 🟡 Sensitive (personal location) + paymentTokenId: Highly Sensitive (payment reference) + customerEmail: 🟡 Sensitive (personal contact) + customerPhone: 🟡 Sensitive (personal contact) + +--- Event: PaymentAuthorized + +Fields and sensitivity: + orderId: 🟢 Public + paymentId: 🟡 Sensitive (transaction reference) + authCode: Highly Sensitive (can be used for disputes/refunds) + amount: 🟢 Public + cardLast4: 🟡 Sensitive (partial card info) + timestamp: 🟢 Public +``` + +## Tracing Data Flow + +### Sensitive Data Journey + +``` +Event: CreateOrder + customerId: 🟡 Sensitive + Stays in: Order stream (encrypted) + Sent to: InventorySystem (internal) + Sent to: NotificationSystem (internal) + Displayed in: OrderStatusView (only to owner) + + shippingAddress: 🟡 Sensitive + Stays in: Order stream (encrypted) + Sent to: FulfillmentSystem (external!) + Risk: Data leaves our domain + Mitigation: Use separate address service + Displayed in: OrderStatusView (only to owner) + + customerEmail: 🟡 Sensitive + Stays in: Order stream (encrypted) + Sent to: NotificationSystem (internal) + Risk: Email stored in logs? + Mitigation: Hash email, use secure templates + Not displayed in UI + +--- Event: PaymentAuthorized + authCode: Highly Sensitive + Received from: External PaymentGateway + Stored in: Payment stream (encrypted, HSM-backed) + Accessed by: RefundProcessor (needs authCode) + Risk: Exposure = Unauthorized refunds + Mitigation: Encrypt at rest, TLS in transit, access logging + + cardLast4: 🟡 Sensitive + Received from: External PaymentGateway + Stored in: Payment stream (encrypted) + Displayed in: OrderStatusView (last 4 digits OK, not full card) +``` + +### Create a Sensitivity Matrix + +``` +| Event | Field | Sensitivity | Stored Where | Sent To | Display | Protection | +|-------|-------|------------|-------------|---------|---------|-----------| +| CreateOrder | customerId | 🟡 | Order stream | Inventory, Notify | OrderView | Encrypted, TLS | +| CreateOrder | shippingAddress | 🟡 | Order stream | Fulfillment | OrderView | Encrypted, TLS | +| PaymentAuthorized | authCode | | Payment stream | Refund processor | Hidden | Encrypted, HSM, Access log | +| PaymentAuthorized | cardLast4 | 🟡 | Payment stream | Notification | Last 4 only | Encrypted, TLS | +| OrderStatusView | customerId | 🟡 | Read model | - | Owner only | Encrypted, Access control | +``` + +## Identifying Boundary Crossings + +### System Boundaries + +``` +Your System Boundary: + + + Your Core System + + Order Service + Stores: customerId, orderId, items + + Payment Service (internal) + Stores: authCode, cardLast4 + + Notification Service (internal) + Stores: customerEmail + + + + BOUNDARY CROSSING + ↓ ↓ ↓ + + Fulfillment Payment Analytics + (External) Gateway (Our + (External) external + Receives: vendor) + shipping Receives: + address Amount Receives: + 🟡 Token customer + behavior + 🟡 + + +Boundary Crossings: + 1. shippingAddress → Fulfillment (🟡 Sensitive) + Risk: Data in external system + Mitigation: Encrypted channel, data minimization + + 2. authCode → PaymentGateway ( Highly sensitive in both directions) + Risk: Highest - payment fraud + Mitigation: PCI compliance, TLS only, never in logs + + 3. Customer behavior → Analytics (🟡 Sensitive) + Risk: Behavioral tracking, profiling + Mitigation: Anonymization, consent, data minimization +``` + +## Compliance Requirements + +### Map Events to Compliance + +``` +Regulation: GDPR (Europe) + +Sensitive data: customerId, email, phone, address + +GDPR Requirements: + 1. "Right to be forgotten": Delete all customer data on request + Implementation: Create CustomerDataDeleted event + Scope: Wipe from Order stream, Payment stream, all views + + 2. "Data minimization": Only collect necessary data + Review: Which fields in events are actually needed? + Action: Remove unused fields + + 3. "Explicit consent": Collect consent for non-essential data + Review: Which fields require consent? + Events: CustomerConsentGiven, CustomerConsentWithdrawn + + 4. "Data transfer restrictions": Can't send to certain countries + Boundary: PaymentGateway location (check compliance) + Boundary: Analytics vendor location (check compliance) + +--- Regulation: PCI DSS (Payment Card Industry) + +Sensitive data: authCode, cardLast4, cardNumber (if stored) + +PCI Requirements: + 1. "Encrypt at rest": authCode must be encrypted in storage + Check: Event store encryption enabled? + + 2. "Encrypt in transit": Data sent via TLS only + Check: All processors use HTTPS? + + 3. "No full card numbers": Never store full credit card + Check: Event has only cardLast4? + + 4. "Access logging": Log all access to authCode + Action: Add processor access logs for PaymentAuthorized events + + 5. "Regular testing": Security audits + Plan: Quarterly review of this matrix +``` + +## Creating Security Controls + +### Control Framework + +``` +For each sensitive field, define controls: + +Field: authCode ( Highly Sensitive) + +Sensitivity: 4/4 (highest) + +Data classification: Payment authorization + +Controls: + Encryption at Rest + Type: AES-256 + Location: Event store + Key: Hardware Security Module (HSM) + Rotation: Annual + + Encryption in Transit + Type: TLS 1.3 + Required: All access to authCode + Pinning: Certificate pinning to payment gateway + + Access Control + Who can read: RefundProcessor, RefundHandler + Who can write: PaymentProcessor (external system) + Logging: All reads logged with timestamp, user, purpose + + Audit Trail + Tracked: Every access to authCode + Retention: 7 years (compliance requirement) + Review: Monthly audit of access logs + + Purpose Limitation + Can be used for: Refund processing only + Cannot be: Displayed in UI, sent in emails, logged + + Expiration + Retention: 6 months after transaction + Action: Automatic purge after retention period + +--- Field: shippingAddress (🟡 Sensitive) + +Sensitivity: 2/4 (medium) + +Data classification: Personal location + +Controls: + Encryption at Rest + Type: AES-256 + Key: Application-level encryption + + Encryption in Transit + Type: TLS 1.3 + + Access Control + Who can read: FulfillmentService, OrderService, OrderOwner + Who can write: CreateOrder command, UpdateOrder command + + Audit Trail + Tracked: Access to addresses, modifications + Retention: 2 years + + Purpose Limitation + Can be used for: Order fulfillment, customer service + Cannot be: Sold to third parties, used for marketing (without consent) + + Anonymization for Analytics + When sending to Analytics: Geocode to region level only + Never: Individual addresses to analytics +``` + +## Audit Trail & Compliance + +### Compliance Checklist + +``` +Security Review Checklist (using Event Model) + + Sensitive data identified + - All fields marked with sensitivity level + - Classification agreed with security team + + Data flows mapped + - Every sensitive field: origin, journey, destination + - Boundary crossings identified + + Protections specified + - Encryption requirements defined + - Access controls documented + - Audit logging configured + + Compliance verified + - GDPR checks: Consent, Right to delete, Data minimization + - PCI checks: Encryption, Access control, No full cards + - SOC 2 checks: Access logging, Audit trail + + Controls implemented + - Encryption: Enabled + - TLS: All channels + - Access logging: All sensitive data + - Monitoring: Alerts on unauthorized access + + Testing scheduled + - Penetration test: Quarterly + - Access control audit: Monthly + - Encryption key rotation: Annual +``` + +## Examples: Real Audit + +### Before Event Modeling + +``` +Security auditor asks: + "Where does customer email go?" + +Team A: "It's in the order service database" +Team B: "It goes to the notification system" +Team C: "Not sure, might be in logs?" +Team D: "I think analytics uses it?" + +Auditor result: "Insufficient documentation, cannot verify compliance" +Recommendation: "Complete audit required" (expensive, time-consuming) +``` + +### After Event Modeling + +``` +Security auditor: + 1. Reviews event model + 2. Looks up: Field "customerEmail" in CreateOrder event + 3. Sees: 🟡 Sensitive (marked in schema) + 4. Traces flow: + Stored in: Order stream (encrypted, detailed in control matrix) + Sent to: NotificationService (internal, over TLS) + Stored in: Notification logs (PII removal configured) + Not sent to: Analytics (marketing consent required, marked in schema) + Deleted when: CustomerDeletionRequested event issued + 5. Verifies: All controls documented and implemented + 6. Result: "Compliant, controls adequate" + +Time: 2 hours instead of 2 days +Confidence: High (all flows documented) +``` + +## Key Principles + +1. **Visibility**: Mark sensitivity on every field +2. **Traceability**: Track sensitive data through all boundaries +3. **Compliance**: Map regulations to data flows +4. **Control**: Define protection for each sensitivity level +5. **Audit**: Document controls and verify implementation +6. **Change Tracking**: When event model changes, security review updates +7. **Testing**: Include security in compliance testing + +## Summary + +Event Modeling transforms security from: +- Interviews and guesswork +- Risk of missing flows +- Hard to verify compliance +- Expensive audits + +To: +- Visual, documented data flows +- Complete traceability +- Systematic compliance verification +- Auditable, repeatable process diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-designing-event-models/SKILL.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-designing-event-models/SKILL.md new file mode 100644 index 0000000..afaa782 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-designing-event-models/SKILL.md @@ -0,0 +1,499 @@ +--- +name: eventmodeling-designing-event-models +description: >- + Designs event-sourced domain models. Maps business processes to immutable + events and state projections. Events are the source of truth; state is + derived from events for command validation. Use when designing event streaming + architectures from domain analysis. Do not use for: brainstorming events from + scratch (use eventmodeling-brainstorming-events), optimizing stream sizing + or snapshotting (use eventmodeling-optimizing-stream-design), or translating + external system events (use eventmodeling-translating-external-events). +allowed-tools: AskUserQuestion, Write +--- + +# Designing Event Models + +## Interview Phase (Optional) + +**When to Interview**: Skip if the user has specified: stream identity strategy, command-specific state needs, and read model requirements. Interview when stream boundaries or state design are unclear. + +**Interview Strategy**: Establish stream identity and per-command state boundaries before designing. Ambiguous boundaries are the primary cause of the DDD aggregate anti-pattern appearing in event-sourced models. + +### Critical Questions + +1. **Stream Identity** (Impact: Determines how events are grouped into streams) + - Question: "What's the entity that owns events? (e.g., orderId, reviewId, customerId) What's the lifetime? Single transaction or years?" + - Why it matters: Wrong stream identity causes design problems; correct identity keeps streams appropriately scoped + - Follow-up triggers: If multiple candidates → ask "Which entity's identity would you use to load events for a single command decision?" + +2. **Minimal State vs Bundled State** (Impact: Prevents DDD aggregate anti-pattern) + - Question: "Will different commands need different state? Or does every command need the same full state?" + - Why it matters: Each command should have minimal, command-specific state—not bundled DDD aggregates + - Follow-up triggers: If "same full state" → walk through two commands and ask what each actually reads during validation + +### Interview Flow + +**Conditional Entry**: +```text +If user has provided: + - Stream identity (which entity ID anchors the stream) + - AND at least two commands with explicitly different state needs documented + - AND read model requirements (what queries the UI or processors make) + +Then: Skip interview, proceed directly to design + +Else: Conduct interview +``` + +**Phase 1: Stream Boundaries** (Question 1) +- Confirm which entity anchors the stream +- Establish stream lifetime expectations +- Identify whether multiple candidate roots exist and resolve them + +**Phase 2: State Design** (Question 2) +- Confirm per-command state isolation +- Identify whether DDD aggregate thinking is present upfront +- Establish minimal state shapes for at least two commands + +### Capturing Interview Findings + +Append findings to the project's event modeling file: + +**File**: `.trogonai/interviews/[project-name]/EVENTMODELING.md` + +Use Write tool to add/update this section: + +```markdown +## Designing Event Models (eventmodeling-designing-event-models) + +### Stream Identity +[From Q1: Which entity? What identity key? Lifetime?] + +### Per-Command State Decisions +[From Q2: Which commands need different state? Initial minimal state shapes?] + +### Design Decisions +- Stream root: [entity name] identified by [id field] +- State isolation: [confirmed / DDD pattern caught and corrected] +``` + +Update Interview Trail: +```markdown +| Design | eventmodeling-designing-event-models | Done | Stream identity, per-command state shapes | +``` + +--- + +## Core Architectural Rule + + **NEVER use a "DDD Aggregate Root" (bundled state) for command validation** Every command handler has its own minimal state projection. What DDD calls an "aggregate root" is actually a **read model**, not command-validation state. + +```text + WRONG: Using DDD Aggregate as command state +OrderAggregate { orderId, customerId, items[], total, status, paymentId, address, shippedAt, cancelledAt, ... } + ↑ This is a READ MODEL, not command state + ↓ NEVER use for command validation + handleConfirmOrder(OrderAggregate) + handleShipOrder(OrderAggregate) + handleCancelOrder(OrderAggregate) + + CORRECT: Minimal state per command +ConfirmOrderState { status, orderId } + ↓ + handleConfirmOrder(ConfirmOrderState) + +ShipOrderState { status, orderId, paymentId } + ↓ + handleShipOrder(ShipOrderState) + +CancelOrderState { status, orderId, createdAt } + ↓ + handleCancelOrder(CancelOrderState) + +OrderSummaryView { orderId, customerId, items[], total, status, paymentId, ... } + ↑ This is for UI queries, NOT command validation +``` + +## Purpose +Converts domain analysis into the event sourcing architecture pattern: + +**UI/Processor** → **Command** → [Command State Read Model] → **Event** → **Query Read Models** - **UI/Processor**: Entry points that trigger intent +- **Command**: Intent data (can be rejected) +- **Stream Root**: Logical grouping of immutable events (NOT a DDD aggregate bundle) +- **Command State Read Model**: Minimal projection derived from events, optimized for this specific command's validation. Each command gets its own read model interface. Different commands = different shapes. (Categorized as "Command State" for semantic clarity) +- **Event**: Result of successful command (immutable fact: command data + implicit context) +- **Query Read Models**: Rich projections of events optimized for UI/Processor queries. Separate from command state. (Categorized as "Query Models" for semantic clarity) + +## Workflow + +Given a domain analysis, design a complete event-sourced model: + +### 1. Design Event Streams +Events are the immutable source of truth. Each stream holds facts about one entity: +- **Stream Name**: Entity type + identity (Order:order-123) +- **Event Type**: What changed? (past tense: Created, Confirmed, Shipped) +- **Event Data**: Combines command input + implicit stream state facts +- **Causality**: Triggered by which command? + +Format: +```text +Stream: Order:order-123 + +Events (chronological): +1. OrderCreated + Triggered by: CreateOrder command + Data: customerId, items[], total, shippingAddress, createdAt + (from command: customerId, items[], shippingAddress) + (implicit: total calculated from items) + +2. OrderConfirmed + Triggered by: ConfirmOrder command + Data: paymentId, confirmedAt + (from command: paymentId) + (implicit: orderId from stream, previous status verified) + +3. OrderShipped + Triggered by: ShipOrder command + Data: shipmentId, shippedAt + (from command: shipmentId) + (implicit: orderId, confirmed status verified) +``` + +**Key Rules**: +- Events are **immutable facts** from successful commands +- Event data = command input + implicit stream state context +- Stream identity is explicit (Order:order-123) +- Event order matters for state reconstruction +- Never modify or delete events +- Events only exist if command succeeded + +### 2. Design Command State Read Models (Minimal Per-Command) + + **Critical Rule: Each command must have its own read model (command state). NEVER share read models between commands.** **Naming Convention (for Automation)**: +- `[CommandName]State` = Implemented command state read model +- `[CommandName]StateToDo` = Planned command state read model (marked for implementation) + +Examples: +- `PublishReviewState` = implemented +- `EditReviewStateToDo` = planned, needs implementation +- `SellerRespondState` = implemented + +**Semantic Categorization**: These are read models, but categorized as "Command State" based on their purpose (command validation, not UI queries). + +Command state read models are **derived** from events and **minimal**: +- Read only events needed for a specific command's decision +- Build state by replaying only relevant events +- **ENFORCEMENT**: Different commands = different read model interfaces. Period. +- Each command handler defines what state projection it needs (and ONLY what it needs) +- Projection can be regenerated from events at any time + +Example for Order stream with separate command state read model for EACH command: + +```text +## ConfirmOrder Command (IMPLEMENTED) +State interface: ConfirmOrderState { status, orderId } +Builder: buildConfirmOrderState(events) +Naming: [CommandName]State = implemented +- OrderCreated event → Set status='Draft' +- OrderConfirmed event → Set status='Confirmed' +(SKIP: items, total, shipping - not needed for this command) + +## ShipOrder Command (IMPLEMENTED) +State interface: ShipOrderState { status, orderId, paymentId } +Builder: buildShipOrderState(events) +Naming: [CommandName]State = implemented +(DIFFERENT from ConfirmOrderState) +- OrderCreated event → (skip) +- OrderConfirmed event → Set status='Confirmed', set paymentId +- OrderShipped event → Set status='Shipped' + +## CancelOrder Command (PLANNED - NOT IMPLEMENTED) +State interface: CancelOrderStateToDo { status, orderId, createdAt } +Builder: buildCancelOrderStateToDo(events) [STUB - TODO] +Naming: [CommandName]StateToDo = planned, needs implementation +(DIFFERENT from both above) +- OrderCreated event → Set status='Draft', createdAt +- OrderCancelled event → Set status='Cancelled' +``` + +**Enforcement Rule**: +- ConfirmOrderState used ONLY by handleConfirmOrder +- ShipOrderState used ONLY by handleShipOrder +- NEVER share state between commands +- NEVER create a single "OrderState" for all Order commands + +This is **NOT** a full aggregate state bundle—it's minimal, command-specific state access. + +### 3. Design Commands +Commands are **intent data from UI or Processor**: +- Represent what user/system wants to do +- Can be rejected (validation failure) +- Only UI or Processor can issue commands +- Load current stream state for validation +- Produce events if valid, or reject if invalid + +Format: +```text +Command: ConfirmOrder +Source: UI or Processor (only these can issue) +Input: orderId, paymentId + +Processing: + 1. Load current state from Order:orderId stream + 2. Validate preconditions: + - state.status === 'Draft' (reject: already confirmed) + - paymentId is valid (reject: invalid payment) + 3. If all valid: + - Produce: OrderConfirmed event + - Data: paymentId, confirmedAt + - Implicit: orderId (from stream), previous status (from state) + 4. If any validation fails: + - Reject: return error (no event created) + +Outcomes: + Success: OrderConfirmed event appended to stream + Rejection: Error returned, no event created +``` + +**Key Rules**: +- Only UI or Processor can issue commands (entry points) +- One command per UI/Processor action +- Commands validate against stream state +- Successful command → Event(s) created +- Failed validation → Command rejected, no event +- Commands are synchronous decision logic (pure) + +### 4. Design Read Models +Read models are **projections of events for UI/Processor queries**: +- Built from events (only source is events) +- Optimized for specific query patterns +- Consumed by UI or Processor (for display/decision) +- Can be regenerated from events anytime + +Format: +```text +ReadModel: OrderSummaryView +Purpose: UI displays customer order list, Processor checks order status + +Subscribed to events: + - OrderCreated + - OrderConfirmed + - OrderShipped + - OrderCancelled + +Data (optimized for queries): + { + orderId: string + customerId: string + total: number + status: string + createdAt: Date + confirmedAt?: Date + shippedAt?: Date + } + +Update from events: + - OrderCreated → Insert row (id, customer, total, status='Draft') + - OrderConfirmed → Update status='Confirmed', set confirmedAt + - OrderShipped → Update status='Shipped', set shippedAt + - OrderCancelled → Update status='Cancelled' + +Consumed by: + - UI: displays list of orders + - Processor: checks if order can be shipped +``` + +### 5. Document Event Causality +Show how events relate to each other: + +```text +Command Flow: +CreateOrder command + → OrderCreated event + ↓ (may trigger external process) +ConfirmOrder command (reads OrderCreated state) + → OrderConfirmed event + ↓ (may trigger) +ShipOrder command (reads OrderCreated + OrderConfirmed state) + → OrderShipped event +``` + +### 6. Document State Transitions +Show valid state transitions: + +```text +Order Stream State Transitions: + +Initial state: (empty stream) + ↓ +CreateOrder → OrderCreated + ↓ +State: Draft + +Draft state: + → ConfirmOrder → OrderConfirmed → State: Confirmed + → CancelOrder → OrderCancelled → State: Cancelled + +Confirmed state: + → ShipOrder → OrderShipped → State: Shipped + → CancelOrder (rejected - already confirmed) + +Shipped state: + → No more transitions allowed +``` + +### Output Format + +Present complete model as: + +```markdown +# Event Model: [Domain] + +## Event Streams + +### Stream: Order + +**Identity**: orderId + +**Events**: +- OrderCreated: Initial event creating the order +Data: customerId, items[], total, shippingAddress + +- OrderConfirmed: Payment confirmed +Data: paymentId, confirmedAt + +- OrderShipped: Order shipped +Data: shipmentId, shippedAt + +- OrderCancelled: Order cancelled +Data: cancelledAt, reason + +**State Projection (Human Example)**: +For the ConfirmOrder command, we need minimal state: +```text +ConfirmOrderState: + - orderId: 'order-123' + - status: 'Draft' +``` + +For the ShipOrder command, we need different data: +```text +ShipOrderState: + - orderId: 'order-123' + - status: 'Confirmed' + - paymentId: 'payment-456' +``` + +--- + +## Commands + +### Command: CreateOrder +- Input: customerId, items[], shippingAddress +- Validation: Items valid, customerId exists +- Events produced: OrderCreated +- Possible outcomes: Success (OrderCreated) or Validation error + +### Command: ConfirmOrder +- Input: orderId, paymentId +- Validation: Order in Draft status, payment validated +- Events produced: OrderConfirmed +- Possible outcomes: Success or "Already confirmed" error + +--- + +## Read Models (Optional) + +### ReadModel: OrderSummaryView +- Purpose: Quick lookup of order status +- Events: OrderCreated, OrderConfirmed, OrderShipped, OrderCancelled +- Queries served: GetOrder(orderId), ListOrdersByCustomer(customerId) + +--- + +## Implementation Notes +- All state is derived from events +- Commands validate against derived state +- No transaction across streams +- Events are source of truth +- Read models can be rebuilt from events +``` + +## Key Event Sourcing Principles + +1. **Events are Facts**: Events describe what happened, not what might happen +2. **Immutable Event Log**: Events are appended, never modified +3. **State is Minimal and Command-Driven**: State is built by replaying events, but ONLY for what a specific command needs to validate. Not all stream fields are needed for all commands. +4. **Not DDD Aggregates**: Stream roots group events logically, but aren't bundles of related data like DDD aggregates. State is determined per-command, not designed upfront for the whole stream. +5. **Commands are Pure**: No side effects, just decision logic against minimal state +6. **Read Models are Separate**: Read models (projections) are separate from command-validation state. Read models can have rich data; command state stays minimal. +7. **Event Causality**: Commands → [minimal state] → Events → [read models] + +## Design Patterns + +### Compensation Pattern +Handle errors by appending compensation events: +```text +Command: ProcessPayment failed + → PaymentFailed event + (triggered by external error) + → OrderCancelled event (compensation) + (or retry logic) +``` + +### Temporal Queries +Answer "what was the state at time T?": +```text +Replay events up to timestamp T + → Get historical state +``` + +## Best Practices for Event Model Design + +### 1. Design Minimal State Per Command +Each command handler only loads the state it needs: +- "LoadOrderState loads { id, items, total, shipping, customer, payment, status, ... }" +- "ConfirmOrderState loads { status, orderId }" +- "ShipOrderState loads { status, orderId, paymentConfirmed }" + +### 2. Separate Command State from Query Models +Keep command-validation state and read models strictly separate: +- **Command State** (minimal): Used by handlers to validate commands +- **Query Models** (rich): Used by UI/Processor to display/query data +- Never share between them + +### 3. Name State Interfaces by Command +Use the pattern `[CommandName]State` to make the relationship explicit: +- `PublishReviewState` for PublishReview command +- `EditReviewState` for EditReview command +- `ReviewState` (ambiguous - which command?) + +### 4. Document State Transitions Clearly +Show what state changes trigger what commands: +- Include initial state +- Show all valid transitions +- Mark impossible transitions (and why) +- Document rejection conditions + +### 5. Make All Constraints Explicit +Transform "obvious" business rules into documented invariants: +- "Obviously can't ship an unconfirmed order" +- "ShipOrder validation: requires status='Confirmed' with paymentId" + +### 6. Keep Event Data Factual +Events record facts, not derived values: +- "OrderCreated { items, total }" (total is computed from items) +- "OrderCreated { items[] with unitPrice, shippingAddress }" (total computed in projection) + +## Quality Checklist + +- [ ] All events are immutable facts (past tense) +- [ ] Events contain only captured data, no computed fields +- [ ] State projection is deterministic from events +- [ ] Each command validates against current state +- [ ] Commands either produce events or reject +- [ ] Event causality is clear +- [ ] State transitions are documented +- [ ] No references between streams in events +- [ ] Read models are optional, not required +- [ ] All logic is state → events (pure functions) diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-elaborating-scenarios/SKILL.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-elaborating-scenarios/SKILL.md new file mode 100644 index 0000000..84fe914 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-elaborating-scenarios/SKILL.md @@ -0,0 +1,598 @@ +--- +name: eventmodeling-elaborating-scenarios +description: >- + Step 7 of Event Modeling - Elaborate scenarios using Given-When-Then format. + Specify behavior of commands and views. Each spec tied to exactly one command + or view. Use after defining systems and boundaries. Do not use for: + architectural validation (use eventmodeling-validating-event-models) or + verifying field completeness across the model (use + eventmodeling-checking-completeness). +allowed-tools: AskUserQuestion, Write +--- + +# Elaborating Scenarios + +## Interview Phase (Optional) + +**When to Interview**: Skip if the user has already specified: scenario coverage depth (happy path + validation + state violations), known edge cases to include, and stakeholders available for review. Interview when coverage goals are unclear or edge cases haven't been identified. + +**Interview Strategy**: Align on scenario depth and coverage strategy to avoid under-specification or excessive documentation. Identify stakeholders who can validate business rules. + +### Critical Questions + +When scenario coverage is uncertain: + +1. **Scenario Depth & Coverage Goals** (Impact: Determines scope—happy path only vs. comprehensive coverage) + - Question: "How comprehensive should scenario coverage be? (A) Happy path + basic validation, (B) All command variations, (C) Comprehensive including edge cases and error paths" + - Why it matters: Affects time investment and implementation complexity; production code needs (C), design validation might use (A) or (B) + - Follow-up triggers: If (C) → ask "How many scenarios per command is reasonable?"; if (A) → clarify MVP vs. production distinction + +2. **Known Edge Cases & Business Rules** (Impact: Ensures critical scenarios aren't missed) + - Question: "What specific edge cases or business rules are critical to test? (e.g., 'order cancellation within 24 hours', 'payment decline recovery')" + - Why it matters: Business rules often generate overlooked scenarios; edge cases reveal missing events + - Follow-up triggers: For each rule → ask "What scenarios demonstrate this rule? What happens when it's violated?" + +3. **Testing & Automation Strategy** (Impact: Shapes scenario detail and executable format) + - Question: "Will these scenarios be: (A) Automated tests, (B) Manual QA reference, (C) Documentation only?" + - Why it matters: Automated tests need precise Given/When/Then; documentation can be more narrative + - Follow-up triggers: If (A) → ask about test framework; if (B) → ask about QA process + +4. **Stakeholder Review & Validation** (Impact: Determines who validates business logic correctness) + - Question: "Who will review and validate scenarios? (A) Product Owner, (B) QA/Tester, (C) Multiple roles, (D) Engineering only?" + - Why it matters: Multi-role review catches business logic errors; single role may miss perspective + - Follow-up triggers: If (A) only → ask "Will PO have time for detailed review?"; if (C) → plan review workshop + +### Interview Flow + +**Conditional Entry**: +``` +If user has provided: + - Clear scenario coverage goals (happy path + validation + state violations) + - AND identified edge cases or known business rules to test + - AND specified who will review/validate scenarios + +Then: Skip interview, proceed directly to scenario elaboration + +Else: Conduct interview +``` + +**Phase 1: Coverage Planning** (Questions 1-2) +- Determine depth (happy path vs. comprehensive) +- Identify critical edge cases to cover +- Establish coverage priorities + +**Phase 2: Implementation & Review** (Questions 3-4) +- Decide on automation vs. documentation +- Confirm stakeholder availability +- Plan review workflow + +### Capturing Interview Findings + +Append findings to the project's event modeling file: + +**File**: `.trogonai/interviews/[project-name]/EVENTMODELING.md` + +Use Write tool to add/update this section: + +```markdown +## 9. Scenarios (eventmodeling-elaborating-scenarios) + +### Coverage Goals +[From Q1: Happy path / Comprehensive / Deep] + +### Critical Edge Cases +[From Q2] +- Edge case 1: [Case] → [Why important] +- Edge case 2: [Case] → [Why important] + +### Business Rules Requiring Scenarios +[From Q2] +- Rule 1: [Statement] → Success + Failure scenarios +- Rule 2: [Statement] → Success + Failure scenarios + +### Testing Strategy +[From Q3: Automated / Manual / Documentation] + +### Review & Validation +[From Q4: Who reviews, when, workflow] + +### Key Scenario Specifications +[GWT format scenarios for critical commands and views] + +--- + +## Validation & Completeness + +### Validated +- [ ] All fields traced (completeness check) +- [ ] Events are immutable +- [ ] State projections deterministic +- [ ] Model ready for code generation + +**Validation Date**: [Date] +``` + +Update Interview Trail: +```markdown +| 9 | eventmodeling-elaborating-scenarios | [today] | Scenario coverage, testing strategy, edge cases | +``` + +At this point, EVENTMODELING.md is complete and ready for implementation! + +--- + +## Workshop Facilitation Guide + +**Context**: Scenarios are created in a collaborative workshop with multiple stakeholders. Use this approach for rapid, real-time scenario creation: + +### Before the Workshop + +**Participants** (required roles): +- **Product Owner/Domain Expert**: Knows business rules, priorities, edge cases +- **Developer**: Technical feasibility, implementation concerns +- **QA/Tester**: Test coverage, edge cases, error scenarios +- **Facilitator**: Keeps pace, ensures shared understanding, captures scenarios + +**Setup**: +- Whiteboard or collaborative tool (Miro, Figma, etc.) +- Sticky notes or digital cards for scenarios +- Previously completed steps: Events timeline and system boundaries +- Timer for time-boxing per command/view + +### During Workshop (Per Command/View) + +**Rapid Cycle** (15-20 min per command): +1. **Happy Path First**: "What's the normal success case?" (Product Owner leads) + - Facilitator writes scenario live + - All roles review in real-time + - Adjust based on feedback + +2. **Validation Failures**: "What could go wrong with inputs?" (Developer/QA) + - Common: invalid format, missing fields, invalid references + - Quick scenarios, add to board + +3. **State Violations**: "What if system is in wrong state?" (Domain Expert) + - Example: "Can't confirm if already confirmed" + - These are business rules, often overlooked + +4. **Alternative Paths**: "Are there other ways this could work?" (Product Owner) + - Different paths through the same command + - Different outcomes based on business logic + +5. **Error Handling**: "What if external systems fail?" (Developer) + - Payment decline, inventory unavailable + - Recovery/retry scenarios + +6. **Compensation**: "Can this be undone?" (Domain Expert) + - Cancellation, reversal, refund flows + - Often reveal missing events + +**Review Style**: +- Each scenario read aloud by facilitator +- Quick check: "Is this right?" (Everyone nods or speaks up) +- Move forward—don't perfect, iterate later +- Target: 3-5 scenarios per command, 10-20 minutes per command + +### Multi-Role Review + +As scenarios are written, ensure each role checks: +- **Product Owner**: "Is this the right business behavior?" +- **Developer**: "Can we implement this? Need system state? Edge cases?" +- **QA**: "Can we test this? Is it clear enough?" +- **Facilitator**: "Do we have enough detail for coding?" + +### Common Workshop Mistakes to Avoid + + **Perfectionism**: Don't spend 30 minutes on one scenario. Capture and move. + **Missing roles**: One person can't represent all perspectives. + **Too technical**: Use domain language, not code. Adjust in implementation. + **Incomplete givens**: "Given an order" is too vague. Specify state. + **Unclear events**: Every scenario must show what event is produced (or why not). + +### Tips for Rapid Creation + + **Use templates**: Have sticky note templates with Given/When/Then pre-printed + **Parallel work**: Different people write different scenarios simultaneously + **Capture edge cases**: When someone says "What if...?" → immediately capture as scenario + **Reference past decisions**: Point to event timeline and boundary diagrams + **Record decisions**: Why did we choose this behavior? (Helps implementers later) + +## Workflow + +For each command and view, write scenarios in Given-When-Then format: + +### 1. Command Scenarios (Given-When-Then) +Specify command behavior: + +``` +Feature: Order Creation + +Scenario: Create order successfully +Given a customer with ID "cust-123" +And products exist with IDs ["prod-1", "prod-2"] +And customer has valid shipping address +When the customer creates an order with items: + | productId | quantity | unitPrice | + | prod-1 | 2 | 50.00 | + | prod-2 | 1 | 30.00 | +Then the order should be created with status "Draft" +And the total should be calculated as 130.00 +And an "OrderCreated" event is produced with: + | field | value | + | orderId | {uuid} | + | customerId | cust-123 | + | items | [...] | + | total | 130.00 | + | status | Draft | + +Scenario: Reject order with invalid customer +Given a customer ID "invalid-cust" +And no customer exists with that ID +When the customer tries to create an order +Then the command should be rejected +And the rejection reason is "Customer not found" +And no event is produced + +Scenario: Reject order with empty items +Given a customer with ID "cust-123" +And an empty items list [] +When the customer tries to create an order +Then the command should be rejected +And the rejection reason is "Order must contain items" +And no event is produced + +Scenario: Reject order with invalid address +Given a customer with ID "cust-123" +And an incomplete shipping address (missing city) +When the customer tries to create an order +Then the command should be rejected +And the rejection reason is "Invalid shipping address" +And no event is produced +``` + +### 2. Command Scenarios - State Validation +Specify how stream state affects command: + +``` +Feature: Order Confirmation + +Scenario: Confirm order in Draft state +Given an order "order-456" in Draft state +And OrderCreated event exists +And no OrderConfirmed event exists +When the customer confirms the order with payment method "card" +Then the order should be confirmed +And an "OrderConfirmed" event is produced with: + | field | value | + | orderId | order-456 | + | paymentMethod | card | + | confirmedAt | {timestamp} | + +Scenario: Reject confirming already-confirmed order +Given an order "order-456" in Confirmed state +And OrderConfirmed event already exists +When the customer tries to confirm the order again +Then the command should be rejected +And the rejection reason is "Order already confirmed" +And no OrderConfirmed event is produced + +Scenario: Reject confirming cancelled order +Given an order "order-456" in Cancelled state +And OrderCancelled event exists +When the customer tries to confirm the order +Then the command should be rejected +And the rejection reason is "Cannot confirm cancelled order" +And no event is produced +``` + +### 3. View Scenarios (Given-When-Then) +Specify how read models display data: + +``` +Feature: Order Status View + +Scenario: Display order after creation +Given an OrderCreated event with: + | field | value | + | orderId | order-789 | + | customerId | cust-123 | + | items | [{...}] | + | total | 150.00 | +When the OrderStatusView processes this event +Then the view should display: + | field | value | + | Order ID | order-789 | + | Status | Draft | + | Total | $150.00 | + | Items | 3 products | + | Created | {date} | + +Scenario: Update status after confirmation +Given an OrderCreated event already processed +And OrderStatusView showing status "Draft" +When an OrderConfirmed event is received with: + | field | value | + | orderId | order-789 | + | confirmedAt | 2024-12-31T10:00:00Z | +Then the view should update to display: + | field | value | + | Status | Confirmed | + | Confirmed Date | 12/31/2024 10:00 AM | + +Scenario: Accumulate payment information +Given OrderConfirmed event processed (status=Confirmed) +When a PaymentAuthorized event arrives with: + | field | value | + | orderId | order-789 | + | paymentId | pay-123 | + | authCode | AUTH-456 | +Then the view should accumulate: + | field | value | + | Payment ID | pay-123 | + | Auth Code | AUTH-456 | + | Payment Status | Authorized | +``` + +### 4. Error Path Scenarios +Specify how system handles failures: + +``` +Feature: Payment Authorization Failure + +Scenario: Handle declined payment +Given an order "order-001" in Confirmed state +And customer initiates payment +When the payment gateway declines the card +Then a PaymentFailed event is produced with: + | field | value | + | orderId | order-001 | + | reason | Card declined | + | timestamp | {now} | + +Scenario: Update order view on payment failure +Given OrderStatusView shows status "Confirmed" +When PaymentFailed event arrives for order-001 +Then the view should update: + | field | value | + | Payment Status | Failed | + | Failure Reason | Card declined | + | Retry Available | Yes | + +Scenario: Allow retry after payment failure +Given a PaymentFailed event exists +And order status is still "Confirmed" +When customer retries payment +Then the new AuthorizePayment command is accepted +And can produce new PaymentAuthorized event +``` + +### 5. Compensation Scenarios +Specify rollback/cancellation flows: + +``` +Feature: Order Cancellation + +Scenario: Cancel order in Draft state +Given an order "order-555" in Draft state +And only OrderCreated event exists +When customer cancels the order with reason "Changed mind" +Then an OrderCancelled event is produced with: + | field | value | + | orderId | order-555 | + | reason | Changed mind | + | cancelledAt | {timestamp} | + +Scenario: Cannot cancel completed order +Given an order "order-555" in Delivered state +And DeliveryConfirmed event exists +When customer tries to cancel +Then the command should be rejected +And the rejection reason is "Cannot cancel delivered order" + +Scenario: Trigger compensation on cancellation +Given an order in Confirmed state +And PaymentAuthorized event exists +When OrderCancelled event is produced +Then a RefundPayment command should be automatically triggered +And RefundInitiated event should follow +``` + +## Output Format + +Present as: + +````markdown +# Scenarios: [Domain Name] + +## Commands + +### Command: CreateOrder + +**Description**: Customer creates a new order with items and shipping address. + +#### Scenario 1: Successful Order Creation +```gherkin +Given a customer with ID "cust-123" +And products ["prod-1", "prod-2"] exist in catalog +And the shipping address is valid +When the customer creates an order: + | customerId | cust-123 | + | items | [{productId: prod-1, qty: 2}, {productId: prod-2, qty: 1}] | + | shippingAddress | {street, city, state, zip} | +Then the command succeeds +And an "OrderCreated" event is produced with all input data +And the order status is "Draft" +``` + +#### Scenario 2: Reject with Invalid Customer +```gherkin +Given a customer ID "invalid" that doesn't exist +When the customer tries to create an order +Then the command is rejected +And the error is "Customer not found" +And no event is produced +``` + +[Continue for each scenario] + +--- + +### Command: ConfirmOrder + +**Description**: Customer confirms order and selects payment method. + +#### Scenario 1: Confirm Draft Order +```gherkin +Given an order in "Draft" state +And OrderCreated event exists +When the customer confirms with paymentMethod="card" +Then an "OrderConfirmed" event is produced +And the order status becomes "Confirmed" +``` + +#### Scenario 2: Prevent Duplicate Confirmation +```gherkin +Given an order already in "Confirmed" state +And OrderConfirmed event already exists +When the customer tries to confirm again +Then the command is rejected +And the error is "Order already confirmed" +And no new event is produced +``` + +--- + +## Views + +### View: OrderStatusView + +**Description**: Real-time order status display showing accumulated event data. + +#### Scenario 1: Initial Display After Creation +```gherkin +Given an OrderCreated event with id, customer, items, total, address +When the view processes this event +Then the view displays: + - Order ID: order-123 + - Status: Draft + - Total: $150.00 + - Items: 3 products + - Customer: cust-456 +``` + +#### Scenario 2: Update on Confirmation +```gherkin +Given the view displaying status="Draft" +When an OrderConfirmed event arrives +Then the view updates to: + - Status: Confirmed + - Confirmed At: {timestamp} + - Payment Method: (from event) +``` + +#### Scenario 3: Accumulate Payment Data +```gherkin +Given status="Confirmed" +When PaymentAuthorized event arrives +Then the view shows: + - Payment Status: Authorized + - Auth Code: (from event) + - Payment ID: (from event) +``` + +--- + +## Error Paths + +### Scenario: Payment Decline +```gherkin +Given an order in "Confirmed" state +When payment gateway declines +Then PaymentFailed event is produced +And OrderStatusView updates to show: + - Payment Status: Failed + - Retry Available: true +``` + +--- + +## Compensation Flows + +### Scenario: Order Cancellation with Refund +```gherkin +Given an order in "Confirmed" state +And PaymentAuthorized event exists +When OrderCancelled event is produced +Then a RefundPayment command is triggered +And RefundInitiated event follows +And inventory reservation is released +``` +```` + +## Quality Checklist + +- [ ] Every command has success scenario +- [ ] Every command has failure scenarios +- [ ] Every command has state-validation scenarios +- [ ] State preconditions are explicit (Given) +- [ ] Actions are clear (When) +- [ ] Outcomes are verifiable (Then) +- [ ] Event data is specified +- [ ] Rejection reasons are clear +- [ ] Every view has update scenarios +- [ ] Alternative paths documented +- [ ] Compensation flows specified +- [ ] Error handling explicit +- [ ] **Workshop facilitation approach documented** +- [ ] **All stakeholder roles (PO, Dev, QA, Domain Expert) perspectives captured** +- [ ] **Rapid time-boxing used (15-20 min per command)** +- [ ] **Edge cases suggested by participants captured** +- [ ] **Why behind business rules documented (not just the what)** + +## Gherkin Best Practices + +``` +Good: +Given an order in "Draft" state +When the customer confirms the order +Then the status changes to "Confirmed" + +Bad: +Given order +When stuff happens +Then it works + +Good: +And an OrderConfirmed event is produced with: + | field | value | + | orderId | order-123 | + +Bad: +And an event is produced + +Good: +Then the command is rejected +And the error is "Customer not found" + +Bad: +Then there's an error +``` + +## Scenario Organization + +1. **Happy Path**: Successful execution +2. **Validation Failures**: Invalid inputs +3. **State Violations**: Wrong pre-conditions +4. **Duplicate Actions**: Already processed +5. **Alternative Paths**: Different branches +6. **Error Handling**: Failures and recovery +7. **Compensation**: Rollback and cleanup + +## Key Principles + +1. **One Scenario = One Test**: Each scenario is testable +2. **Explicit Preconditions**: State is clear in "Given" +3. **Clear Actions**: "When" describes user/processor action +4. **Verifiable Outcomes**: "Then" checks results +5. **Event-Centric**: Every scenario produces or updates events +6. **Business Language**: Use domain terms, not technical jargon diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-identifying-inputs/SKILL.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-identifying-inputs/SKILL.md new file mode 100644 index 0000000..f5625fc --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-identifying-inputs/SKILL.md @@ -0,0 +1,443 @@ +--- +name: eventmodeling-identifying-inputs +description: >- + Step 4 of Event Modeling - Identify Commands/Inputs from UI and Processor + actions. Map user actions to commands and data. Use after storyboarding UI. + Do not use for: identifying read models or outputs (use + eventmodeling-identifying-outputs) or elaborating behavior specifications + (use eventmodeling-elaborating-scenarios). +allowed-tools: AskUserQuestion, Write +--- + +# Identifying Inputs + +## Interview Phase (Optional) + +**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. + +**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. + +### Critical Questions + +1. **Automation Level** (Impact: Determines which commands are UI-triggered vs. processor-triggered) + - Question: "Are there actions that should be: (A) User-initiated only, (B) Processor-automated, (C) Mix of both?" + - Why it matters: Knowing automation vs. manual separates command types + - Follow-up triggers: If (C) → ask "Which specific user actions trigger automation? What does the processor decide on its own?" + +2. **External System Triggers** (Impact: Determines if there are processor commands from webhooks/integrations) + - Question: "Will commands be triggered by: (A) UI only, (B) External webhooks (payments, notifications, etc.), (C) Scheduled processors, (D) All of above?" + - Why it matters: External triggers are processor commands, not UI commands + - Follow-up triggers: If (B) or (D) → ask which external systems send webhooks and what data they include + +### Interview Flow + +**Conditional Entry**: +``` +If user has provided: + - UI actions already listed per storyboard screen + - AND processor triggers identified with source systems named + - AND it's clear which role/actor initiates each action + +Then: Skip interview, proceed directly to command identification + +Else: Conduct interview +``` + +**Phase 1: Trigger Classification** (Question 1) +- Establish which commands come from human actors vs. automated processors +- Confirm Role Catalog from Step 1 is available for attribution + +**Phase 2: External Triggers** (Question 2) +- Identify all external system integrations that issue commands +- Confirm whether scheduled jobs or event-driven processors exist + +### Capturing Interview Findings + +Append findings to the project's event modeling file: + +**File**: `.trogonai/interviews/[project-name]/EVENTMODELING.md` + +Use Write tool to add/update this section: + +```markdown +## 4. Identifying Inputs (eventmodeling-identifying-inputs) + +### Automation Classification +[From Q1: Which actions are user-initiated vs. processor-automated?] + +### External System Triggers +[From Q2: Which external systems trigger commands? Webhook formats?] + +### Command Attribution Summary +- UI-issued commands: [list with role from Role Catalog] +- Processor-issued commands: [list with source system] +``` + +Update Interview Trail: +```markdown +| 4 | eventmodeling-identifying-inputs | Done | UI commands, processor commands, role attribution | +``` + +--- + +## Workflow + +Given UI storyboards and event timeline, identify all inputs. + +**PREREQUISITE**: The **Role Catalog** from Step 1 (eventmodeling-brainstorming-events) must exist. Every command identified below MUST be attributed to a specific role or system actor from that catalog. + +### 1. Extract Commands from UI Actions +For each user action in storyboard, create a command attributed to a specific role: + +``` +Storyboard: Order Creation Screen +User action: Click "Create Order" button + ↓ +Command: CreateOrder +Input data from form: + - customerId + - items[] (product selections + quantities) + - shippingAddress +Validation: + - customerId must exist + - items must not be empty + - quantities must be > 0 +Produces event: OrderCreated +``` + +### 2. Identify Processor Triggers +Identify automation-triggered commands: + +``` +Processor trigger: Payment gateway webhook received + ↓ +Command: AuthorizePayment (from Processor, not UI) +Input data from webhook: + - orderId + - paymentId + - authorizationCode +Validation: + - orderId must exist and be in Confirmed state + - authorizationCode must be valid +Produces event: PaymentAuthorized +``` + +### 2b. Understand the Processor "Todo List" Pattern +Processors don't directly process events—they maintain a todo list driven by events: + +``` +Event Stream (Domain events): +PaymentAuthorized → triggers Inventory system + +Processor: InventoryReserver + +Todo List: +When PaymentAuthorized event arrives: + 1. Add item to todo: "Reserve inventory for order-123" + +Processor Logic (continuously): +FOR EACH todo item IN todo_list: + - Check if inventory available + - If yes: Reserve inventory, produce InventoryReserved event, mark done + - If no: Produce InventoryFailed event, mark failed + - If error: Keep in todo for retry + +Example: +Event: PaymentAuthorized(orderId=order-123, items=[{prodId: P1, qty: 2}]) + ↓ +Todo added: Reserve P1 qty 2 + ↓ +Processor checks: P1 has 5 available, need 2 + ↓ +Action: Reserve 2 units + ↓ +Event produced: InventoryReserved(orderId=order-123, reserved=[...]) + ↓ +Todo marked done +``` + +**Key insight**: Processors are reactive. They listen for events and create todo items, then execute those todos by issuing commands that produce new events. + +### 2c. Document Processor Automation (Gears Symbol) +Show which commands come from automation vs. user actions: + +``` +Command Catalog with Role Attribution (from Role Catalog): + +UI-Issued Commands (attributed to specific human roles): + 1. CreateOrder (Order Entry screen) [ Customer] + 2. ConfirmOrder (Confirmation screen) [ Customer] + 3. CancelOrder (Status screen) [ Customer] + 4. RequestReturn (Order page) [ Customer] + 5. OverrideOrderStatus (Admin panel) [ Support Agent] + +Processor-Issued Commands (attributed to system actors): + 6. AuthorizePayment (Payment gateway webhook) [ Payment Gateway] + 7. ReserveInventory (Triggered by PaymentAuthorized) [ Inventory System] + 8. CreateShipment (Triggered by InventoryReserved) [ Fulfillment System] + 9. NotifyCustomer (Triggered by multiple events) [ Notification Service] +``` + +**Validation**: Every command MUST have a role/actor attribution. If a command says `[ User]` instead of a specific role name, it's incomplete — go back to the Role Catalog and assign the correct role. + +### 3. Document Command Specifics +For each command, define structure: + +``` +Command: ConfirmOrder +Source: UI (user clicks button) +Input: + orderId: string (from URL/context) + paymentMethod: enum ('card' | 'transfer') + [paymentDetails]: depends on method + +Validation rules: + - Order must exist + - Order must be in Draft state + - Payment method must be supported + - Funds must be available (pre-check) + +Preconditions (from stream state): + - OrderCreated event exists + - No ConfirmOrder previously processed + +Success result: OrderConfirmed event + +Failure results: + - "Order not found" → Command rejected, no event + - "Order already confirmed" → Command rejected, no event + - "Payment method not supported" → Command rejected, no event +``` + +### 4. Create Command Catalog +List all commands the system accepts: + +``` +Command Catalog: Order System + +### UI-Issued Commands + +1. CreateOrder + Source: User (Order Entry screen) + Input: customerId, items[], shippingAddress + Produces: OrderCreated event + +2. ConfirmOrder + Source: User (Confirmation screen) + Input: orderId, paymentMethod + Produces: OrderConfirmed event + +3. CancelOrder + Source: User (Status screen) + Input: orderId, reason + Produces: OrderCancelled event + +### Processor-Issued Commands + +4. AuthorizePayment + Source: Payment Processor (webhook) + Input: orderId, paymentId, authCode + Produces: PaymentAuthorized event + +5. FailPayment + Source: Payment Processor (webhook) + Input: orderId, paymentId, reason + Produces: PaymentFailed event + +6. ReserveInventory + Source: Inventory Processor (triggered by PaymentAuthorized) + Input: orderId, items[] + Produces: InventoryReserved event + +7. CreateShipment + Source: Fulfillment Processor (triggered by InventoryReserved) + Input: orderId, items[] + Produces: OrderShipped event +``` + +### 5. Map Data Sources +Document where each command input comes from: + +``` +Command: ConfirmOrder + +Data origin matrix: + orderId + ↑ Source: UI context (from OrderCreated, displayed to user) + ↑ Captured: Hidden in URL or session + ↑ Validation: Must match Order from stream + + paymentMethod + ↑ Source: UI form selection + ↑ Captured: User selects checkbox/radio + ↑ Validation: Must be in allowed list + +[paymentDetails] (conditional) + ↑ Source: Depends on paymentMethod + ↑ For 'card': Card number, CVV, expiry (from payment form) + ↑ For 'transfer': Bank account, routing number (from form) + ↑ Validation: Format and validity checks +``` + +### 6. Identify Implicit Context +Document what comes from stream state: + +``` +Command: ShipOrder +Explicit input (from UI/Processor): + orderId + shipmentId (from fulfillment system) + +Implicit context (from stream state): + Order must exist + Order must be in InventoryReserved state + Payment must be authorized (from PaymentAuthorized event) + Inventory must be reserved (from InventoryReserved event) + +These implicit checks use stream state: + currentState.orderId === orderId + currentState.status === 'InventoryReserved' + currentState.paymentId exists + currentState.shipmentId can be set +``` + +## Output Format + +Present as: + +```markdown +# Inputs: [Domain Name] + +## Commands Summary + +| Command | Role/Actor | Source | Trigger | Input | Event | +|---------|------------|--------|---------|-------|-------| +| CreateOrder | Customer | UI | User action | customerId, items, address | OrderCreated | +| ConfirmOrder | Customer | UI | User action | orderId, paymentMethod | OrderConfirmed | +| CancelOrder | Customer | UI | User action | orderId, reason | OrderCancelled | +| AuthorizePayment | Payment Gateway | Processor | Webhook | orderId, paymentId | PaymentAuthorized | +| ReserveInventory | Inventory System | Processor | PaymentAuthorized event | orderId, items | InventoryReserved | +| ShipOrder | Fulfillment System | Processor | InventoryReserved event | orderId, shipmentId | OrderShipped | + +--- + +## Detailed Commands + +### Command: CreateOrder + +**Source**: User (Order Entry screen) + +**Input Data**: +- customerId: string +- items: Array<{productId: string, quantity: number}> +- shippingAddress: {street, city, state, zip} + +**Validation**: +- customerId must exist in system +- items array must not be empty +- quantities must be > 0 +- address fields must be non-empty + +**Preconditions** (from stream state): +- Stream Order:X does not exist yet + +**Success**: Produces OrderCreated event + +**Failure**: Command rejected, no event +- "Customer not found" +- "Items invalid" +- "Address incomplete" + +--- [Repeat for each command] + +--- + +## Data Completeness Check + +### Data Input → Event + +Verify every command input becomes event data: + +| Command Input | Event Data | Status | +|---------------|-----------|--------| +| customerId | orderId | Stored in OrderCreated | +| items | items | Stored in OrderCreated | +| shippingAddress | shippingAddress | Stored in OrderCreated | + +### Missing Data + +Document any input that doesn't make it to events: +- None identified + +--- + +## Processor Commands + +Document all processor-triggered commands: +[List each with source system and trigger condition] +``` + +## Quality Checklist + +- [ ] Every UI action maps to a command +- [ ] Every processor action maps to a command +- [ ] **Every command is attributed to a specific role/actor from the Role Catalog** +- [ ] **No command uses generic "User" — must name the specific role (Customer, Seller, Admin, etc.)** +- [ ] Every command input is documented +- [ ] Every input validates against rules +- [ ] Preconditions from stream state are explicit +- [ ] Success and failure outcomes documented +- [ ] Implicit context from stream state is identified +- [ ] No undocumented commands exist +- [ ] Command naming is consistent and clear +- [ ] Processor triggers are explicit +- [ ] **Processor todo list pattern explained for each automation** +- [ ] **Event-to-todo triggering mechanism documented** +- [ ] **Automation marked with [AUTO] to distinguish from user actions [USER]** +- [ ] **Processor failure/retry handling specified** + +## Key Principles + +1. **Source Clarity**: Every command comes from UI or Processor +2. **Input Completeness**: All needed data captured +3. **Validation Explicit**: All rules documented +4. **State Awareness**: Preconditions from stream state clear +5. **Event Mapping**: Every input becomes event data + +## Common Patterns + +### User Command Pattern +``` +User action on UI screen + ↓ +Captures form/selection data + ↓ +Validation checks + ↓ +Command issued + ↓ +Event created or rejection +``` + +### Processor Command Pattern +``` +External event/webhook received + ↓ +Triggers processor logic + ↓ +Processor validates and decides + ↓ +Command issued (if valid) + ↓ +Event created or decision recorded +``` + +### Conditional Input Pattern +``` +Command: PaymentConfirm +Input: + - paymentMethod (user selected) + - paymentDetails (conditional on method) + If method='card': cardNumber, CVV, expiry + If method='transfer': bankAccount, routingNumber +``` diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-identifying-outputs/SKILL.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-identifying-outputs/SKILL.md new file mode 100644 index 0000000..e059d6f --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-identifying-outputs/SKILL.md @@ -0,0 +1,509 @@ +--- +name: eventmodeling-identifying-outputs +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). +allowed-tools: AskUserQuestion, Write +--- + +# Identifying Outputs + +## Interview Phase (Optional) + +**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. + +**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. + +### Critical Questions + +1. **Query Patterns** (Impact: Determines which read models are needed and their update frequency) + - Question: "What data do users/processors need to query? (A) Real-time (sub-second), (B) Near-real-time (seconds), (C) Periodic (minutes/hours)?" + - Why it matters: Query frequency drives read model design and caching strategy + - Follow-up triggers: If (A) → ask which specific screens or processors require sub-second reads; these need dedicated, highly optimized read models + +2. **Event vs Read Model Clarification** (Impact: Ensures we don't model calculations as events) + - Question: "Are there calculated/aggregated fields? (e.g., average rating, total sales, inventory count) - These are read models, not events." + - Why it matters: Common mistake to model calculations as events; identifying them upfront prevents architecture errors + - 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?" + +### Interview Flow + +**Conditional Entry**: +``` +If user has provided: + - UI screens with data needs mapped to event sources + - AND processor query needs documented + - AND calculated/aggregated fields identified as read models (not events) + +Then: Skip interview, proceed directly to read model design + +Else: Conduct interview +``` + +**Phase 1: Query Pattern Mapping** (Question 1) +- Identify which UI screens and processors need data +- Establish freshness requirements per consumer +- Determine if any queries require real-time consistency + +**Phase 2: Calculation Detection** (Question 2) +- Surface any aggregated or computed values +- Confirm they are projections, not events +- Prevent the calculation-as-event anti-pattern before design begins + +### Capturing Interview Findings + +Append findings to the project's event modeling file: + +**File**: `.trogonai/interviews/[project-name]/EVENTMODELING.md` + +Use Write tool to add/update this section: + +```markdown +## 5. Identifying Outputs (eventmodeling-identifying-outputs) + +### Query Patterns +[From Q1: Which consumers need what freshness? Real-time vs. periodic?] + +### Calculated Fields Identified +[From Q2: Which fields are aggregated/calculated? Confirmed as read models?] + +### Read Model Summary +- Real-time read models: [list] +- Near-real-time read models: [list] +- Calculation-as-event anti-patterns caught: [list or "None"] +``` + +Update Interview Trail: +```markdown +| 5 | eventmodeling-identifying-outputs | Done | Read model catalog, query patterns, calculation classification | +``` + +--- + +## CRITICAL: Events vs Read Models + +**This is the most important distinction in event sourcing.** Many architectures fail because this line gets blurred. + +### Events = Immutable Domain Facts +Things that actually happened in the domain. Once created, they never change: +- CustomerCreated (a customer actually signed up) +- OrderPlaced (someone actually placed an order) +- PaymentAuthorized (payment gateway actually authorized) +- OrderShipped (fulfillment actually shipped the order) + +**Characteristics**: +- Represents an action someone took +- Immutable once recorded +- Can be replayed to rebuild state +- Provides audit trail +- Independent of other events + +### Read Models = Derived Projections +Optimized views calculated FROM events. They recalculate multiple times: +- CustomerDashboard (projects current customer data) +- OrderStatusView (projects order state) +- InventoryLevelView (projects available stock from receipt/sale events) +- InventoryLevel (projects available stock) + +**Characteristics**: +- Calculated/aggregated state +- Recalculates when source events change +- Derived from other events +- Query optimization +- Can be regenerated from events + +### The Test: Is It an Event or Read Model? + +Ask these questions in order: + +| Question | Answer | Type | Example | +|----------|--------|------|---------| +| Did an actor perform an action? | YES | EVENT | Customer confirmed the order | +| Is this pure calculation? | YES | READ MODEL | Inventory level total | +| Is it immutable once created? | YES | EVENT | PaymentAuthorized | +| Does it recalculate multiple times? | YES | READ MODEL | Total sales (updates as orders change) | +| Is it independent (causes no other events)? | YES | EVENT | OrderFlagged (flagged for manual review) | +| Is it derived FROM other events? | YES | READ MODEL | OrderStatus (derived from multiple events) | + +### Common Anti-Patterns + +**DON'T model these as EVENTS**: +- Inventory level totals (calculation from stock events) +- Inventory totals (sum of transactions) +- Account balances (calculation from transactions) +- Search indexes (derived from documents) +- Aggregated metrics (sums, counts, averages) +- Scheduled calculations (processor outputs that are pure calculation) + +**DO model them as READ MODELS**: + + WRONG: Modeling as Event +``` +InventoryLevelRecalculated + productId: product-456 + currentStock: 84 (This recalculates!) + reservedStock: 12 (Derived, not a fact) +``` + + CORRECT: Model as Read Model +``` +InventoryLevelView + productId: product-456 + totalReceived: 200 + totalSold: 116 + currentStock: 84 + lastUpdated: 2025-01-24T10:30:00Z + history: + - 2024-12-01: stock 150 (200 received) + - 2024-12-15: stock 110 (40 sold) + - 2025-01-24: stock 84 (26 sold) +``` + +**WHY**: +- Events should capture facts (what happened) +- Calculations should be projections (how we view the facts) +- Otherwise you end up with circular dependencies and replay issues + +--- + +## Workflow + +Given commands and events, identify all outputs: + +### 1. Map Event Data to UI Screens +For each screen, identify source events: + +``` +Screen: Order Status View +Displays data from events: + orderId ← OrderCreated event + customerId ← OrderCreated event + items ← OrderCreated event + total ← OrderCreated event + status ← OrderConfirmed event (or OrderCancelled) + confirmedAt ← OrderConfirmed event + paymentId ← PaymentAuthorized event + shipmentId ← OrderShipped event + shippedAt ← OrderShipped event + +This screen is a projection of these events: + - OrderCreated + - OrderConfirmed + - PaymentAuthorized + - OrderShipped +``` + +### 2. Define Read Models +Create optimized views from event data: + +``` +ReadModel: OrderStatusView +Purpose: UI displays current order status +Events subscribed: OrderCreated, OrderConfirmed, PaymentAuthorized, OrderShipped, OrderCancelled +Data: +{ + orderId: string (from OrderCreated) + customerId: string (from OrderCreated) + status: enum (from events: Draft → Confirmed → Authorized → Shipped → Delivered) + createdAt: Date (from OrderCreated) + confirmedAt: Date (from OrderConfirmed) + paymentId: string (from PaymentAuthorized) + shipmentId: string (from OrderShipped) + shippedAt: Date (from OrderShipped) +} +``` + +### 3. Document Event → Data Mapping +Show exactly what data each event provides: + +``` +Event: OrderCreated +Provides to UI/Processors: + orderId + customerId + items[] + total + shippingAddress + createdAt + +Event: OrderConfirmed +Provides to UI/Processors: + orderId (link to stream) + paymentMethod (user selected method) + confirmedAt (timestamp) + paymentId (payment system reference) + +Event: PaymentAuthorized +Provides to UI/Processors: + orderId (link to stream) + paymentId + authCode + authorizedAt (timestamp) + amount (verified amount) + +Event: OrderShipped +Provides to UI/Processors: + orderId (link to stream) + shipmentId + shippedAt (timestamp) + carrier (shipping company) + trackingNumber (for delivery tracking) +``` + +### 4. Create Output Catalog +List all read models: + +``` +ReadModel Catalog: Order System + +1. OrderStatusReadModel + Purpose: UI shows current order status + Events: OrderCreated, OrderConfirmed, PaymentAuthorized, OrderShipped, OrderCancelled + Data: orderId, status, createdAt, confirmedAt, paymentId, shipmentId + Consumed by: + - Order Status screen (UI) + - Customer Dashboard (UI) + - Order Processing Processor (decides if can ship) + +2. OrderListReadModel + Purpose: UI lists all orders for a customer + Events: OrderCreated, OrderConfirmed, OrderCancelled + Data: orderId, customerId, total, status, createdAt + Consumed by: + - Customer Order History (UI) + - Order Search/Filter (UI) + +3. PaymentStatusReadModel + Purpose: UI shows payment status + Events: OrderConfirmed, PaymentAuthorized, PaymentFailed + Data: orderId, paymentId, status, authCode, failureReason, timestamp + Consumed by: + - Payment Status screen (UI) + - Accounting Processor (reconciliation) + +4. ShipmentTrackingReadModel + Purpose: UI shows tracking information + Events: OrderShipped, DeliveryConfirmed + Data: orderId, shipmentId, trackingNumber, carrier, shippedAt, estimatedDelivery + Consumed by: + - Order Tracking screen (UI) + - Customer notifications (Processor) +``` + +### 5. Identify Missing Data +Check if all UI needs are covered: + +``` +Question: What if UI needs "estimated delivery date"? +Event: OrderShipped has carrier + trackingNumber +Action needed: Add estimatedDelivery to OrderShipped event + (or compute from carrier info) + +Question: What if UI needs to show "payment method" on status? +Event: OrderConfirmed has paymentMethod +Action needed: Include paymentMethod in relevant read models + +Question: What if UI needs "item descriptions"? +Event: OrderCreated has items[] +But: items[] only has productId +Action needed: Enrich with product descriptions from catalog + (via join with product service) +``` + +### 6. Processor Outputs +Identify what processors consume: + +``` +Processor: Inventory System +Consumes from read models: + - Orders in "PaymentAuthorized" status + - Items and quantities needed +Produces commands: + - ReserveInventory + +Processor: Fulfillment System +Consumes from read models: + - Orders in "InventoryReserved" status + - Items and quantities + - Shipping address +Produces commands: + - CreateShipment + +Processor: Notification System +Consumes from read models: + - OrderCreated (sends confirmation) + - OrderConfirmed (sends receipt) + - OrderShipped (sends tracking) + - DeliveryConfirmed (sends thank you) +Does not produce commands (info-only) +``` + +## Output Format + +Present as: + +```markdown +# Outputs: [Domain Name] + +## Read Models Summary + +| ReadModel | Purpose | Events | Consumed By | +|-----------|---------|--------|-------------| +| OrderStatus | Show order state | OrderCreated, OrderConfirmed | UI, Processor | +| OrderList | List orders | OrderCreated, OrderCancelled | UI | +| PaymentStatus | Payment info | OrderConfirmed, PaymentAuthorized | UI, Accounting | +| Shipment Tracking | Track delivery | OrderShipped, DeliveryConfirmed | UI, Notifications | + +--- + +## Detailed Read Models + +### ReadModel: OrderStatusView + +**Purpose**: Order Status screen displays current order state + +**Events subscribed**: +- OrderCreated +- OrderConfirmed +- PaymentAuthorized +- OrderShipped +- OrderCancelled +- DeliveryConfirmed + +**Data**: +``` +{ + orderId: string + customerId: string + status: 'Draft' | 'Confirmed' | 'Authorized' | 'Shipped' | 'Delivered' | 'Cancelled' + items: Array<{productId, quantity, unitPrice}> + total: number + shippingAddress: Address + + createdAt: Date + confirmedAt: Date + paymentId: string + paymentMethod: 'card' | 'transfer' + authorizedAt: Date + + shipmentId: string + carrier: string + trackingNumber: string + shippedAt: Date + estimatedDelivery: Date +} +``` + +**Update Logic**: +- OrderCreated: Insert with status='Draft' +- OrderConfirmed: Update status='Confirmed' +- PaymentAuthorized: Update status='Authorized', set paymentId +- OrderShipped: Update status='Shipped', set shipmentId, carrier, trackingNumber +- DeliveryConfirmed: Update status='Delivered' +- OrderCancelled: Update status='Cancelled' + +**Consumed By**: +- Order Status Screen (displays) +- Order Processing Processor (checks status) +- Notification System (sends updates) + +--- [Repeat for each read model] + +--- + +## Data Completeness Check + +### Events → UI Needs + +Verify all UI needs have event sources: + +| UI Need | Event Source | Status | +|---------|-------------|--------| +| Order status | OrderConfirmed, OrderShipped | | +| Tracking number | OrderShipped | | +| Order items | OrderCreated | | +| Estimated delivery | OrderShipped | | +| Cancellation reason | OrderCancelled | | + +### Missing Data + +Identify UI needs without event sources: +- None identified + +--- + +## Processor Consumption + +### Processors and their reads: + +| Processor | Reads From | Writes Commands | +|-----------|-----------|-----------------| +| Inventory | OrderStatusView (Authorized) | ReserveInventory | +| Fulfillment | OrderStatusView (InventoryReserved) | CreateShipment | +| Notification | OrderStatusView (all) | None (info-only) | +| Accounting | PaymentStatusView | None (reporting) | +``` + +## Quality Checklist + +### Read Model Design +- [ ] Every UI screen maps to read model(s) +- [ ] Every read model has clear purpose +- [ ] Every data field has event source +- [ ] Update logic for each event is explicit +- [ ] All UI needs are covered +- [ ] Processor reads are identified +- [ ] Read model access patterns clear +- [ ] No undocumented data sources +- [ ] Compensation/cancellation handled +- [ ] Error states shown + +### CRITICAL: Event vs Read Model Validation +- [ ] **Reviewed each read model**: "Is this pure calculation or an actual domain fact?" +- [ ] **No aggregations modeled as events**: (totals, averages, counts are read models) +- [ ] **No recalculated state modeled as events**: (if value changes multiple times, it's a read model) +- [ ] **Processor outputs are categorized**: + - [ ] Produces NEW EVENT = actual domain fact (e.g., PaymentAuthorized) + - [ ] Updates READ MODEL = calculation (e.g., SellerRatingCalculated) + - [ ] Sends NOTIFICATION = info-only (no event or model) +- [ ] **History tracking is clear**: Derived state keeps history in read model `history[]`, not as separate events + +## Key Principles + +1. **Event-Driven**: All data comes from events +2. **Projection-Based**: Read models are projections, not persistent +3. **UI-Focused**: Optimized for UI display needs +4. **Processor-Friendly**: Enough data for processor decisions +5. **Completeness**: All needed data available + +## Common Patterns + +### Status View Pattern +``` +Events: Create, Confirm, Process, Ship +ReadModel: Accumulates data from all events +Displayed: Current state reflecting all events +``` + +### List View Pattern +``` +Events: Create, Update, Delete (Cancel) +ReadModel: Summary of each item +Used for: Filtering, sorting, searching +``` + +### Timeline View Pattern +``` +Events: Any event with timestamp +ReadModel: Chronological list +Used for: History, audit trail +``` + +### Processor Decision Pattern +``` +Events: State-changing events +ReadModel: Current state only +Processor reads to decide next action +``` diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-integrating-legacy-systems/SKILL.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-integrating-legacy-systems/SKILL.md new file mode 100644 index 0000000..86b4b8a --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-integrating-legacy-systems/SKILL.md @@ -0,0 +1,675 @@ +--- +name: eventmodeling-integrating-legacy-systems +description: >- + Apply Event Modeling to legacy systems using side-car pattern. Freeze old + system, extract events, build new features without rewriting. Use when + modernizing legacy applications. Do not use for: greenfield systems without + existing legacy constraints (use eventmodeling-orchestrating-event-modeling) + or translating inbound events from external APIs (use + eventmodeling-translating-external-events). +allowed-tools: AskUserQuestion, Write +--- + +# Integrating Legacy Systems + +## Interview Phase (Critical - Not Optional) + +**When to Interview**: This step is high-risk and often initiated prematurely. Always interview unless the user has explicit organizational buy-in for a freeze agreement AND has already assessed legacy system state and extraction feasibility. + +**Interview Strategy**: Assess organizational readiness, understand legacy system constraints, and validate event extraction feasibility before designing the side-car. Poor planning here leads to costly integration failures. + +### Critical Questions + +Always conduct this interview unless all context is provided: + +1. **Legacy System State & Documentation** (Impact: Determines how much reverse-engineering is needed; affects timeline dramatically) + - Question: "Tell me about the legacy system: (A) Technology stack, (B) Age/last major update, (C) Database size/complexity, (D) Current users/traffic, (E) Known documentation or audit trails?" + - Why it matters: Undocumented systems require exploration; modern systems may have better audit logs; scaling affects extraction approach + - Follow-up triggers: If documentation is incomplete → ask for at least data schema; if no audit trail → ask about update_at timestamps; if very large → ask about partitioning strategy + +2. **Organizational Freeze Agreement** (Impact: Most critical—determines if side-car is even feasible) + - Question: "Has business leadership agreed to FREEZE the legacy system? Specifically: (A) No new features in legacy, (B) Only bug fixes permitted, (C) No schema changes?" + - Why it matters: Without explicit freeze, teams keep modifying legacy → events become stale → side-car becomes incorrect → project fails + - Follow-up triggers: If not frozen → ask "What would get stakeholder buy-in for freeze?"; if partially frozen → clarify exact boundaries + +3. **Event Extraction Feasibility** (Impact: Determines if extraction is reverse-engineer-able or if it requires external data) + - Question: "For event extraction: (A) Can you query the legacy database directly, (B) Is there an audit log/change tracking, (C) Will you use CDC (Change Data Capture), (D) Can you modify the legacy system for hooks?" + - Why it matters: Direct query extraction is fastest but may be imperfect; CDC is cleaner but requires infrastructure; modified legacy defeats freeze + - Follow-up triggers: If (A) → ask about query access and schema understanding; if (B) → ask format of audit log; if (C) → discuss CDC tool selection + +4. **Integration Timeline & Staffing** (Impact: Determines realistic phase durations; affects approach choices) + - Question: "What's your timeline? (A) Need new features within 3 months (aggressive), (B) 6-12 months (standard), (C) 18+ months (gradual). And team capacity: (A) Full team on side-car, (B) Part of team, (C) Skeleton crew?" + - Why it matters: Aggressive timeline might skip historical extraction, reducing risk surface; team size affects whether extraction and side-car can happen in parallel + - Follow-up triggers: If aggressive → ask "What's the MVP scope?"; if skeleton crew → ask "Can you backfill?" + +5. **Risk Tolerance & Failure Recovery** (Impact: Determines safety margins and validation rigor) + - Question: "How critical is the system? (A) Revenue-critical/zero downtime tolerance, (B) Important but can tolerate brief outages, (C) Low-risk migration path acceptable?" + - Why it matters: Affects how much validation you need before user cutover; determines rollback strategy importance + - Follow-up triggers: If (A) → propose comprehensive testing and gradual rollout; if (C) → can be more aggressive + +### Interview Flow + +**No Conditional Skip**: This interview is critical. Even if some context is provided, confirm all five dimensions. + +**Phase 1: System Understanding** (Question 1) +- Document legacy system constraints +- Assess documentation gaps +- Plan information gathering + +**Phase 2: Organizational Alignment** (Question 2) CRITICAL +- Confirm freeze agreement (required) +- Document boundaries +- Identify stakeholders + +**Phase 3: Technical Feasibility** (Question 3) +- Validate extraction approach +- Identify data challenges +- Plan extraction strategy + +**Phase 4: Timeline & Staffing** (Questions 4-5) +- Set realistic phases +- Identify team structure +- Plan rollout phases + +### Capturing Interview Findings + +**REQUIRED**: Document findings in detail before proceeding: + +```markdown +## Interview Findings: Legacy System Integration + +**System Overview**: +- Name: [System name] +- Age: [X years] +- Tech: [Stack] +- Scale: [Users/Data size] +- Documentation: [State] + +**Freeze Agreement** CRITICAL +- Status: [Agreed / Pending / Blocked] +- Boundaries: [What's frozen, what's allowed] +- Stakeholders signed off: [Yes/No - names if yes] + +**Event Extraction Approach**: +- Method: [Direct query / CDC / Audit log / Hooks] +- Feasibility: [High / Medium / Low] +- Challenges: [List specific data challenges] + +**Timeline & Staffing**: +- Target completion: [Date] +- Phase 1 duration: [Months] +- Team capacity: [% allocated to project] + +**Risk Assessment**: +- Criticality: [High / Medium / Low] +- Acceptable downtime: [None / Minutes / Hours] +- Rollback strategy: [How to recover if side-car fails] + +**Blockers or Concerns**: +- [Any showstoppers identified] +- [Questions for stakeholders] + +**Green Light Status**: +- [ ] Freeze agreement obtained (REQUIRED) +- [ ] Extraction approach validated (REQUIRED) +- [ ] Team staffing confirmed (REQUIRED) +- [ ] Risk mitigation plan accepted (REQUIRED) + +RECOMMENDATION: [Proceed with side-car / Resolve blockers first / Not recommended at this time - explain why] +``` + +**CRITICAL**: Write findings to the project's event modeling file: + +**File**: `.trogonai/interviews/[project-name]/EVENTMODELING.md` + +Append this section (place it in "Additional Steps" or create new section if legacy integration is primary): + +```markdown +## Legacy System Integration (eventmodeling-integrating-legacy-systems) + +### System Overview +[From Q1] +- Name: [System name] +- Age: [X years] +- Tech: [Stack] +- Scale: [Users/Data size] + +### Freeze Agreement CRITICAL +[From Q2] +- Status: [Agreed / Pending / Blocked] +- Boundaries: [What's frozen] +- Stakeholders: [Signed off: Yes/No] + +### Event Extraction Approach +[From Q3] +- Method: [Direct query / CDC / Audit log / Hooks] +- Feasibility: [High / Medium / Low] +- Challenges: [Data challenges] + +### Timeline & Staffing +[From Q4 & Q5] +- Target: [Date] +- Criticality: [High / Medium / Low] +- Rollback Strategy: [How to recover] + +### Green Light Checklist +- [ ] Freeze agreement obtained (REQUIRED) +- [ ] Extraction approach validated (REQUIRED) +- [ ] Team staffing confirmed (REQUIRED) +- [ ] Risk mitigation accepted (REQUIRED) + +**RECOMMENDATION**: [Proceed / Resolve blockers / Not recommended - why] +``` + +Update Interview Trail with integration-specific findings. + +This section is the risk management document for high-risk integrations. + +--- + +## The Side-Car Pattern + +Instead of rewriting the legacy system, build new features alongside it: + +```text +Traditional Approach (Risky): +Legacy System → Rewrite everything from scratch → New System +Problem: Risk of losing functionality, expensive, long timeline + +Side-Car Approach (Safe): + + Legacy System (Frozen - no new changes) + - Still handles existing features + - Still processes existing users + - No modifications, no new bugs + + + > Database (Event Source) + Query existing data + Extract domain events + + > Event Store (New) + Captured events + New event source of truth + + + Side-Car System (New Event-Modeled Features) + - New functionality using events + - New UI/APIs + - Runs in parallel with legacy + + Contains: + Event Store (primary source of truth) + Commands/Handlers + Read Models + User-facing UIs/APIs + + +Result: Legacy system frozen, new features built safely alongside. +``` + +## Workflow + +### 1. Analyze the Legacy System + +Document what the legacy system does: + +```text +Legacy System: Order Management (10-year-old monolith) + +Current capabilities: + Create orders + Confirm orders + Track shipments + Process refunds + Generate invoices + +Known issues: + No audit trail + Hard to modify order status + Performance degrades with large datasets + No clear separation of concerns + Tightly coupled to specific customer + +Technology: + - Database: MySQL (20+ GB) + - Code: Monolithic Rails application + - API: XML-based SOAP + - Users: 500+ directly using legacy UI + +Cost of rewrite: + - Effort: 6-12 months + - Risk: High (functionality gaps) + - Cost: $500k+ +``` + +### 2. Define the Freeze + +Establish what won't change in the legacy system: + +```text +Freeze Agreement with Business + +We will NOT change: + Legacy UI (users continue using it) + Legacy database schema + Legacy business logic + Legacy APIs + +We WILL do: + Maintain legacy system (bug fixes, support) + Extract events from legacy data + Build new features in side-car + Gradually migrate users to new features + +Benefits: + Zero risk to existing operations + Can start immediately (no design cycle) + Old users continue with familiar UI + New users get modern features + Can integrate both systems gradually + +Timeline: +Year 1: Side-car handles new functionality +Year 2-3: Gradually migrate users +Year 3-4: Phase out legacy system +``` + +### 3. Extract Domain Events from Legacy Data + +The legacy database is your event source: + +```text +Legacy Database Schema: + +Orders table: + id, customer_id, status, created_at, updated_at, items_json, total, ... + +Payments table: + id, order_id, amount, status, gateway_ref, created_at, ... + +Shipments table: + id, order_id, carrier, tracking_num, delivered_at, created_at, ... + +Event Extraction Strategy: + +For Orders table: +When status = 'draft' and record exists + → Extract: OrderCreated event (created_at, items_json, customer_id, ...) + +When status = 'confirmed' and previous was 'draft' + → Extract: OrderConfirmed event + +When status = 'shipped' and previous was 'confirmed' + → Extract: OrderShipped event + +When status = 'cancelled' + → Extract: OrderCancelled event + +For Payments table: +When status = 'authorized' + → Extract: PaymentAuthorized event (amount, gateway_ref, ...) + +When status = 'failed' + → Extract: PaymentFailed event + +For Shipments table: +When delivered_at is populated + → Extract: DeliveryConfirmed event + +Key insight: Legacy tables contain the data that represents events that happened. +We reverse-engineer: State changes → Events. +``` + +### 4. Build Event Capture Pipeline + +Create a process to extract events: + +```text +Option A: One-time Historical Extraction (Catch-up) + +Script: + 1. Query legacy Orders: SELECT * WHERE id > last_extracted_id + 2. For each record, reverse-engineer what events happened + 3. Create events in new Event Store + 4. Continue polling for changes + +Process: + order_id=123, status=confirmed, updated_at=2024-01-15 + → Determine: OrderCreated happened at created_at + → Determine: OrderConfirmed happened at updated_at + → Persist: { OrderCreated, OrderConfirmed } to Event Store + +--- Option B: Real-time Sync (Ongoing) + +Trigger on legacy writes: + 1. When legacy system creates/updates record + 2. Database trigger OR Change Data Capture (CDC) + 3. Event generated and sent to new system + 4. Both systems stay in sync + +Benefits: + - Zero delay between legacy action and event capture + - Can serve new features in real-time + - Cleaner integration + +--- Option C: Hybrid (Start with historical, add real-time) + +Year 1: + - Historical extract existing 10 years of orders + - New events captured in real-time + +Advantage: Smooth onboarding, future-proof +``` + +### 5. Build the Side-Car System + +Create new Event-Modeled system alongside legacy: + +```text +New Side-Car System Architecture: + + + Event Store (Source of Truth for new features) + - OrderCreated + - OrderConfirmed + - PaymentAuthorized + - OrderShipped + - DeliveryConfirmed + - CustomerCreated (new feature) + - ReturnRequested (new feature) + + + > Handlers (Process events) + PaymentProcessor + InventoryProcessor + NotificationProcessor + + > Read Models (Projections) + OrderStatusView + CustomerDashboard (new!) + ReturnStatusView (new!) + + > APIs & UIs (New user-facing) + REST API + GraphQL endpoint + New web UI + Mobile app +``` + +### 6. Handle Y-Valve User Traffic + +Gradually redirect users from legacy to new: + +```text +Phase 1: New features only in side-car +User action → Legacy system handles + +Phase 2: Read model shown alongside legacy +User views → Legacy UI + New dashboards + +Phase 3: New features accessible, legacy still available +User can: Use legacy OR new features +Gradual migration as users opt-in + +Phase 4: Deprecation period +New features required +Legacy features deprecated +Legacy system in read-only mode + +--- Y-Valve Pattern (Traffic Routing): + +User Request + + Is this a NEW feature? → Route to Side-Car system + + Is user opted-in to new UI? → Route to Side-Car system + + Default → Route to Legacy system + +Example code: + if (isNewFeature(request)) { + return sideCarSystem.handle(request); + } else if (user.preferNewUI) { + return sideCarSystem.handle(request); + } else { + return legacySystem.handle(request); + } +``` + +### 7. Develop New Features in Side-Car + +Use Event Modeling for new functionality: + +```text +New Feature: Order Returns & Refunds + +Legacy system has: Nothing (returns handled via email/phone) +New side-car feature: Self-service return management + +Event Model for Returns: +Commands: + - RequestReturn (from customer) + - ApproveReturn (from support agent) + - ProcessRefund (from payment system) + +Events: + - ReturnRequested + - ReturnApproved + - RefundInitiated + - RefundCompleted + +Views: + - ReturnStatusView (by order) + - ReturnQueueView (pending approvals) + - RefundHistoryView (completed refunds) + +Benefits: + Built with modern Event Modeling patterns + Clear contracts + Easy to test + Scalable architecture + No need to modify legacy code +``` + +## Output Format + +Present as: + +```markdown +# Legacy System Integration: [Organization Name] + +## Current Legacy System + +**System Name**: [Name] +**Age**: [Years] +**Technology**: [Tech stack] +**Users**: [Count] +**Database Size**: [Size] + +**Current Capabilities**: +- [Feature 1] +- [Feature 2] + +**Known Issues**: +- [Issue 1] +- [Issue 2] + +**Rewrite Impact**: +- Effort: [Months/Years] +- Risk: [Low/Medium/High] +- Cost: [Estimate] + +--- + +## The Freeze Agreement + +**What we won't change**: +- [Legacy UI] +- [Legacy database] +- [Legacy APIs] + +**What we will do**: +- [Maintain legacy] +- [Extract events] +- [Build new features] + +**Timeline**: +- [Phase 1] +- [Phase 2] +- [Phase 3] + +--- + +## Event Extraction Strategy + +### Source: [Legacy Table/System] + +**Data available**: +- [Field 1] +- [Field 2] + +**Events extracted**: +- [Event 1] when [condition] +- [Event 2] when [condition] + +**Extraction logic**: +[Reverse-engineering approach] + +--- + +## Side-Car System Architecture + +### Events Captured from Legacy +- OrderCreated +- OrderConfirmed +- [Other events...] + +### Events Generated by Side-Car +- CustomerCreated (new feature) +- ReviewSubmitted (new feature) +- [Other new events...] + +### New Features Built +- [Feature 1]: Commands → Handlers → Events → Views +- [Feature 2]: Commands → Handlers → Events → Views + +--- + +## User Migration Plan + +### Phase 1: Read-Only Views +**Timeline**: [Duration] +**Users**: [Gradual rollout] +**Change**: New dashboards available alongside legacy + +### Phase 2: New Features +**Timeline**: [Duration] +**Users**: [% of user base] +**Change**: New functionality accessible, legacy still primary + +### Phase 3: Preference Switch +**Timeline**: [Duration] +**Users**: [Opt-in] +**Change**: Users choose new UI + +### Phase 4: Deprecation +**Timeline**: [Duration] +**Change**: Legacy system read-only + +--- + +## Risks & Mitigations + +| Risk | Mitigation | +|------|-----------| +| Data inconsistency | Event capture validation | +| User confusion | Gradual rollout, clear messaging | +| Operational overhead | Automated monitoring, alerts | +| Performance | Side-car scales independently | + +``` + +## Quality Checklist + +- [ ] Legacy system freeze agreement documented +- [ ] Freeze agreement signed by business stakeholders +- [ ] Event extraction strategy defined for all legacy data +- [ ] All legacy tables mapped to extractable events +- [ ] Event capture pipeline designed +- [ ] Side-car system architecture defined +- [ ] New features scoped clearly +- [ ] User migration plan documented +- [ ] Y-valve routing logic designed +- [ ] Parallel operation testing plan +- [ ] Deprecation timeline agreed +- [ ] Rollback plan in place + +## Common Integration Patterns + +### Pattern 1: Read Models from Legacy +```text +Legacy Database → Query → Extract state → Create Read Model for side-car +Benefit: New UI shows unified data (legacy + new) +``` + +### Pattern 2: Event Stream from Audit Logs +```text +Legacy audit log (if available) → Parse → Extract events → Event Store +Benefit: Complete history, less guesswork +``` + +### Pattern 3: Scheduled Sync +```text +Every N minutes → Query legacy changes → Generate events → Event Store +Benefit: Simple to implement, eventual consistency +``` + +### Pattern 4: Mirror-Write via Integration Boundary (Use with Caution) +```text +Default: Avoid dual-write. Keep side-car-only and sync via legacy events. + +Exception: Dual-write is allowed only with an approved freeze exception. + +Required controls when dual-write is approved: +- Route all writes through a controlled integration boundary (not direct DB access) +- Make every write idempotent (safe to replay on retry or failure) +- Add a reconciliation check and a documented rollback plan +- Document the owner, the sunset date, and the freeze exception approval + +Without these controls: keep side-car-only. +``` + +## Key Principles + +1. **Freeze First**: Establish clear freeze agreement before starting +2. **No Rewrites**: Side-car builds NEW features, doesn't duplicate legacy +3. **Gradual Migration**: Don't force everyone at once +4. **Dual Operation**: Both systems run in parallel indefinitely (your timeline) +5. **Clear Ownership**: Legacy team maintains legacy, side-car team owns new +6. **Event-Driven**: Use events as integration point +7. **User Choice**: Where possible, let users choose when to migrate + +## When Side-Car Is Right + + **Use side-car when**: +- Legacy system works but is hard to modify +- Business needs new features quickly +- Rewrite would take 6+ months +- High risk of rewrite failure +- Users are comfortable with both systems +- Clear separation of old vs. new features + + **Don't use side-car when**: +- Legacy system is broken and needs fixes +- Complete integration required (tight coupling) +- Users only want one unified system +- Legacy holds critical IP that can't be replicated + +## Anti-Patterns to Avoid + + **Hybrid approach**: Trying to modify legacy AND build side-car (confusion) + **Forced unification**: Requiring all users to switch at once (disruption) + **Incomplete event extraction**: Missing important legacy data in events + **Tight coupling**: Side-car depends on legacy database directly (defeats purpose) + **No clear separation**: Users don't know which system they're using (confusion) diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-optimizing-stream-design/SKILL.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-optimizing-stream-design/SKILL.md new file mode 100644 index 0000000..341b9be --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-optimizing-stream-design/SKILL.md @@ -0,0 +1,235 @@ +--- +name: eventmodeling-optimizing-stream-design +description: >- + Design event streams with proper stream identity to keep streams appropriately + sized, avoid unnecessary snapshotting, and balance performance with simplicity. + Use when concerned about stream length, planning performance, or validating + stream design before implementation. Do not use for: designing the initial + event model structure (use eventmodeling-designing-event-models) or + general architectural validation (use eventmodeling-validating-event-models). +allowed-tools: AskUserQuestion, Write +--- + +# Optimizing Stream Design + +## Interview Phase (Optional) + +**When to Interview**: Skip if the user has specified: expected event frequency, stream lifetime, and growth patterns. Interview when stream length concerns exist but growth estimates are unclear. + +**Interview Strategy**: Establish growth expectations and performance requirements before recommending snapshotting. Most snapshotting proposals stem from poor stream boundary design, not genuine volume — surface the estimates first to distinguish real performance concerns from design problems. + +### Critical Questions + +1. **Growth Estimates** (Impact: Determines if snapshotting is needed or if stream design should change) + - Question: "Estimate events: (A) Per entity per day, (B) Lifetime total, (C) Growth over years. Example: 5-10 events/order, 1-10 million orders/year?" + - Why it matters: Growth estimates reveal if streams will genuinely be too long or if design is wrong + - Follow-up triggers: If estimates exceed 300 events per stream lifetime → ask "Is the stream identity correct? Could this stream be split by a narrower business entity?" + +2. **Performance SLAs** (Impact: Determines acceptable latency and snapshotting decisions) + - Question: "Performance requirements? (A) <100ms read latency, (B) <1s acceptable, (C) Eventual consistency OK?" + - Why it matters: Strict SLAs might need snapshotting; loose SLAs often don't + - 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?" + +### Interview Flow + +**Conditional Entry**: +``` +If user has provided: + - Event frequency estimate (per entity per day or per transaction) + - AND stream lifetime estimate (months or years) + - AND read latency SLA (or confirmation that eventual consistency is acceptable) + +Then: Skip interview, proceed directly to stream analysis + +Else: Conduct interview +``` + +**Phase 1: Growth Estimation** (Question 1) +- Establish per-entity event volume +- Project lifetime stream length using the estimation formula +- Determine whether redesign or snapshotting analysis is warranted + +**Phase 2: SLA Requirements** (Question 2) +- Identify read latency requirements per command +- Determine whether read models or direct stream replay satisfies the SLA +- Establish whether snapshotting is justified by SLA alone + +### Capturing Interview Findings + +Append findings to the project's event modeling file: + +**File**: `.trogonai/interviews/[project-name]/EVENTMODELING.md` + +Use Write tool to add/update this section: + +```markdown +## Optimizing Stream Design (eventmodeling-optimizing-stream-design) + +### Growth Estimates +[From Q1: Events per entity per day, lifetime total, annual growth] + +### Performance SLAs +[From Q2: Latency requirements per command or view] + +### Optimization Decisions +- Streams requiring redesign: [list or "None"] +- Streams where snapshotting is justified: [list or "None"] +- Streams within acceptable bounds: [list] +``` + +Update Interview Trail: +```markdown +| Optimization | eventmodeling-optimizing-stream-design | Done | Stream growth estimates, SLA review, snapshotting decisions | +``` + +--- + +## Stream Design Optimization + +**Purpose**: Optimize event stream design by validating stream boundaries, estimating growth, and making snapshotting decisions based on design quality—not just size. + +**Applies To**: Any domain - e-commerce, banking, SaaS, marketplace, healthcare, etc. + +**When to Use**: +- After defining event streams in domain analysis +- When concerned about stream length or performance +- Before implementing to validate stream design +- During performance planning to determine snapshotting strategy +- When redesigning streams for scalability + +**What It Does**: +1. Analyzes event stream design for proper event organization +2. Estimates stream growth over time +3. Identifies when snapshotting is genuinely needed vs. design issue +4. Recommends optimal stream identity boundaries +5. Balances performance optimization against complexity +6. Provides snapshotting strategy without over-engineering + +--- + +## Core Principle: Design First, Snapshot Second + +**Golden Rule**: +> If you find yourself needing to snapshot because the stream is too long, first ask: "Is my stream identity wrong?" Usually, the answer is yes. + +Snapshotting is a **performance optimization**, not a design problem. Good stream design (proper identity boundaries) often eliminates the need for snapshotting entirely. + +--- + +## Stream Design Analysis Framework + +### 1. Estimate Stream Growth + +**Formula**: +``` +Estimated Stream Length (total events/instance) = +Events Per Aggregate Instance Per Year (events/instance/year) + × Lifetime of Instance (years) + × Annual Growth Factor (dimensionless year-over-year multiplier ≥ 1.0) +``` + +**Quick Examples**: + +**E-commerce Order**: 8 events/year × 1.5 year lifetime = 8-16 events → NOT NEEDED + +**Banking Account**: 100-200 events/year × 10 years = 1000-2000 events → CONSIDER AT 1000+ + +**Order Processing**: 100+ events/year × 5 years = 300-500+ events → PROBABLY NEEDED + +**SaaS User**: 12-60 events/year × 5 years = 60-300 events → RARELY NEEDED + +### 2. Identify Stream Length Categories + +| Length | Status | Action | Snapshotting | +|--------|--------|--------|--------------| +| < 50 events | IDEAL | Keep as-is | NOT NEEDED | +| 50-100 events | GOOD | Monitor growth | NOT NEEDED | +| 100-300 events | ACCEPTABLE | Review boundary | CONSIDER if replayed | +| 300-1000 events | LONG | REDESIGN first | Only last resort | +| 1000+ events | CRITICAL | REDESIGN required | Won't help | + +--- + +## Quick Decision Matrix + +| Stream Length | Read Pattern | Frequency | Action | +|---|---|---|---| +| < 50 | Any | Any | IDEAL - Keep as-is | +| 50-100 | Any | Any | Good - Monitor | +| 100-300 | From Model | Any | OK - No snapshot | +| 100-300 | Stream Replay | Low | OK - Monitor | +| 100-300 | Stream Replay | High | REDESIGN | +| 300-1000 | From Model | Any | OK - No snapshot | +| 300-1000 | Stream Replay | Any | REDESIGN | +| 1000+ | Any | Any | CRITICAL - REDESIGN | + +--- + +## Reference Files + +**Aggregate Boundary Design**: See [patterns.md](references/patterns.md) for: +- 5 aggregate patterns (single entity, composite, collections, event logs, historical) +- Stream size decision tree +- Red flags that indicate redesign needed +- Tips for optimal stream design + +**Snapshotting Strategy**: See [snapshotting.md](references/snapshotting.md) for: +- Criteria for when snapshotting is truly needed +- Context-based decision thresholds +- Snapshot frequency, versioning, and cleanup strategies +- Cost-benefit analysis + +**Domain-Specific Guidance**: See [domain-patterns.md](references/domain-patterns.md) for: +- E-commerce patterns (orders, carts, accounts) +- Banking patterns (accounts, transactions, loans) +- SaaS patterns (subscriptions, workspaces, data collections) +- Implementation checklist + +--- + +## Key Insights + +### Why Snapshotting Usually Isn't the Answer + +``` +Before implementing snapshotting, ask: + +1. Can I split this aggregate into smaller ones? + → YES: Do that instead. Simpler, better design. + +2. Can I reduce event granularity? + → YES: Batch events or create coarser state changes. + +3. Am I using a read model for this aggregate? + → NO: Create a read model (cached projection). + Stream size becomes irrelevant. + +4. Have I measured actual replay latency? + → NO: Measure first. Most systems exceed expectations. + +If ANY of these is YES, do that before snapshotting. +Only after exhausting design improvements, consider snapshots. +``` + +### The Snapshotting Trade-off + +``` +Snapshotting Complexity ≈ 2-3x Complexity of Better Design + +Before snapshot: 50 lines of code, simple, testable +With snapshots: 150+ lines, versioning, recovery logic, testing matrix + +Better to redesign and keep streams < 300 events. +``` + +--- + +## Quality Checklist + +- [ ] Each stream is identified by a business entity identity (e.g., `orderId`), not a category or type +- [ ] No stream grows unboundedly without a design reason — event frequency and stream lifetime estimated +- [ ] Streams under 1000 events require no snapshotting justification +- [ ] If snapshotting is proposed, all simpler alternatives (split stream, shorter lifetime) have been eliminated first +- [ ] Command handler state is reconstructed from stream events — no persistent state stored outside the stream +- [ ] Each stream can be independently versioned and replayed without affecting other streams + diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-optimizing-stream-design/references/domain-patterns.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-optimizing-stream-design/references/domain-patterns.md new file mode 100644 index 0000000..2f326d7 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-optimizing-stream-design/references/domain-patterns.md @@ -0,0 +1,150 @@ +# Domain-Specific Stream Size Patterns + +## Contents +- E-commerce patterns +- Banking patterns +- SaaS patterns +- Implementation checklist + +--- + +## E-commerce Domain + +**Order Aggregate**: +``` +Events: 5-20 +Lifetime: 1-3 years +Frequency: 1 event per few days +Stream Length: 8-60 events +Snapshotting: NOT NEEDED +Reason: Short entity lifetime, low frequency, few state changes +``` + +**Shopping Cart Aggregate**: +``` +Events: 5-50+ (add/remove items many times) +Lifetime: 30 minutes to 2 years (varies widely) +Frequency: 1-10 events per hour (if active) +Stream Length: 10-500+ events (depends on user behavior) +Snapshotting: RARELY (only for frequent shoppers) +Strategy: Split abandoned vs. active carts if too long +``` + +**User Account Aggregate**: +``` +Events: 2-10 per year (profile updates, settings changes) +Lifetime: 5-10+ years +Frequency: Very low (events measured in months apart) +Stream Length: 10-100 events +Snapshotting: NOT NEEDED +Reason: Infrequent events, long lifetime, many separate streams +``` + +--- + +## Banking Domain + +**Account Aggregate**: +``` +Events: 50-500+ per year (deposits, withdrawals, fees) +Lifetime: 10-50+ years +Frequency: 0.1-2 events per day +Stream Length: 500-25,000+ events +Snapshotting: MAYBE (at 5000+) +Strategy: Consider splitting by time period or account type +Alternative: Snapshotting might be justified for regulatory access needs +``` + +**Transaction Aggregate**: +``` +Events: 1-5 (Requested → Processing → Settled) +Lifetime: 1-2 months (then archived) +Frequency: Single transaction, short lifecycle +Stream Length: 2-5 events +Snapshotting: NEVER NEEDED +Reason: Tiny, immutable after completion +``` + +**Loan Aggregate**: +``` +Events: 100-500+ (payments, rate changes, modifications) +Lifetime: 5-30 years +Frequency: 1-5 events per month +Stream Length: 1000-10,000+ events +Snapshotting: CONSIDER AT 5000 +Strategy: Split by loan product, payment period, or status +Example: ActiveLoan vs. CompletedLoan aggregates +``` + +--- + +## SaaS Domain + +**Subscription Aggregate**: +``` +Events: 2-20 (Created, Upgraded, Downgraded, Cancelled) +Lifetime: 1-5+ years +Frequency: 1-5 events per year +Stream Length: 5-100 events +Snapshotting: NOT NEEDED +Reason: Low frequency, well-defined lifecycle +``` + +**User Workspace Aggregate**: +``` +Events: 10-100+ (members added, roles changed, settings updated) +Lifetime: 2-5+ years +Frequency: 0.5-5 events per month +Stream Length: 10-500 events +Snapshotting: NOT NEEDED +Reason: Moderate frequency, small discrete events +``` + +**Data Collection Aggregate**: +``` +Events: 100-10,000+ (data points added, processed, analyzed) +Lifetime: 1-5+ years +Frequency: 1-1000+ events per day (varies wildly) +Stream Length: 100-50,000+ events +Snapshotting: PROBABLY +Strategy: Split by data type, time period, or processing stage +Question: Are all these events about the same business entity? + → If NO, split the aggregate + → If YES, snapshotting might be needed +``` + +--- + +## Implementation Checklist + +Before implementing snapshotting, answer ALL of these: + +``` +Design Questions: +[ ] Does this aggregate have a single business identity? +[ ] Can I split this into smaller aggregates? +[ ] Are there natural lifecycle phases (archived vs. active)? +[ ] Is event granularity appropriate (not too fine)? + +Performance Questions: +[ ] Have I measured replay latency? +[ ] Does latency exceed acceptable threshold? +[ ] Is the problem snaphotting will solve? +[ ] Or is it a design problem? + +Cost-Benefit Questions: +[ ] How many writes per second? +[ ] How many reads per second? +[ ] What's the read latency requirement (SLA)? +[ ] Is snapshotting complexity worth the benefit? + +Operational Questions: +[ ] How will I version snapshots? +[ ] How will I test snapshot recovery? +[ ] How will I monitor snapshot health? +[ ] Can I implement this given current skills? +``` + +**If ANY question suggests redesign is better**: Redesign first, snapshot never. + +**If ALL questions support snapshotting**: Proceed with implementation. diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-optimizing-stream-design/references/patterns.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-optimizing-stream-design/references/patterns.md new file mode 100644 index 0000000..cc9c284 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-optimizing-stream-design/references/patterns.md @@ -0,0 +1,329 @@ +# Aggregate Boundary Design Patterns + +## Contents +- Aggregate Boundary Design Patterns (5 patterns with examples) +- Stream Size Decision Tree +- Red Flags: Redesign Needed +- Tips for Optimal Stream Design + +--- + +## Aggregate Boundary Design Patterns + +### Pattern 1: Single Entity (Most Common) + + CORRECT: One aggregate per entity +``` +Aggregate: Order +Root Identity: orderId (e.g., 'order-123') +Entity: The specific order +Lifetime: 1-2 years + +Events in stream: + 1. OrderCreated (2024-01-15) + 2. OrderLineAdded (2024-01-15) + 3. OrderLineAdded (2024-01-15) + 4. OrderConfirmed (2024-01-16) + 5. PaymentProcessed (2024-01-16) + 6. OrderShipped (2024-01-20) + 7. OrderDelivered (2024-01-25) + +Stream Length: 7 events +Snapshotting: NOT NEEDED + +Identity Principle: orderId is the natural business key +Boundary: Everything about THIS specific order, nothing else +Consistency: Only one order being modified at a time +``` + +--- + +### Pattern 2: Composite Entity (Proper Composition) + + CORRECT: Aggregate contains related child entities +``` +Aggregate: Order +Root Identity: orderId (e.g., 'order-456') + +Contains related children (same lifetime): + - OrderLines: 3 items + * Line 1: productId=prod-A, qty=2, price=$50 + * Line 2: productId=prod-B, qty=1, price=$100 + * Line 3: productId=prod-C, qty=5, price=$10 + + - ShippingAddress: + street: 123 Main St, City: Portland, State: OR + + - PaymentInfo: + method: credit_card, amount: $400 + +Events in stream: + 1. OrderCreated (customer-789, 3 items) + 2. OrderLineAdded (item 1) + 3. OrderLineAdded (item 2) + 4. OrderLineAdded (item 3) + 5. OrderConfirmed (payment method selected) + 6. PaymentProcessed (authorization complete) + 7. OrderShipped (tracking 123456) + +Stream Length: 7 events +Snapshotting: NOT NEEDED (well under 1000) + +Pattern: Small, bounded number of children per parent +Lifetime: Parent and all children created/destroyed together +Consistency: All modified as a unit (can't ship without payment, etc.) +``` + +--- + +### Pattern 3: Collection (ANTI-PATTERN - DO NOT USE) + + WRONG: Treating a collection as aggregate +``` +Bad Aggregate: AllOrders +Root Identity: "all-orders-collection" (artificial, meaningless) + +Contains: Every order ever created +Events: + 1. OrderCreated (customer-001, order-001) + 2. OrderCreated (customer-002, order-002) + 3. OrderCreated (customer-001, order-003) + 4. OrderCreated (customer-003, order-004) + ... (continues forever, unbounded) + +Month 1: 50,000 events +Year 1: 600,000 events +Year 5: 3,000,000 events + +Stream Length: 1,000,000+ events +Snapshotting: Doesn't help - design is fundamentally wrong + +Problems with this approach: + - No single business identity (it's a collection, not an entity) + - Stream grows unbounded (can never achieve performance SLA) + - Snapshotting won't fix it (snapshot is also 1M+ events) + - Can't split or scale + - Every write goes to same stream (contention) + +Solution: Use a projection/read model query instead, not an aggregate + - Query: "GetAllOrdersByCustomer(customer-id)" + - Query: "GetOrdersByStatus(status)" + - Rebuild from individual Order streams on-demand +``` + +--- + +### Pattern 4: Event Log (ANTI-PATTERN - DO NOT USE) + + WRONG: Using aggregate as event log +``` +Bad Aggregate: SystemLog +Root Identity: "system-log" (meaningless placeholder) + +Contains: Every system event imaginable +Events: + 1. UserLoggedIn (user-123) + 2. OrderCreated (order-456) + 3. PaymentProcessed (payment-789) + 4. InventoryUpdated (sku-101) + 5. UserLoggedOut (user-123) + 6. UserLoggedIn (user-223) + ... (grows indefinitely, no pattern) + +Per Day: 100,000+ events +Per Year: 36,500,000+ events + +Stream Length: 10,000,000+ events +Snapshotting: Impossible - design is fundamentally broken + +Problems with this approach: + - No business identity (log of everything) + - Events unrelated to each other (mixing user, order, payment, inventory) + - No consistency boundary (user login != order creation) + - Can't answer "what's the state of X?" (too mixed) + - Contention: every subsystem writing to same stream + - Can't replay meaningfully (mixed concerns) + +Solution: Use separate event logs or time-series database + - Keep dedicated event streams: Order, Payment, Inventory, User + - Use time-series DB for metrics/logs: Prometheus, DataDog, ELK + - Query system logs separately from domain events +``` + +--- + +### Pattern 5: Historical Aggregate (GOOD - When Needed) + + CORRECT: Keep historical data for audit/compliance +``` +Aggregate: ArchivedOrder +Root Identity: archivedOrderId (e.g., 'archived-order-001') +Purpose: Regulatory compliance (7-year retention) + +Contains: Snapshot + audit trail of an order +Events: + 1. OrderArchived (original order-123 on 2023-12-31) + - reason: compliance_retention + - originalData: { id, customerId, items, total, dates } + + 2. AuditLogAdded (accessed by accounting, 2024-01-15) + - accessor: accounting@company.com + - action: viewed for tax audit + + 3. AuditLogAdded (accessed by auditor, 2024-02-01) + - accessor: auditor@firm.com + - action: reviewed for compliance + + ... (additional audit entries over time) + +Lifetime: 7 years (regulatory requirement) +Stream Length: 500-2000 events (audit entries added slowly) +Snapshotting: Not needed (historical, not active) + +Key architectural principles: + - Completely separate from active Order aggregate + - Active Order is for current business operations + - Archived Order is immutable historical record + - Different access patterns, different SLAs +``` + +--- + +## Stream Size Decision Tree + +Use this to decide if your streams are properly designed: + +``` +Does your stream have a natural business identity? + NO → This is not an aggregate, it's a log/report + SOLUTION: Use read model/projection, not aggregate + + YES → How many events does it accumulate? + + < 100 events + PERFECT: No optimization needed + + 100-1000 events + Is it growing because of high frequency? + NO → GOOD: Probably well-designed + YES → MONITOR: Watch for growth + + Does each event represent a meaningful state change? + YES → GOOD: Healthy stream + NO → REDESIGN: Too granular events + + 1000-5000 events + Can you split this aggregate? + YES → REDESIGN: Do it now + Examples: User → UserProfile + UserSessions + Order → Order + OrderLineItems + + NO → Is read frequency high (> 10/sec)? + YES → Consider snapshotting at 5000 + NO → ACCEPTABLE: Leave as-is + + Is latency critical (< 100ms)? + YES → MONITOR: Measure replay time + NO → ACCEPTABLE: No snapshotting needed + + 5000-10000 events + This is a design problem → REDESIGN + OR business justifies complexity → Snapshot at 5000 + + Questions before snapshotting: + Can I split aggregate? (usually YES) + Can I reduce event granularity? (sometimes) + Am I using a read model for this aggregate? (maybe not) + If all NO → Then snapshot is justified + + > 10000 events + CRITICAL: Redesign required + This is NOT a properly designed aggregate + Snapshotting won't save you + Root cause: Aggregate boundary is wrong +``` + +--- + +## Red Flags: Redesign Needed (Not Snapshotting) + +If your stream exhibits ANY of these, snapshotting won't help—you need to redesign: + +``` + Red Flag 1: Stream growing > 1000 events/day + Cause: Events are too granular + Solution: Batch events or coarsen granularity + Example: "UserClickedButton" → "UserCompletedTask" (higher level) + + Red Flag 2: Thousands of events but no business meaning + Cause: Treating log as aggregate + Solution: Use read model/query instead of aggregate + Example: "SystemMetricRecorded" → Use time-series database + + Red Flag 3: Stream contains unrelated entities + Cause: Aggregate boundary is wrong + Solution: Split into separate aggregates + Example: "AllOrders" → "Order" per customer + + Red Flag 4: Snapshot is 80% of the stream size + Cause: Snapshot isn't helping + Solution: Re-examine aggregate boundary + Example: If snapshot is 800 events and deltas 100, redesign + + Red Flag 5: Can't explain what business question the stream answers + Cause: Not a real aggregate + Solution: Convert to read model/projection + Example: "SystemEvents" → Query specific streams + + Red Flag 6: Stream length doubles every 6 months + Cause: Exponential growth pattern + Solution: Likely aggregate boundary issue + Example: Split by time period: 2024-Orders vs. 2025-Orders +``` + +--- + +## Tips for Optimal Stream Design + +### 1. Favor Redesign Over Snapshotting +``` +Cost: Redesign effort < Snapshotting maintenance +Quality: Better design > Better optimization +Future: Smaller streams are easier to scale +``` + +### 2. Understand Event Granularity +``` + RIGHT: One event per meaningful state change + WRONG: Multiple events per semantic operation +Example: "UserUpdatedProfile" (1 event) +NOT: "FirstNameChanged", "LastNameChanged", ... (N events) +``` + +### 3. Split When Possible +``` + AllOrders (growing unbounded) + Order (per order) + OrderLine (per line item) + + UserAccount (everything about user) + UserProfile (personal info) + UserPreferences (settings) + UserSessions (login history) +``` + +### 4. Archive Old Data +``` + Keep everything in active aggregate + Move completed/closed data to archive aggregate +Example: + - ActiveSubscription (current state) + - ArchivedSubscription (after cancelled) +``` + +### 5. Measure Before Optimizing +``` + Assume snapshotting is needed + Measure replay latency first + Only snapshot if measurement justifies it +``` diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-optimizing-stream-design/references/snapshotting.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-optimizing-stream-design/references/snapshotting.md new file mode 100644 index 0000000..d2eed81 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-optimizing-stream-design/references/snapshotting.md @@ -0,0 +1,204 @@ +# Snapshotting Strategy + +## Contents +- Criteria for Snapshotting +- Context-Based Decision Thresholds +- Snapshotting Downsides +- Snapshot Frequency & Versioning +- Snapshot Cleanup Strategies + +--- + +## When Snapshotting is Actually Needed + +### Conservative First Approach: Keep Streams Short + +**Default Principle**: Prefer shorter streams over snapshotting +- Shorter streams = simpler code, easier debugging, fewer bugs +- Snapshotting = added complexity that's hard to get right +- Most systems don't actually need snapshotting if designed well + +### Criteria: Snapshotting Only When ALL Are True + +``` +1. Stream length > 100 events (conservative default) AND +2. You've measured latency and it exceeds SLA AND +3. The latency problem IS stream replay (not read model) AND +4. Aggregate boundary is already optimal (can't split further) AND +5. You have operational capability to maintain snapshots +``` + +**If ANY criteria fail**: Don't snapshot. Redesign instead. + +### Context-Based Thresholds (Ask These Questions) + +Instead of assuming a fixed number, ask about your actual business context: + +**Question 1: How is this aggregate read?** +``` +"From stream replay" (loaded every time) + → Conservative threshold: 50-100 events + → Reason: Replay latency compounds + +"From read model/cache" (projection loaded once) + → Conservative threshold: Not relevant (stream size doesn't matter!) + → Reason: You're not replaying on each read +``` + +**Question 2: What's your read latency requirement?** +``` +"Immediate/real-time" (< 50ms, user-facing) + → Conservative threshold: 50 events max + → Reason: Strict SLA, no room for slowness + +"Normal web response" (100-500ms, typical page load) + → Conservative threshold: 100-300 events + → Reason: Some latency acceptable if not critical path + +"Background/batch operations" (seconds to minutes) + → Conservative threshold: Not a concern + → Reason: Speed doesn't matter for batch work +``` + +**Question 3: How often is this aggregate read?** +``` +"Very frequent" (> 100 reads/second) + → Use threshold ÷ 5 (contention matters more) + → Reason: Concurrent replays degrade badly + +"Normal frequency" (1-10 reads/second) + → Use stated threshold + → Reason: Single-digit concurrency manageable + +"Rare" (< 1 read per minute) + → Use threshold × 2-3 (who cares about latency?) + → Reason: Speed doesn't matter if rarely accessed +``` + +### If User Doesn't Know (Most Common Case) + +**Guidance**: Be conservative AND use conversation context +``` +Default position: + → Start with 100 events as safe threshold + → This prevents 90% of problems + → Better to redesign early than add snapshotting later + +If user says "I don't know my requirements": + → Use context from earlier conversation + → Review: What did domain analysis say? + → Check: What's the business criticality? + → Ask: Is this user-facing or backend? + +Example Decision Logic: +Domain: E-commerce (user-facing) + No explicit SLA + → Use 100-event threshold (conservative for user-facing) + +Domain: Bank transfers (critical) + No explicit SLA + → Use 50-event threshold (very conservative, safety margin) + +Domain: Analytics (batch) + No explicit SLA + → Use 1000+ threshold (performance doesn't matter) +``` + +--- + +## Snapshotting Downsides to Consider + +``` +Complexity Cost: + - Extra code path (snapshot loading logic) + - Testing complexity (snapshot + delta replay) + - Snapshot versioning challenges + - Potential for bugs in snapshot recovery + +Operational Cost: + - Storage overhead (original events + snapshots) + - Cleanup and archival strategies + - Debugging difficulty (was it the snapshot?) + - Migration burden if snapshot format changes + +Performance Cost: + - Snapshot creation cost + - Storage I/O for snapshots + - Memory usage during snapshot loading + - Synchronization between events and snapshots + +Rule of Thumb: +Complexity of snapshotting ≈ 2-3x complexity of solving with better design +``` + +--- + +## Snapshotting Strategy (When Actually Needed) + +### If You Decide Snapshotting is Necessary: + +#### Snapshot Frequency Decision: + +``` +Rule: Snapshot every N events where N = √(Total Estimated Events) + +Example: +If stream will eventually reach 10,000 events: +N = √10,000 = 100 +Snapshot every 100 events +Result: 100 snapshots + max 100 events to replay = manageable + +If stream reaches 100,000 events (red flag): +N = √100,000 = 316 +Snapshot every 316 events +Result: 316 snapshots = storage issue, redesign needed +``` + +**Better Rule**: Snapshot when read latency exceeds acceptable threshold + +``` +Measure: +1. Measure event replay time for current stream length +2. If > acceptable latency (e.g., 50ms), snapshot +3. Snapshot frequency = whatever makes latency acceptable +4. Re-measure after snapshot implementation + +Example: +- Stream: 2000 events +- Replay time: 120ms (acceptable if reads are occasional) +- Snapshot needed? NO +- Decision: Monitor, implement snapshotting only if latency > 200ms +``` + +#### Snapshot Versioning: + +``` + DON'T: Version snapshots, migrate old formats + DO: Version aggregates instead + +Pattern: +Aggregate Version 1: Stream 1 +Aggregate Version 2: New Stream with different structure + +Reason: Snapshots are just optimization, not part of model + If snapshot format needs to change, it means your aggregate changed + → Create new aggregate version with new stream instead +``` + +#### Snapshot Cleanup: + +``` + Good Strategy: Snapshot + Event Log + - Keep original events (immutable, source of truth) + - Keep snapshots (performance optimization) + - No special cleanup needed (both are authoritative together) + + Bad Strategy: Snapshot + Purge Old Events + - Destroys event history + - Makes auditing impossible + - Complicates recovery + - Only do if regulatory rules require it + + Alternative: Archive Old Events + - Keep all events for audit trail + - Archive to slower storage if needed + - Snapshot in hot storage for performance + - Best of both worlds +``` diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-orchestrating-event-modeling/SKILL.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-orchestrating-event-modeling/SKILL.md new file mode 100644 index 0000000..21f4477 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-orchestrating-event-modeling/SKILL.md @@ -0,0 +1,226 @@ +--- +name: eventmodeling-orchestrating-event-modeling +description: >- + Orchestrates complete event modeling workflow from requirements to code + generation. Models architecture as UI/Processor → Command → Event → Read + Model. Use when modeling a domain end-to-end from requirements. Do not use + for: executing a single step in isolation (invoke the named step skill + directly, e.g., eventmodeling-brainstorming-events for Step 1 or + eventmodeling-elaborating-scenarios for Step 7), validating an + already-completed model (use eventmodeling-validating-event-models), or + modernizing legacy systems (use eventmodeling-integrating-legacy-systems). +allowed-tools: AskUserQuestion, Write +--- + +# Orchestrating Event Modeling + +Coordinates the 9-step Event Modeling workflow. Each step delegates to a +specialized skill — this skill holds the sequence, transition conditions, and +what to carry forward between steps. + +--- + +## Interview Phase + +**Skip if**: user has provided a clear domain description, requirements or +scope, and stated output goal (code, design, learning, docs). + +**When interviewing**, use AskUserQuestion: + +1. **Domain** — "What are you modeling? Describe the business process in 2-3 + sentences." +2. **Requirements state** — "(A) Written requirements/user stories, (B) Rough + ideas, (C) Existing system to reverse-engineer?" +3. **Goal** — "(A) Learning event modeling, (B) Generate production code, + (C) Design validation, (D) Team documentation?" +4. **Constraints** — "Any constraints? (timeline, external integrations, team + size, target language/framework)" +5. **Starting point** — "Are you starting from scratch, or do you already have + outputs from earlier steps (event list, commands, scenarios)?" + +Confirm understanding before proceeding: "So we're modeling [domain], goal is +[goal], constraints are [constraints]. Starting from [step]. Does that match?" + +**Capture findings** — write to `.trogonai/interviews/[project-name]/EVENTMODELING.md`: + +```markdown +# Event Modeling: [Project Name] + +**Project**: [project-name] +**Started**: [ISO date] +**Goal**: [learning / production code / design validation / documentation] +**Constraints**: [timeline, integrations, team size, language] + +## Interview Trail + +| Step | Skill | Status | Key Output | +|------|-------|--------|------------| +| Orchestration | eventmodeling-orchestrating-event-modeling | Done | Domain scoped, starting point confirmed | +``` + +Update this file as each step completes. + +--- + +## Mid-Workflow Entry + +If the user already has outputs from earlier steps, start from where they are. +Ask which steps are complete and what artifacts exist. Do not re-run completed +steps — pick up from the first incomplete step. + +--- + +## Workflow + +### Step 1: Brainstorm Events + +Invoke `eventmodeling-brainstorming-events`. + +**Input**: Domain requirements and any existing knowledge about the domain. +**Output to carry forward**: Event list + Role Catalog. The Role Catalog (all +human roles and system actors) feeds into every subsequent step. +**Gate**: Do not proceed until the Role Catalog exists and events cover all +known business processes. + +--- + +### Step 2: Plot Events + +Invoke `eventmodeling-plotting-events`. + +**Input**: Event list from Step 1. +**Output to carry forward**: Chronological event timeline showing causal +dependencies between events. +**Gate**: Timeline should read as a coherent narrative before proceeding. + +--- + +### Step 3: Storyboard + +Invoke `eventmodeling-storyboarding-events`. + +**Input**: Event timeline + Role Catalog. +**Output to carry forward**: UI mockups/wireframes with one swimlane per +human role, showing what data each screen displays and collects. +**Gate**: Every human role from the Role Catalog has at least one screen. + +--- + +### Step 4: Identify Inputs + +Invoke `eventmodeling-identifying-inputs`. + +**Input**: Storyboards + Role Catalog. +**Output to carry forward**: Command definitions, each attributed to a specific +role or system processor. +**Gate**: Every UI action in the storyboards maps to a named command. + +--- + +### Step 5: Identify Outputs + +Invoke `eventmodeling-identifying-outputs`. + +**Input**: Event list + Commands from Step 4. +**Output to carry forward**: Read model definitions — projections of events +optimized for UI and processor queries. +**Gate**: Every screen data need from the storyboards is satisfied by a read +model. + +--- + +### Step 6: Apply Conway's Law + +Invoke `eventmodeling-applying-conways-law`. + +**Input**: Full event model so far (events, commands, read models). +**Output to carry forward**: System swimlanes mapping events and commands to +team boundaries. +**Gate**: Each boundary can be independently owned by a team. Skip this step +if Conway's Law boundaries are not relevant to the project. + +--- + +### Step 7: Elaborate Scenarios + +Invoke `eventmodeling-elaborating-scenarios`. + +**Input**: Commands and read models. +**Output to carry forward**: Given-When-Then specifications for each command +and view, including happy paths, validation failures, and edge cases. +**Gate**: At least one scenario per command before proceeding. + +--- + +### Step 8: Check Completeness + +Invoke `eventmodeling-checking-completeness`. + +**Input**: Full model — events, commands, read models, scenarios, Role Catalog. +**Output to carry forward**: Field traceability matrix confirming every field +has an origin and a destination. List of any gaps found. +**Gate**: All gaps resolved or explicitly accepted before proceeding. + +--- + +### Step 9: Validate + +Invoke `eventmodeling-validating-event-models`. + +**Input**: Complete event model. +**Output**: Validation report with PASS / PASS WITH WARNINGS / FAIL verdict. +**Gate**: PASS verdict before declaring the model ready for implementation. + +If FAIL: address findings and re-invoke `eventmodeling-validating-event-models`. + +**Optional — Production Readiness Checklist**: Invoke +`eventmodeling-validating-event-models-checklist` when the model is destined +for production. It runs 23 architectural checks across 7 phases and returns a +PASS / PASS WITH WARNINGS / FAIL verdict independently of Step 9. A PASS on +Step 9 does not substitute for this checklist when production readiness is +required. + +--- + +## Final Output + +A complete event model consisting of: +- Role Catalog (human roles and system actors with permissions) +- Chronological event timeline +- UI storyboards with role-based swimlanes +- Command definitions with actor attribution +- Read model designs +- System boundaries (if Conway's Law applied) +- Given-When-Then scenarios +- Completeness verification +- Validation report with readiness verdict + +### Optional Follow-on Skills + +These skills are not part of the 9-step main path but extend the model for +specific needs: + +- **`eventmodeling-designing-event-models`** — Use when stream identity, + per-command state shapes, or event causality need detailed design work. Can + be applied at any step where those decisions arise, most commonly during or + after Step 1. +- **`eventmodeling-optimizing-stream-design`** — Use after the model is + complete to validate stream growth estimates and snapshotting decisions. +- **`eventmodeling-translating-external-events`** — Use when external systems + (webhooks, IoT, third-party APIs) need to feed into the domain model. +- **`eventmodeling-slicing-event-models`** — Use after Step 9 PASS to break + the model into independently deployable feature slices and plan parallel + team implementation. + +--- + +## Quality Checklist + +- [ ] All 9 modeling steps completed — no step skipped without explicit reason +- [ ] Role Catalog exists with named human roles and system processors +- [ ] Every command is attributed to a specific role from the Role Catalog +- [ ] Every read model satisfies at least one UI or processor query need +- [ ] At least one Given-When-Then scenario exists per command +- [ ] Completeness check shows no unresolved field traceability gaps +- [ ] Validation returns PASS or PASS WITH WARNINGS with all critical issues resolved +- [ ] Interview trail in `.trogonai/` updated with status of each completed step diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-orchestrating-event-modeling/references/project-planning-with-event-modeling.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-orchestrating-event-modeling/references/project-planning-with-event-modeling.md new file mode 100644 index 0000000..984c269 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-orchestrating-event-modeling/references/project-planning-with-event-modeling.md @@ -0,0 +1,341 @@ +# Project Planning with Event Modeling + +## Overview + +One of the most significant benefits of Event Modeling is the **flat cost curve** for features. Unlike traditional development where each new feature becomes increasingly complex and expensive, Event Modeling enables teams to deliver features at a consistent cost. + +## The Flat Cost Curve + +### Traditional Development Cost Pattern + +``` +Feature Cost + ^ + Feature 3 (hardest, most expensive) + /\ + / \ + / \ + / Feature 2 (harder, expensive) + / /\ + / / \ + / / \ + / Feature 1 / + /____/\______/_____ Time + +Problem: Cost increases with each feature + - Feature 1: 2 weeks, 2 people + - Feature 2: 4 weeks, 3 people + - Feature 3: 8 weeks, 5 people + +Reason: Increasing technical debt and coupling +``` + +### Event Modeling Cost Pattern + +``` +Feature Cost + ^ + Feature 1 Feature 2 Feature 3 Feature 4 + /\ /\ /\ /\ + / \ / \ / \ / \ + / \ / \ / \ / \ + /______\ /______\ /______\ /______\___ Time + +Consistent: Each feature = ~2 weeks, ~2 people + +Reason: Clear contracts between steps enable parallel work +``` + +### Why the Flat Curve? + +The article explains: + +> "The biggest impact of using Event Modeling is the flat cost curve of the average feature cost. This is due to the fact that the effort of building each workflow step is not impacted by the development of other workflows." + +**Key Insight**: When you have explicit contracts, teams can work independently. + +``` +Team A builds Step 1 (Create Order) + - Produces: OrderCreated event with specific fields + - Contract: "If OrderCreated exists, these fields are guaranteed" + +Team B builds Step 2 (Confirm Order) + - Precondition: OrderCreated event exists + - Can start IMMEDIATELY while Team A finishes + - Mocks OrderCreated event in tests + - When Step 1 ready, tests pass immediately + +Team C builds Step 3 (Authorize Payment) + - Precondition: OrderConfirmed event exists + - Can start immediately + - Works independently + +Result: 3 features in parallel instead of sequential! +Cost per feature: Constant +Delivery speed: 3x faster +``` + +## Velocity-Based Estimation + +Instead of story points, estimate using workflow steps. + +### Measuring Velocity + +``` +Definition: Velocity = Number of workflow steps completed per sprint + +Example Sprint: +Week 1: + Team A: Completed CreateOrder command (1 step) + Team B: Completed ConfirmOrder command (1 step) + Team C: Completed AuthorizePayment processor (1 step) + +Velocity: 3 workflow steps per sprint + +Historical data: +Sprint 1: 3 steps +Sprint 2: 3 steps +Sprint 3: 2 steps (one complex step slowed us down) +Sprint 4: 3 steps + +Average velocity: ~3 steps per sprint +``` + +### Estimating Projects + +``` +New Feature: E-Commerce with Reviews + +Event Model: +Workflow steps identified: + Step 1: Create Order + Step 2: Confirm Order + Step 3: Authorize Payment + Step 4: Reserve Inventory + Step 5: Create Shipment + Step 6: Deliver Package + Step 7: Submit Review + Step 8: Moderate Review + Step 9: Calculate Ratings (read model) + +Total: 9 workflow steps + +Team velocity: 3 steps per sprint + +Estimate: 9 ÷ 3 = 3 sprints = ~12 weeks + +Without Event Modeling: + - Estimate: 4-6 months (guess) + - Actual: Often 6-9 months due to coupling issues + +With Event Modeling: + - Estimate: 3 sprints (confident) + - Actual: Usually matches or beats estimate +``` + +### Benefits of Velocity-Based Estimation + +1. **Empirical**: Based on actual history, not guesses +2. **Objective**: Not influenced by opinion +3. **Consistent**: Same factors each time +4. **Scalable**: Works for teams and organizations +5. **Improvable**: You can identify and fix bottlenecks + +## Project Planning Spreadsheet + +``` +Project: Order Management System +Team Velocity: 3 steps per sprint + +Feature Planning: + + Feature Steps Sprints Timeline + + Core Order Flow 3 1 sprint Week 1-4 + Payment Processing 2 1 sprint Week 5-8 + Inventory Management 2 1 sprint Week 9-12 + Fulfillment & Shipping 2 1 sprint Week 13-16 + Order Tracking (read model) 1 0.3 spr Week 17 + Customer Reviews 2 1 sprint Week 18-21 + Analytics Dashboard 1 0.3 spr Week 22 + + TOTAL 13 4 sprints ~22 weeks + + +With parallel teams: + - Team A: Weeks 1-4 (Orders) + - Team B: Weeks 1-4 (Payments) ← Parallel! + - Team C: Weeks 1-4 (Inventory) ← Parallel! + - Team D: Weeks 5-8 (Fulfillment) ← After steps 1-3 + +Result: All work done in ~8 weeks with proper parallelization +Without parallelization: ~22 weeks (1 team, sequential delivery) +``` + +## Scaling to Organization Level + +### Velocity per Team + +``` +Organization has 3 teams: + +Team A (Order Processing): 3 steps/sprint +Team B (Payment): 2 steps/sprint +Team C (Fulfillment): 3 steps/sprint + +Organization velocity: 8 steps/sprint + +Can deliver projects worth 8 workflow steps in parallel per sprint! +``` + +### Multi-Team Project Planning + +``` +Large Project: Complete E-Commerce Platform + +Identify all workflow steps: +Phase 1 (must complete first): + - Create Order (Step 1) + - Confirm Order (Step 2) + - Authorize Payment (Step 3) + → 3 steps, 1 sprint with 3 teams + +Phase 2 (depends on Phase 1): + - Reserve Inventory (Step 4) + - Create Shipment (Step 5) + - Deliver Package (Step 6) + → 3 steps, 1 sprint with 3 teams + +Phase 3 (independent from 1-2): + - Customer Reviews (Step 7-8) + - Rating Calculations (Step 9) + → 3 steps, 1 sprint with 3 teams + +Total: 9 steps, 3 sprints, 3 teams working in parallel = 3 sprints total + +Without parallelization: 9 steps × 1 team = 9 sprints sequential +With proper contracts: 3 sprints with 3 teams +Speedup: 3x faster! +``` + +## Handling Variable Complexity + +Some workflow steps are more complex: + +``` +Typical workflow step: 1 week, 1 developer +Complex workflow step: 2 weeks, 1-2 developers +Simple workflow step (read model): 0.5 weeks, 1 developer + +Velocity calculation (realistic): +Sprint 1: + - CreateOrder (typical): 1 step + - ComplexPaymentValidation (complex): 0.5 steps + - Notifications (simple): 1 step + → Velocity: 2.5 steps/sprint + +Using this more accurate velocity: + 9-step project = 9 ÷ 2.5 = 3.6 sprints +More realistic estimate! +``` + +## Capacity Planning + +``` +Team has 1 developer available +Velocity: ~2.5 steps/sprint + +Project needs 13 workflow steps delivered +Timeline: 13 ÷ 2.5 = 5.2 sprints = ~5.5 months + +Add another developer: +Team velocity: ~5 steps/sprint +Timeline: 13 ÷ 5 = 2.6 sprints = ~2.5 months +Cost reduction: 50% reduction in calendar time + +Add processes/tools: +Better test infrastructure: +0.5 steps/sprint +Better CI/CD: +0.5 steps/sprint +New velocity: ~6 steps/sprint +Timeline: 13 ÷ 6 = 2.2 sprints = ~2 months +``` + +## Common Estimation Mistakes + +### Mistake 1: Counting All Features as Equal Weight + +``` +Wrong: "Feature A = 8 points, Feature B = 8 points" (same complexity?) +Right: "Feature A = 3 workflow steps, Feature B = 5 workflow steps" + (Different complexity reflected) +``` + +### Mistake 2: Including Non-Workflow-Step Work + +``` +Wrong: "8 points for order system" (includes meetings, planning, docs) +Right: "5 workflow steps for order system" (measure implementation only) + Add separate budget for: Planning (1 week), Testing (1 week), Deployment (0.5 week) +``` + +### Mistake 3: Ignoring Workflow Step Dependencies + +``` +Wrong: "Project = 10 steps, 2 teams, 5 sprints" +Right: Identify dependencies: + - Steps 1-3 can run in parallel (3 sprints) + - Steps 4-5 depend on 1-3 (sequential after) + - Steps 6-10 can run in parallel with 4-5 + → 5-6 sprints with proper dependency management +``` + +## Retrospectives & Velocity Improvement + +Use completed projects to improve estimation: + +``` +Sprint Retrospective: + +Planned: 3 workflow steps +Completed: 2.5 workflow steps +Blocking issue: "Couldn't start step C until step B was fully integrated" + +Action: Better integration earlier → Next sprint, improve parallelization + +Track over time: +Sprint 1 velocity: 2.5 +Sprint 2 velocity: 2.8 (better parallelization) +Sprint 3 velocity: 3.2 (developers more comfortable with patterns) +Sprint 4 velocity: 3.0 (added new junior developer, slower) + +Trend: Improving as team gets comfortable (minus new hires) +``` + +## Key Metrics + +| Metric | Calculation | What It Tells You | +|--------|-----------|-------------------| +| **Velocity** | Workflow steps completed / sprint | Team throughput | +| **Step Complexity** | Actual time / 1 week | Which steps take longer | +| **Parallelization Rate** | Teams working on independent steps / total teams | How well we're using resources | +| **Estimation Accuracy** | Planned steps / completed steps | How good our estimates are | + +## Summary: From Estimates to Reality + +``` +Traditional Approach: +Project scope → [Guess complexity] → Estimate → [Often wrong] + +Event Modeling Approach: +Project scope → [Count workflow steps] → [Use historical velocity] → +Estimate → [Usually accurate] → Deliver on time + +Traditional accuracy: ±50% (at best) +Event Modeling accuracy: ±10% (with historical data) +``` + +## Further Reading + +- Article section: "Flat Cost Curve" +- Article section: "Estimates without Estimating" +- Article section: "Strong Contracts" diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-plotting-events/SKILL.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-plotting-events/SKILL.md new file mode 100644 index 0000000..9e74ab8 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-plotting-events/SKILL.md @@ -0,0 +1,180 @@ +--- +name: eventmodeling-plotting-events +description: >- + Step 2 of Event Modeling - Arrange events chronologically in logical narrative + sequence. Create timeline showing event flow and dependencies. Use after + brainstorming events. Do not use for: brainstorming new events (use + eventmodeling-brainstorming-events) or designing command/read model + architecture (use eventmodeling-designing-event-models). +allowed-tools: Write +--- + +# Plotting Events + +Arrange all brainstormed events chronologically to create a logical sequence that makes sense as a narrative timeline. Show how events flow and depend on each other. + +## Workflow + +Given a list of brainstormed events, create the chronological plot: + +### 1. Sequence Events Chronologically +Order events in time-based narrative: +- What happens first? +- What depends on what? +- What's the causal chain? + +Format: +``` +Timeline: Order Processing + +1. Customer initiates → OrderCreated + (Event: OrderCreated) + +2. Order confirmed → OrderConfirmed + Depends on: OrderCreated happened + (Event: OrderConfirmed) + +3. Payment processed → PaymentAuthorized + Depends on: OrderConfirmed happened + (Event: PaymentAuthorized) + +4. Inventory reserved → InventoryReserved + Depends on: PaymentAuthorized happened + (Event: InventoryReserved) + +5. Order shipped → OrderShipped + Depends on: InventoryReserved happened + (Event: OrderShipped) + +6. Delivery confirmed → DeliveryConfirmed + Depends on: OrderShipped happened + (Event: DeliveryConfirmed) +``` + +### 2. Show Dependencies and Causality +Document what triggers each event: +``` +Event: OrderConfirmed +Can only happen after: OrderCreated +Triggered by: Customer confirms order +Precondition: Order in Draft state + +Event: PaymentAuthorized +Can only happen after: OrderConfirmed +Triggered by: Payment gateway authorizes +Precondition: Order confirmed and payment submitted +``` + +### 3. Identify Alternative Paths +Show events that can diverge: +``` +After OrderCreated: +Path A: Customer confirms → OrderConfirmed +Path B: Customer cancels → OrderCancelled + +After PaymentAuthorized: +Path A: Payment succeeds → PaymentProcessed +Path B: Payment fails → PaymentFailed → OrderCancelled +``` + +### 4. Create Timeline Diagram +Visual representation of event flow: + +``` + + Time → + + OrderCreated + ↓ + OrderConfirmed + → PaymentAuthorized + → InventoryReserved + → OrderShipped + → DeliveryConfirmed + → PaymentFailed → OrderCancelled + → OrderCancelled (rejected before payment) + +``` + +## Output Format + +Present as: + +```markdown +# The Plot: [Domain Name] + +## Chronological Event Sequence + +### Phase 1: Order Initiation +1. **OrderCreated** - When: Customer submits order + - Previous state: None (initial event) + - Next possible: OrderConfirmed or OrderCancelled + +### Phase 2: Order Confirmation +2. **OrderConfirmed** - When: Customer confirms and payment ready + - Depends on: OrderCreated + - Next possible: PaymentAuthorized or OrderCancelled + +### Phase 3: Payment Processing +3. **PaymentAuthorized** - When: Payment gateway approves + - Depends on: OrderConfirmed + - Next possible: InventoryReserved or PaymentFailed + +4. **PaymentFailed** - When: Payment declined + - Depends on: OrderConfirmed (payment attempted) + - Next possible: OrderCancelled (or retry) + +### Phase 4: Fulfillment +5. **InventoryReserved** - When: Inventory allocated + - Depends on: PaymentAuthorized + - Next possible: OrderShipped + +6. **OrderShipped** - When: Order leaves warehouse + - Depends on: InventoryReserved + - Next possible: DeliveryConfirmed + +### Phase 5: Delivery +7. **DeliveryConfirmed** - When: Customer receives order + - Depends on: OrderShipped + - Next possible: None (terminal) + +### Phase 6: Cancellations (Alternative Path) +8. **OrderCancelled** - When: Customer cancels or payment fails + - Can happen after: OrderCreated, OrderConfirmed, PaymentFailed + - Next possible: RefundInitiated + +9. **RefundInitiated** - When: Refund processed + - Depends on: OrderCancelled + - Next possible: None (terminal) + +## Event Flow Diagram + +[ASCII or text representation of timeline] + +## Key Insights + +- **Critical Path**: Events that must happen in order +- **Decision Points**: Where flow branches +- **Terminal Events**: Where flow ends +- **Compensation Events**: How to handle cancellations +- **Wait States**: Where system pauses for external action +``` + +## Quality Checklist + +- [ ] Every event has clear predecessor +- [ ] Dependencies are explicitly documented +- [ ] Alternative paths are shown +- [ ] Flow forms a coherent narrative +- [ ] No events without trigger +- [ ] Terminal states are clear +- [ ] Compensation/cancellation flows are complete +- [ ] Timeline makes business sense + +## Principles + +1. **Narrative Coherence**: Events tell a story +2. **Dependency Clarity**: What must come before what +3. **Alternative Paths**: Show all possible flows (happy path + errors) +4. **Natural Sequence**: Order matches business domain logic +5. **Completeness**: Every brainstormed event appears diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-slicing-event-models/SKILL.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-slicing-event-models/SKILL.md new file mode 100644 index 0000000..961cf39 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-slicing-event-models/SKILL.md @@ -0,0 +1,355 @@ +--- +name: eventmodeling-slicing-event-models +description: >- + Break down complete event models into independently implementable feature + slices, identify dependencies, and plan parallel implementation across teams. + Use when planning team allocation, identifying MVP scope, or establishing + implementation order after completing event modeling. Do not use for: + organizational team structure based on Conway's Law (use + eventmodeling-applying-conways-law) or planning before the event model is + complete (complete the full model first using + eventmodeling-orchestrating-event-modeling). +allowed-tools: AskUserQuestion, Write +--- + +# Slicing Event Models + +## Interview Phase (Optional) + +**When to Interview**: Skip if the user has already specified: available team capacity, sprint duration, MVP scope/timeline, and critical path requirements. Interview when implementation planning details haven't been discussed or when you want to help identify MVP scope. + +**Interview Strategy**: Understand team capacity and timeline constraints to create realistic implementation slices. This shapes MVP scope and parallel work planning. + +### Critical Questions + +When implementation planning is needed: + +1. **Available Team Capacity** (Impact: Determines how many slices can be built in parallel) + - Question: "How many teams/people are available? (A) 1 team (solo), (B) 2-3 teams, (C) 4+ teams" + - Why it matters: More capacity enables parallel work; small teams need fewer slices to avoid idle time + - Follow-up triggers: If (A) → plan sequential slices; if (C) → maximize parallel work + +2. **Sprint/Timeline Constraints** (Impact: Affects slice size and MVP scope) + - Question: "What's your sprint duration and MVP deadline? (e.g., 2-week sprints with 8-week deadline, 1-week sprints with 4-week deadline)" + - Why it matters: Tight timelines mean smaller slices; longer timelines allow more ambitious MVP + - Follow-up triggers: If very tight → ask what MUST be in MVP; if loose → ask what nice-to-haves exist + +3. **Critical Path & Dependencies** (Impact: Determines implementation order and blocking relationships) + - Question: "Are there features that must be built first? (A) No dependencies (parallel from start), (B) Some core features first, (C) Complex dependency chain" + - Why it matters: Understanding dependencies reveals optimal build order and which slices can start immediately + - Follow-up triggers: If (C) → ask what depends on what; map dependency chain + +### Interview Flow + +**Conditional Entry**: +```text +If user has provided: + - Team capacity (number of teams/people) + - AND sprint duration + MVP deadline + - AND identified critical path / MVP features + +Then: Skip interview, proceed directly to slicing + +Else: Conduct interview +``` + +**Phase 1: Capacity Planning** (Questions 1-2) +- Understand team count +- Establish timeline constraints +- Determine slice count target + +**Phase 2: Dependency Mapping** (Question 3) +- Identify critical path +- Determine implementation order +- Find parallel work opportunities + +### Capturing Interview Findings + +Document findings to guide slicing: + +```markdown +## Interview Findings: [Domain Name] Implementation Plan + +**Team Capacity**: [Number of teams/people] +**Sprint Duration**: [Days/weeks] +**MVP Deadline**: [Date] +**Available Sprints for MVP**: [Number] + +**Critical Path Features** (must build first): +- [Feature 1] +- [Feature 2] + +**Dependency Chain**: +- [Feature A] blocks [Feature B] +- [Feature B] blocks [Feature C] + +**Parallel Work Opportunity**: +- Slice 1 & Slice 2 can start simultaneously +- Slice 3 can start after [dependency] + +**Recommended Slices**: +- Slice 1 (Foundation): [features] - [Duration] +- Slice 2 (Features): [features] - [Duration] +- Slice 3 (Extended): [features] - [Duration] +``` + +Optional: Write to `.trogonai/interviews/[timestamp]-slicing-event-models.interview.internal.trogonai.md`. + +--- + +# Event Modeling Slice Skill + +**Purpose**: Break down a complete event model into independently implementable feature slices, identify dependencies, and plan parallel (fan-out) implementation across teams. + +**Applies To**: Any domain - e-commerce, banking, SaaS, marketplace, healthcare, etc. + +**When to Use**: +- After completing full event model (Steps 1-9) +- Before starting implementation +- When planning team allocation and sprint planning +- To identify MVP scope +- To find what can be built in parallel +- To establish implementation order/phases + +**What It Does**: +1. Identifies feature slices from complete event model +2. Maps commands, events, and read models to each slice +3. Identifies slice dependencies +4. Determines which slices can be developed in parallel (fan-out) +5. Suggests optimal implementation order +6. Creates implementation roadmap +7. Shows data flow between slices + +--- + +## Core Concept: Feature Slices + +A **Feature Slice** is a thin, vertical slice through the entire system: + +``` +Feature Slice = Command Handler + [CommandHandler]State + Events + Read Models + Projections + (complete end-to-end flow for one decision/capability) +``` + +**Key Characteristics**: +- Can be implemented independently by one team +- Each handler owns its own [CommandHandler]State class +- Can be deployed separately +- Clear business value (represents one decision/command) +- Communicates with other slices via events only +- Small enough for one team to implement in 1-2 sprints +- Zero merge conflicts (isolated folder with isolated state class) + +--- + +## Feature Slice Identification Framework + +### Step 1: Group by Business Capability + +Start by identifying **what users can do**: + +``` +User Capabilities: + "Place and confirm an order" ← One slice + "Pay for an order" ← One slice + "Manage inventory" ← One slice + "Fulfill and ship an order" ← One slice + "Track shipment status" ← One slice +``` + +Each capability = One feature slice + +### Step 2: Map Commands to Slices + +Identify which **commands** belong to each slice: + +``` +Feature Slice: Core Order Flow +Commands: + CreateOrder (customer submits) + ConfirmOrder (customer confirms) + (CancelOrder belongs to its own slice) + +Feature Slice: Payment Processing +Commands: + AuthorizePayment (payment gateway) + ProcessRefund (customer or support requests) + +Feature Slice: Fulfillment & Shipping +Commands: + CreateShipment (fulfillment team) + ConfirmDelivery (carrier webhook) +``` + +### Step 3: Map Events to Slices + +Identify which **events** are produced by each slice: + +``` +Feature Slice: Core Order Flow +Events Produced: + OrderCreated + OrderConfirmed + OrderCancelled (if cancelled before payment) + +Feature Slice: Payment Processing +Events Produced: + PaymentAuthorized + PaymentFailed + RefundInitiated + RefundCompleted + +Feature Slice: Inventory Management +Events Consumed: + PaymentAuthorized (triggers reservation) +Events Produced: + InventoryReserved + InventoryReleased + +Feature Slice: Fulfillment & Shipping +Events Consumed: + InventoryReserved (triggers shipment) +Events Produced: + ShipmentCreated + DeliveryConfirmed +``` + +### Step 4: Map Read Models to Slices + +Identify which **read models** serve each slice: + +``` +Feature Slice: Core Order Flow +Read Models: + OrderDetailView (show what was ordered) + OrderListView (customer's order history) + +Feature Slice: Payment Processing +Read Models: + PaymentStatusView (payment and refund state) + OrderPaymentView (payment details per order) + +Feature Slice: Inventory Management +Read Models: + InventoryLevelView (current stock per product) + ReservationView (what's reserved for which order) + +Feature Slice: Fulfillment & Shipping +Read Models: + ShipmentStatusView (tracking and delivery state) + OrderFulfillmentView (fulfillment progress per order) +``` + +--- + +## Slice Dependency Analysis + +### Identifying Dependencies + +**Dependency Types**: + +``` +Type 1: Event Dependency + "Slice B needs events from Slice A" +Example: ReserveInventoryHandler needs PaymentAuthorized (from AuthorizePaymentHandler) +Impact: Must implement Slice A first (publish events) + +Type 2: Event Stream Dependency (NOT Aggregate Dependency) + "Slice B's handler reconstructs state from same event stream as Slice A" +Example: ShipOrderHandler uses OrderCreated/OrderConfirmed events to build ShipOrderState +Impact: Can develop in parallel, but must serialize commands at event store level + +Type 3: Read Model Dependency + "Slice B reads projection from Slice A" +Example: Fulfillment slice needs InventoryLevelView (projected from inventory events) +Impact: Can develop in parallel, but A's projections must deploy first + +Type 4: No Dependency + "Slices are completely independent" +Example: AuthorizePaymentHandler and CreateShipmentHandler work separate event streams +Impact: Can develop, test, and deploy in true parallel +``` + +### Dependency Matrix Example + +``` + | Core Orders | Payment | Inventory | Fulfillment | + +Core Orders | (self) | - | - | - | +Payment | ← Depends | (self) | - | - | +Inventory | ← Depends | ← Depends | (self) | - | +Fulfillment | ← Depends | ← Depends | ← Depends | (self) | + +Legend: + ← Depends on (arrow points to dependency) + - = No dependency + = Self (no external dependency) +``` + +--- + +## Fan-Out Implementation Planning + +### Parallel Development Strategy + +``` +CRITICAL PATH (Must do in sequence): +Slice 1: Core Order Flow (foundation) + ↓ (depends on OrderConfirmed event) +Slice 2: Payment Processing (depends on Slice 1) + ↓ (depends on PaymentAuthorized event) +Slice 3: Inventory Management (depends on Slice 2) + ↓ (depends on InventoryReserved event) +Slice 4: Fulfillment & Shipping (depends on Slice 3) + +Visual Timeline: +Week 1-2: [Slice 1: Core Orders] (Team A) + Unlocks Payment slice + +Week 3-4: [Slice 2: Payment] (Team A) [Slice 1 integration tests] (Team B) + Payment unlocks Inventory + +Week 5-6: [Slice 3: Inventory] (Team A) [Slice 4: Fulfillment] (Team B) + Can work in parallel once Payment is done + +Week 7-8: Integration & Cross-Slice Testing +``` + +### Fan-Out Pattern + +**Fan-Out** = One slice (foundation) → Multiple slices (parallel) + +``` +Example: Acme Corp Order Management + +Slice 1 → Slice 2 → Slice 3 → Slice 4 +(Orders) (Payment) (Inventory) (Fulfillment) + +Benefits: + Teams work in parallel + Slice 1 done in Week 2, teams start Weeks 3-4 + 3 teams productive simultaneously + Critical path stays short + Risk distributed (if Slice 2 hits issue, Slice 3 continues) +``` + +--- + +## Reference Documentation + +For detailed patterns, implementation strategies, and examples: + +- **[patterns.md](references/patterns.md)** - Slice templates, implementation strategies, communication patterns, MVP scoping, and best practices +- **[examples.md](references/examples.md)** - Complete slice breakdowns, dependency matrices, fan-out timelines, and checklists + +--- + +## Quality Checklist + +- [ ] Each slice contains exactly one complete UI/Processor → Command → Event → Read Model flow +- [ ] Slice dependencies flow in one direction — no circular dependencies between slices +- [ ] Each slice is independently deployable — no slice requires another slice to be running to function +- [ ] Every [CommandHandler]State in a slice is owned exclusively by that slice's handler +- [ ] MVP scope identifies the minimum set of slices that delivers customer value end-to-end +- [ ] Fan-out plan assigns each slice to a team with no overlapping handler ownership + diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-slicing-event-models/references/examples.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-slicing-event-models/references/examples.md new file mode 100644 index 0000000..38587fb --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-slicing-event-models/references/examples.md @@ -0,0 +1,258 @@ +# Event Modeling Slice Examples + +## Table of Contents +- [Acme Corp Order Management System](#acme-corp-order-management-system) +- [Slice Interaction Diagram](#slice-interaction-diagram) +- [Dependency Matrix Example](#dependency-matrix-example) +- [Fan-Out Timeline Example](#fan-out-timeline-example) +- [Checklist for Slice Definition](#checklist-for-slice-definition) + +--- + +## Acme Corp Order Management System + +### Complete Slice Breakdown + +``` + + FEATURE SLICE 1: Core Order Flow + + Business Value: Customers can place and confirm orders + Effort: 2 weeks / 1-2 engineers + MVP Critical: YES (foundation for all others) + + Handlers & States: + - CreateOrderHandler + CreateOrderState + - ConfirmOrderHandler + ConfirmOrderState + Events Produced: OrderCreated, OrderConfirmed + Events Consumed: NONE + Read Models Created: OrderDetailView, OrderListView + + Upstream Dependencies: NONE (this is foundation) + Can Run Parallel: NONE (blocks everything else) + + + + FEATURE SLICE 2: Payment Processing + + Business Value: Orders can be paid and refunded + Effort: 2 weeks / 1-2 engineers + MVP Critical: YES (no revenue without payment) + + Handlers & States: + - AuthorizePaymentHandler + AuthorizePaymentState + - ProcessRefundHandler + ProcessRefundState + Events Consumed: OrderConfirmed (triggers payment) + Events Produced: PaymentAuthorized, PaymentFailed, + RefundInitiated, RefundCompleted + Read Models Created: PaymentStatusView + + Upstream Dependencies: Slice 1 (needs OrderConfirmed event) + Can Run Parallel: NONE until Slice 1 ships + + + + FEATURE SLICE 3: Inventory Management + + Business Value: Stock is reserved and released per order + Effort: 2 weeks / 1-2 engineers + MVP Critical: YES (prevents overselling) + + Handlers & States: + - ReserveInventoryHandler + ReserveInventoryState + - ReleaseInventoryHandler + ReleaseInventoryState + Events Consumed: PaymentAuthorized (triggers reservation) + Events Produced: InventoryReserved, InventoryReleased + Read Models Created: InventoryLevelView, ReservationView + + Upstream Dependencies: Slice 2 (needs PaymentAuthorized) + Can Run Parallel: Slice 4 (independent once Slice 2 ships) + + + + FEATURE SLICE 4: Fulfillment & Shipping + + Business Value: Orders are shipped and delivery is confirmed + Effort: 2 weeks / 1-2 engineers + MVP Critical: YES (orders must arrive) + + Handlers & States: + - CreateShipmentHandler + CreateShipmentState + - ConfirmDeliveryHandler + ConfirmDeliveryState + Events Consumed: InventoryReserved (triggers shipment) + Events Produced: ShipmentCreated, DeliveryConfirmed + Read Models Created: ShipmentStatusView, OrderFulfillmentView + + Upstream Dependencies: Slice 3 (needs InventoryReserved) + Can Run Parallel: Slice 3 (parallel once Slice 2 ships) + +``` + +### Critical Path + +``` +CRITICAL PATH (must do in sequence): +Slice 1 (Week 1-2) → Core Orders, foundation + ↓ +Slice 2 (Week 3-4) → Payment, depends on OrderConfirmed + ↓ +Slices 3 & 4 (Week 5-6) → Inventory & Fulfillment, both depend on PaymentAuthorized + ↓ +Integration & Testing (Week 7-8) +``` + +### Team Fan-Out + +``` +TEAM FAN-OUT: +Week 1-2: Team A works on Slice 1 (Core Orders) +Week 3-4: Team A works on Slice 2 (Payment) + Team B writes integration tests for Slice 1 +Week 5-6: Team A works on Slice 3 (Inventory) + Team B works on Slice 4 (Fulfillment) + Both work in parallel once Payment ships! +``` + +### MVP Options + +``` +MVP Option 1 (Minimal): +Launch: Slices 1-2 only (Week 4) - orders can be placed and paid +Later: Add Slices 3-4 (fulfillment) + +MVP Option 2 (Full): +Launch: All 4 slices (Week 8) - complete order-to-delivery flow +``` + +--- + +## Slice Interaction Diagram + +### Visual Flow + +``` +User Actions: +[Customer places order] + ↓ +[Core Order Flow Slice] + Command: CreateOrder → ConfirmOrder + Event: OrderCreated → OrderConfirmed + Read Model: OrderDetailView + ↓ +[Event Bus: OrderConfirmed] + ↓ + + ↓ +[Payment Slice] + Command: AuthorizePayment + Event: PaymentAuthorized + Read Model: PaymentStatusView + ↓ +[Event Bus: PaymentAuthorized] + ↓ + + ↓ ↓ +[Inventory Slice] [Fulfillment Slice] + Event Event + InventoryReserved ShipmentCreated + ↓ ↓ + + ↓ + [Read Models Update] + ↓ + [Display to Users] +``` + +--- + +## Dependency Matrix Example + +``` + | Core Orders | Payment | Inventory | Fulfillment | + +Core Orders | (self) | - | - | - | +Payment | ← Depends | (self) | - | - | +Inventory | ← Depends | ← Depends | (self) | - | +Fulfillment | ← Depends | ← Depends | ← Depends | (self) | + +Legend: + ← Depends on (arrow points to dependency) + - = No dependency + = Self (no external dependency) +``` + +--- + +## Fan-Out Timeline Example + +### Visual Timeline + +``` +Week 1-2: [Slice 1: Core Orders] (Team A) + Unlocks Payment slice + +Week 3-4: [Slice 2: Payment] (Team A) [Integration tests Slice 1] (Team B) + Payment unlocks Inventory & Fulfillment + +Week 5-6: [Slice 3: Inventory] (Team A) [Slice 4: Fulfillment] (Team B) + Can work in parallel once Payment ships + +Week 7-8: Integration & Cross-Slice Testing +``` + +### Fan-Out Pattern + +``` +Slice 1 Slice 2 Slice 3 (Inventory) +(Core Orders) → (Payment) → + Slice 4 (Fulfillment) + +Benefits: + Sequential until Payment unlocks the fan-out + Teams A and B work in parallel from Week 5 + Critical path is clear and enforced by event dependencies + Risk isolated: Inventory issues don't block Fulfillment work +``` + +--- + +## Checklist for Slice Definition + +Before implementing a slice, verify: + +``` +Scope: +[ ] Clear business value statement (one sentence) +[ ] All commands identified +[ ] All events identified +[ ] All read models identified +[ ] No scope creep (staying focused) + +Dependencies: +[ ] Upstream dependencies listed (what we need) +[ ] Downstream dependents listed (what depends on us) +[ ] Can we develop in parallel with other slices? +[ ] Do we have all dependencies available? + +Boundaries: +[ ] Handler is isolated (own [CommandHandler]State class) +[ ] No shared state classes with other slices +[ ] Events are contract between slices (source of truth) +[ ] Read models owned by one slice, consumed by others + +Testability: +[ ] Can this be tested independently? +[ ] Do we have test data without dependent slices? +[ ] Can we mock dependencies? + +Deployability: +[ ] Can this be deployed independently? +[ ] Or must we deploy with other slices? +[ ] Database migrations needed? How to coordinate? + +Team: +[ ] Right-sized for 1-2 engineers? +[ ] Effort estimated (days)? +[ ] Assigned to team? +[ ] Sprint plan clear? +``` diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-slicing-event-models/references/patterns.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-slicing-event-models/references/patterns.md new file mode 100644 index 0000000..c81e4cb --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-slicing-event-models/references/patterns.md @@ -0,0 +1,425 @@ +# Event Modeling Slice Patterns + +## Table of Contents +- [Slice Definition Template](#slice-definition-template) +- [Implementation Order Strategies](#implementation-order-strategies) +- [Cross-Slice Communication Patterns](#cross-slice-communication-patterns) +- [MVP Scoping with Slices](#mvp-scoping-with-slices) +- [Tips for Effective Slicing](#tips-for-effective-slicing) + +--- + +## Slice Definition Template + +Use this template for each feature slice: + +``` + + Feature Slice: [Name] + + +BUSINESS VALUE: +What user capability does this enable? +Example: "Buyers can submit reviews and get immediate feedback" + +COMMANDS: + - [Command 1]: What it does + - [Command 2]: What it does + +EVENTS PRODUCED: + - [Event 1]: When it occurs + - [Event 2]: When it occurs + +EVENTS CONSUMED: + - [Event from other slice]: Why needed + +[COMMANDHANDLER]STATES INVOLVED: + - [CommandHandler]State class: Which handler owns it, how it's reconstructed + +READ MODELS/PROJECTIONS CREATED/UPDATED: + - [Projection 1]: What events it consumes, what data it produces + - [Projection 2]: What events it consumes, what data it produces + +UPSTREAM DEPENDENCIES: + "Must complete these slices first:" + - [Slice X]: Why (what event/aggregate needed) + +DOWNSTREAM DEPENDENTS: + "These slices depend on us:" + - [Slice Y]: Why (what event/aggregate they need) + +CAN RUN PARALLEL WITH: + - [Slice Z]: Why (no dependencies between us) + - [Slice W]: Why (independent) + +ESTIMATED EFFORT: + - Development: X days + - Testing: X days + - Total: X days + +TEAM ASSIGNMENT: +Suggested team size: 1-3 people +Skills needed: [Backend/Frontend/Full-stack] + +MVP CRITICAL? +Yes/No (Is this needed for minimum viable product?) + +DEPLOYMENT NOTES: + - Can be deployed independently? [Yes/No] + - Database migrations? [None/Minor/Major] + - Configuration changes? [None/Yes] +``` + +--- + +## Implementation Order Strategies + +### Strategy 1: Bottom-Up (Foundation First) + +``` +Order: + 1. Core domain slices (most dependencies, fewest dependents) + 2. Mid-layer slices (depend on core, some have dependents) + 3. Presentation slices (few dependencies, most flexible) + +Advantage: Stable foundation, reduces rework +Disadvantage: Takes longer to show user value +Best for: Complex systems with many dependencies +``` + +**Example (Acme Corp Order Management)**: +``` +Phase 1: Core Order Flow Handlers (foundation - 2 weeks) + CreateOrderHandler + CreateOrderState + ConfirmOrderHandler + ConfirmOrderState + Establishes Order event stream, OrderCreated/OrderConfirmed events + +Phase 2: Payment Handlers (depends on Phase 1 - 2 weeks) + AuthorizePaymentHandler + AuthorizePaymentState + ProcessRefundHandler + ProcessRefundState + Uses OrderConfirmed event, produces PaymentAuthorized + +Phase 3: Inventory Handlers (depends on Phase 2 - 2 weeks) + ReserveInventoryHandler + ReserveInventoryState + ReleaseInventoryHandler + ReleaseInventoryState + Depends on PaymentAuthorized event + +Phase 4: Fulfillment Handlers (depends on Phase 3 - 2 weeks, parallel with 3) + CreateShipmentHandler + CreateShipmentState + ConfirmDeliveryHandler + ConfirmDeliveryState + Depends on InventoryReserved event, builds ShipmentStatusView +``` + +### Strategy 2: Top-Down (User Value First) + +``` +Order: + 1. MVP slices (minimum user value, isolate dependencies) + 2. Core slices (support MVP) + 3. Enhanced slices (nice-to-have features) + +Advantage: Show value quickly, get feedback early +Disadvantage: May need refactoring when core changes +Best for: Fast-moving products, MVP validation +``` + +**Example**: +``` +MVP Sprint 1-2: Core Order Flow (minimal, customers can place orders) + What users need: Create and confirm an order + +MVP Sprint 3-4: Payment Processing (enables revenue) + What the business needs: Authorize and capture payment + +Later: Inventory Management (operational feature) + Prevent overselling, can be manual initially + +Later: Fulfillment & Shipping (logistics integration) + Can be added after payment and inventory are stable +``` + +### Strategy 3: Risk-Based (De-risk First) + +``` +Order: + 1. Uncertain slices (highest risk, validate early) + 2. Dependent slices (build on validated foundation) + 3. Straightforward slices (low risk, can be last) + +Advantage: Identifies problems early +Disadvantage: May defer high-value features +Best for: Novel architectures, unproven patterns +``` + +**Example**: +``` +Sprint 1-2: Payment Gateway Integration (highest uncertainty) + Will the payment provider API behave at scale? + If this fails, the whole order flow is blocked + Validate this works before building on it + +Sprint 3-4: Core Order Flow (depends on payment working) + Now we know payment authorization is reliable + Safe to build order submission on top + +Sprint 5-6: Inventory & Fulfillment (low risk) + Foundation solid, now add operational slices +``` + +--- + +## Cross-Slice Communication Patterns + +### Pattern 1: Event-Driven (Recommended) + +``` +Slice A produces event + ↓ +Event published to bus + ↓ +Slice B consumes event + ↓ +Slice B updates its read model + +Advantages: + Loose coupling + Asynchronous + Slices don't need to know about each other + Easy to add new slices +``` + +**Example**: +``` +Slice: Review Submission (produces ReviewPublished) + ↓ +Event: ReviewPublished (published to event bus) + ↓ +Slice: Manual Moderation (listens for ReviewPublished) +Slice: Seller Responses (listens for ReviewPublished) +Slice: Seller Ratings (listens for ReviewPublished) + +All three can consume the same event independently +``` + +### Pattern 2: Event Stream with Multiple Handlers (Correct Approach) + +``` +One event stream, multiple independent command handlers + ↓ +Each handler owns its own [CommandHandler]State class + ↓ +Each handler reconstructs its own state from shared events + ↓ +Handlers coordinate via events (eventual consistency) + +Advantages: + Loose coupling (handlers don't call each other) + Easy to parallelize (each handler is isolated) + No shared state classes (zero merge conflicts) + Each handler can deploy independently + +Disadvantages: + Eventual consistency (not immediate) +``` + +**Example**: +``` +Event Stream: Review (ReviewSubmitted, ReviewPublished, ReviewRejected, etc.) + +Handlers (all independent): + - SubmitReviewHandler owns SubmitReviewState + - ApproveReviewHandler owns ApproveReviewState + - RejectReviewHandler owns RejectReviewState + - DeleteReviewHandler owns DeleteReviewState + +All handlers process events from same stream +Each maintains its own state in memory during command processing +No shared state class, no coupling, no merge conflicts +``` + +### Pattern 3: Read Model Dependency + +``` +Slice A creates/updates read model + ↓ +Slice B queries read model + ↓ +Slice B shows data to user + +Advantages: + Can develop in parallel + Slice B independent of Slice A implementation + +Disadvantages: + Eventually consistent + Slice B deployment depends on Slice A being deployed first +``` + +**Example**: +``` +Slice: Seller Ratings (creates SellerProfileView read model) + ↓ +Slice: Seller Dashboard (queries SellerProfileView) + Dashboard independent of how ratings are calculated + But SellerProfileView must be deployed/working +``` + +--- + +## MVP Scoping with Slices + +### Identifying MVP Slices + +``` +MVP Principle: Minimum Viable Product + = Smallest set of slices that provides customer value + +Questions to ask: + +1. What's the core user problem we're solving? + Example: "Buyers want feedback on products" + +2. What's the minimal slice needed? + Example: "Review Submission + Display" (not moderation yet) + +3. What can we defer? + Example: "Seller Responses, Ratings, Moderation" (Phase 2+) + +4. Which slices must we have for others to work? + Example: "Submission is foundation, everything depends on it" + +MVP Slices: +Priority 1 (Must have): Review Submission +Priority 2 (Nice to have): Seller Responses +Priority 3 (Defer): Manual Moderation, Ratings +``` + +### MVP Timeline + +``` +WEEK 1-2: MVP Launch + Slice 1: Review Submission & Auto-Publish + - Buyers can submit reviews + - Auto-moderation (simple checks) + - Reviews published immediately (if passes check) + - Basic review display + +Result: Users can submit and see reviews +Revenue impact: Reputation system working +Team effort: 1-2 engineers + +WEEK 3-4: Phase 2 Additions + Slice 2: Seller Responses + - Sellers can respond + - Responses published immediately + +Result: Two-way conversation +Team effort: 1-2 engineers (parallel) + +WEEK 5-6: Phase 3 Operations + Slice 3: Manual Moderation + - Admin can approve/reject flagged content + +Result: Platform governance +Team effort: 1-2 engineers + +WEEK 7-8: Phase 4 Analytics + Slice 4: Seller Ratings & Dashboard + - Ratings calculated and displayed + - Seller dashboard + +Result: Reputation metrics visible +Team effort: 1-2 engineers +``` + +--- + +## Tips for Effective Slicing + +### 1. Slice by Business Capability, Not Technical Layer + +``` + WRONG (by technical layer): +Slice 1: All command handlers +Slice 2: All event handlers +Slice 3: All read models +Problem: Can't ship anything independently, highly coupled + + CORRECT (by business capability): +Slice 1: Review submission (includes command + event + read model) +Slice 2: Moderation (includes command + event + read model) +Slice 3: Responses (includes command + event + read model) +Benefit: Each slice is shippable independently +``` + +### 2. Keep Slices Thin and Cohesive + +``` + GOOD: One feature per slice + - Submission slice does submission only + - Moderation slice does moderation only + + WRONG: Multiple features in one slice + - "Submission + Moderation" slice +Problem: Harder to parallelize, harder to test +``` + +### 3. Keep Handler State Classes Isolated + +``` +If multiple handlers work same event stream: + SubmitReviewHandler owns SubmitReviewState + ApproveReviewHandler owns ApproveReviewState + Both reconstruct from ReviewSubmitted events + +Problem (DON'T DO THIS): + Shared ReviewAggregate class used by both handlers + Result: Tight coupling, merge conflicts, hard to parallelize + +Solution (DO THIS): + Each handler owns its own [CommandHandler]State class + Result: Loose coupling, no merge conflicts, easy to parallelize + +Read Models: + Slice 3 & 4 both read SellerProfileView + Problem: Who creates it? + Solution: One slice (Rating handler) projects it, others consume +``` + +### 4. Make Dependencies Explicit + +``` +For each slice: +[ ] List which handler this slice implements +[ ] List exact events it needs from other handlers +[ ] List exact events it produces +[ ] List exact read models it reads +[ ] List exact read models it creates/updates + +Result: Clear contracts between slices +``` + +### 5. Plan Handler Communication + +``` +How handlers in different slices connect: + Event Stream (loosely coupled, asynchronous) + - Handler A emits event + - Handler B consumes via event projection + - No direct dependencies + + Event Stream with Multiple Handlers (loosely coupled, asynchronous) + - Multiple handlers work same event stream + - Each owns separate [CommandHandler]State class + - Coordinated via events (eventual consistency) + + Shared Read Models (loosely coupled, eventually consistent) + - Slice A projects read model + - Slice B queries read model + - Works if A's projections deployed first + + Shared State Classes (tightly coupled, avoid) + - Both slices share one [CommandHandler]State class + - Results in merge conflicts and tight coupling + - Don't do this! +``` diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-storyboarding-events/SKILL.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-storyboarding-events/SKILL.md new file mode 100644 index 0000000..f5abc46 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-storyboarding-events/SKILL.md @@ -0,0 +1,447 @@ +--- +name: eventmodeling-storyboarding-events +description: >- + Step 3 of Event Modeling - Create UI storyboards/mockups showing what users + see at each step. Capture all data fields needed from user perspective. Use + after sequencing events. Do not use for: identifying commands or processor + actions (use eventmodeling-identifying-inputs) or designing read models + (use eventmodeling-identifying-outputs). +allowed-tools: AskUserQuestion, Write +--- + +# Storyboarding Events + +## Interview Phase (Optional) + +**When to Interview**: Skip if the user has already specified: existing UI patterns or mockups to reference, critical data fields, and UI/UX preferences. Interview when these details haven't been discussed or when the user wants guidance on storyboarding depth. + +**Interview Strategy**: Clarify UI needs, data priorities, and existing patterns to guide storyboard design. This ensures mockups capture all necessary fields without over-designing. + +### Critical Questions + +When UI design guidance is needed: + +1. **Current UI State** (Impact: Determines if you're designing from scratch or enhancing existing) + - Question: "Do you have: (A) Existing UI/wireframes to reference, (B) Rough sketches, (C) Starting from scratch?" + - Why it matters: Existing UI provides constraints and patterns; starting fresh allows more design freedom + - Follow-up triggers: If (A) → ask to share; if (C) → ask about platform/technology + +2. **Most Critical Data Fields** (Impact: Determines storyboard focus and detail level) + - Question: "Which data fields are most important for users to see? (e.g., order status, payment confirmation, tracking info)" + - Why it matters: Knowing priorities helps avoid over-designing; users need to see what matters most first + - Follow-up triggers: For each critical field → ask "What decisions do users make based on this data?" + +3. **UI/UX Preferences & Constraints** (Impact: Shapes storyboard style and interaction patterns) + - Question: "Any UI preferences? (A) Web, (B) Mobile, (C) Both. And design style: (A) Minimal wireframes, (B) Detailed mockups, (C) Interact prototypes?" + - Why it matters: Platform and fidelity affect storyboard detail; mobile has different constraints than web + - Follow-up triggers: If (C) → ask about prototype tool; if minimal → discuss what level of detail is enough + +### Interview Flow + +**Conditional Entry**: +``` +If user has provided: + - Existing UI patterns or references + - AND identified critical data fields + - AND specified storyboard detail level + +Then: Skip interview, proceed directly to storyboarding + +Else: Conduct interview +``` + +**Phase 1: Context Assessment** (Questions 1-2) +- Understand existing UI context +- Identify data priorities +- Establish storyboard scope + +**Phase 2: Design Guidance** (Question 3) +- Determine platform and fidelity +- Adjust storyboard detail accordingly + +### Capturing Interview Findings + +Document findings to guide storyboard creation: + +```markdown +## Interview Findings: [Domain Name] UI + +**Existing UI Context**: [Starting from scratch / Enhancing / Matching pattern] +**Most Critical Data**: [List fields in priority order] +**Platform**: [Web / Mobile / Both] +**Storyboard Detail**: [Minimal wireframes / Detailed mockups] + +**Key UI Interactions**: +- [Action 1]: [What data triggers it] +- [Action 2]: [What data triggers it] + +**Storyboard Focus**: +- Prioritize showing [most critical fields] +- Ensure [specific interactions] are clear +- Reference [existing patterns] for consistency +``` + +Optional: Write to `.trogonai/interviews/[timestamp]-storyboarding-events.interview.internal.trogonai.md`. + +--- + +## Workflow + +Given the event timeline, create UI storyboards: + +### 1. Identify UI Screens/Views +Create a mockup for each state of the system: + +``` +Screen 1: Order Creation Form + + Place Your Order + + + Customer ID: [____________] + + Items: +Product 1 Qty: [_] Price: $_ +Product 2 Qty: [_] Price: $_ +Product 3 Qty: [_] Price: $_ + + Total: $___ + + Shipping Address: + [_____________________] + [_____________________] + + [ Create Order ] + + +Trigger: CreateOrder command +Result Events: OrderCreated +Data captured from UI: + - customerId + - items (products + quantities) + - total + - shippingAddress +``` + +### 2. Show State Transitions Between Screens +Document what changes when events occur: + +``` +Screen 2: Order Confirmation +(After OrderCreated event) + + + Order Confirmation + + + Order ID: #12345 + Status: Draft + + Items: 3 products + Total: $150.00 + + Shipping: 123 Main St + + Payment Options: +Credit Card +Bank Transfer + + [ Confirm Order ] + + +Trigger: ConfirmOrder command +Result Events: OrderConfirmed +Data from UI: + - orderId (from OrderCreated) + - paymentMethod +``` + +### 3. Document All Data Fields +For each screen, list what data is displayed: + +``` +Screen: Order Status View + + Your Order Status + + Order ID: #12345 (from OrderCreated) + Status: Confirmed (from OrderConfirmed) + Confirmed at: 2024-12-31 10:00 (from OrderConfirmed) + + Payment: Authorized (from PaymentAuthorized) + Auth Code: AUTH-789 (from PaymentAuthorized) + + Inventory: Reserved (from InventoryReserved) + Expected Ship: 2025-01-02 (from InventoryReserved) + + Shipped: Pending (awaiting OrderShipped) + Tracking: -- (waiting for shipment) + + +Fields and their origins: + orderId → OrderCreated event + status → OrderConfirmed event + confirmedAt → OrderConfirmed event + paymentStatus → PaymentAuthorized event + authCode → PaymentAuthorized event + inventoryStatus → InventoryReserved event + expectedShip → InventoryReserved event + tracking → OrderShipped event (when available) +``` + +### 4. Show Data Flow Through Screens +Map how data enters/exits UI: + +``` +Order Entry UI + (user inputs) + customerId + items[] + total + shippingAddress + ↓ + Command: CreateOrder + ↓ + Event: OrderCreated + ↓ + Order Status UI (displays) + orderId (from event) + items (from event) + total (from event) + shippingAddress (from event) +``` + +### 5. Organize Screens by Swimlane (Actor/System) + +**MANDATORY**: Use the **Role Catalog** from Step 1 (eventmodeling-brainstorming-events) as the source of swimlanes. Every human role in the catalog MUST have its own swimlane. Every system actor that has a UI or todo-list view gets a swimlane too. + +Group screens by who interacts with them: + +``` +Swimlane: Customer (Human Role) + Screen 1: Order Entry Form + Screen 2: Order Confirmation + Screen 3: Order Status View + Screen 4: Tracking View + +Swimlane: Seller (Human Role) + Screen 1: Order Fulfillment Dashboard + Screen 2: Review Response Form + Screen 3: Product Management + +Swimlane: Support Agent (Human Role) + Screen 1: Escalation Queue + Screen 2: Manual Override Panel + +Swimlane: Payment Processor (System Actor) + Screen 1: Payment Verification (automated) + Screen 2: Authorization Confirmation + +Swimlane: Inventory System (System Actor) + Screen 1: Reservation Todo List (internal) + Screen 2: Availability Check + +Swimlane: Fulfillment System (System Actor) + Screen 1: Shipment Creation Todo + Screen 2: Shipping Confirmation +``` + +**Validation**: If a role from the catalog has zero screens, either: +- The role is missing screens (add them), or +- The role doesn't belong in the catalog (remove it in Step 1) + +This shows which actors interact with which screens and helps visualize system boundaries. + +### 6. Show Processor "Todo List" Pattern +For automated processors, show the todo list metaphor: + +``` +Processor: InventoryReserver + +Internal "Todo List" (based on received events): + + Inventory Reservation Todos + + +Order-123: Reserve 2x Prod-1 (triggered by PaymentAuthorized) +Order-124: Reserve 3x Prod-2 (triggered by PaymentAuthorized) +Order-125: Reserve 1x Prod-3 (triggered by PaymentAuthorized) + + Processor checks todo items: + For each: Check availability + If available: Mark done + Reserve inventory + Produce event + + + +This todo list is driven by: +Events received → Items added to todo +Processor logic → Items processed +Success → InventoryReserved event produced + todo marked done +Failure → InventoryFailed event produced + todo marked failed +``` + +### 7. Identify Missing Data +Highlight where data doesn't have a clear source: + +``` +Problem: Order Status screen needs "expectedShip" date +Current state: Not in any event +Solution: Add expectedShip to InventoryReserved event + +Problem: Order status needs "last updated" timestamp +Current state: No tracking of when last change occurred +Solution: Every event includes timestamp +``` + +## Output Format + +Present as: + +```markdown +# Storyboard: [Domain Name] + +## Swimlane Organization (from Role Catalog) + +### Human Role Swimlanes + +#### Customer Swimlane +- Screen 1: Order Entry Form +- Screen 2: Order Confirmation +- Screen 3: Order Status View + +#### [Other Human Role Swimlanes — one per role in the catalog] + +### System Actor Swimlanes + +#### Payment Processor Swimlane +- Screen 1: Payment Verification (automated) +- [Shows what UI/views the processor interacts with] + +#### [Other System Actor Swimlanes] + +--- + +## Screen 1: [Screen Name] + +### Mockup +``` +[ASCII art mockup or description] +``` + +### Data Displayed +- Field 1: Description, source event +- Field 2: Description, source event + +### User Actions (Commands) +- Action: [Action], produces: [Event] + +### Business Rules +- Rule about what can/cannot be done on this screen + +--- + +## Screen 2: [Screen Name] + +[Repeat for each screen] + +--- + +## Processor Todo Lists + +### Processor: [Processor Name] + +Internal "Todo List" pattern: +``` +Triggered by: [Event type] +Todo action: [What needs to be done] +Success produces: [Event] +Failure produces: [Event] +``` + +[Repeat for each processor] + +--- + +## Data Flow Diagram + +[Show how data enters from UI and returns via events] + +--- + +## Field Traceability Matrix + +| Field | Screen | Source Event | Status | +|-------|--------|-------------|--------| +| orderId | Status View | OrderCreated | | +| shipmentId | Status View | OrderShipped | | +| customerId | All | OrderCreated | | + +--- + +## Missing Data Analysis + +[Any fields without clear source or destination] +``` + +## Quality Checklist + +- [ ] Every screen has a mockup or clear description +- [ ] Every displayed field has a source event +- [ ] Every user action maps to a command +- [ ] Commands map to events +- [ ] Data flows make sense +- [ ] No missing data sources +- [ ] State transitions are clear +- [ ] Alternative states are shown +- [ ] Error states are shown +- [ ] **Every human role from the Role Catalog has at least one swimlane** +- [ ] **Every swimlane is labeled with the role/actor name from the catalog** +- [ ] **Swimlanes organized by actor/system** +- [ ] **Human role screens clearly separated from processor screens** +- [ ] **Processor todo list pattern shown for automated systems** +- [ ] **System boundaries visible through swimlane organization** + +## Key Principles + +1. **User-Centric**: Design from what users see and do +2. **Data Traceability**: Every field has origin and destination +3. **Completeness**: All needed data is visible +4. **Clarity**: UI clearly shows system state +5. **Consistency**: Same data presented consistently across screens + +## Common Patterns + +### Input Screen Pattern +``` +User fills form (captures command data) + ↓ +Submit button (issues command) + ↓ +Event created with form data + ↓ +Confirmation screen displayed +``` + +### Status Screen Pattern +``` +System displays current state (from read model) + ↓ +Based on latest events + ↓ +Shows all relevant information + ↓ +Available actions based on state +``` + +### Error State Pattern +``` +User action fails (command rejected) + ↓ +No event created + ↓ +Error message displayed + ↓ +UI allows retry or alternative action +``` diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-translating-external-events/SKILL.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-translating-external-events/SKILL.md new file mode 100644 index 0000000..91c2c71 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-translating-external-events/SKILL.md @@ -0,0 +1,467 @@ +--- +name: eventmodeling-translating-external-events +description: >- + Translate external system events (webhooks, APIs, IoT) into domain events. + Map technical data to business concepts. Use when integrating with external + systems that emit events your domain needs to react to. Do not use for: + modernizing legacy systems using the side-car pattern (use + eventmodeling-integrating-legacy-systems) or designing command handlers for + the translated events (use eventmodeling-designing-event-models). +allowed-tools: AskUserQuestion, Write +--- + +# Translating External Events + +## Interview Phase (Optional) + +**When to Interview**: Skip if the user has specified: external systems involved, webhook/API formats, and domain mapping. Interview when external systems haven't been fully cataloged or translation rules are unclear. + +**Interview Strategy**: Catalog all external systems and understand their event formats before defining translation rules. Missing correlation strategies — how external IDs map back to domain entities — are the most common source of integration failures, so surface them early. + +### Critical Questions + +1. **External System Details** (Impact: Determines what translation rules to create) + - Question: "Which external systems send events? For each: (A) System name, (B) Event types, (C) Data format (JSON/XML), (D) Authentication needed?" + - Why it matters: Translation rules depend entirely on what the external system sends + - Follow-up triggers: For each system → ask "Does their payload include your internal entity ID, or do you need a correlation reference table?" + +2. **Domain Mapping Complexity** (Impact: Determines if translation is straightforward or complex) + - Question: "For the most complex integration: Does the external event data: (A) Map directly to domain concept, (B) Need aggregation/multiple events, (C) Need data from another system to map?" + - Why it matters: Simple 1-to-1 mappings vs. complex multi-source translations affect design + - Follow-up triggers: If (B) or (C) → ask "What data must you look up from your own system to complete the translation? How do you handle arrival before that data exists?" + +### Interview Flow + +**Conditional Entry**: +``` +If user has provided: + - Full list of external systems with event types + - AND sample payload formats for each event type + - AND correlation strategy (how to link external IDs to domain entity IDs) + +Then: Skip interview, proceed directly to translation rule design + +Else: Conduct interview +``` + +**Phase 1: External System Catalog** (Question 1) +- Enumerate all systems that send events into the domain +- Document event types and payload formats for each +- Identify authentication and delivery mechanisms (webhook, polling, streaming) + +**Phase 2: Mapping Complexity Assessment** (Question 2) +- Identify which integrations require enrichment from domain data +- Surface correlation gaps (external ID ≠ domain ID) +- Flag multi-source aggregations for deeper design attention + +### Capturing Interview Findings + +Append findings to the project's event modeling file: + +**File**: `.trogonai/interviews/[project-name]/EVENTMODELING.md` + +Use Write tool to add/update this section: + +```markdown +## Translating External Events (eventmodeling-translating-external-events) + +### External Systems Catalog +[From Q1: System names, event types, formats, auth mechanisms] + +### Mapping Complexity +[From Q2: Direct mappings vs. complex enrichment needs, correlation gaps] + +### Correlation Strategies +- [System A]: correlates via [reference field / lookup table] +- [System B]: correlates via [metadata in external payload] + +### High-Risk Integrations +- [System needing multi-source data]: [risk description] +``` + +Update Interview Trail: +```markdown +| Ext. Events | eventmodeling-translating-external-events | Done | External systems cataloged, correlation strategies defined | +``` + +--- + +## Workflow + +### 1. Identify External Event Sources + +Document each external system and what it sends: + +``` +External System: Payment Gateway (Stripe) + +Events received: + - charge.succeeded + - charge.failed + - charge.refunded + - charge.dispute.created + +Example payload: charge.succeeded +{ + "id": "ch_1234567890", + "amount": 15000, + "currency": "usd", + "customer": "cus_9876543210", + "status": "succeeded", + "created": 1640995200 +} + +External System: GPS Location Service (Google Maps) + +Events received: + - location_update + - geofence_enter + - geofence_exit + +Example payload: geofence_exit +{ + "userId": "user-123", + "geoFenceId": "hotel-front-entrance", + "timestamp": 1640995200, + "latitude": 40.7128, + "longitude": -74.0060 +} +``` + +### 2. Analyze Technical Representation + +Understand the raw data from external system: + +``` +External Event: charge.succeeded (Stripe) + +Technical fields: + - id: UUID of charge in Stripe (not meaningful to us) + - amount: Integer cents (15000 = $150.00) + - currency: ISO code ("usd") + - customer: Stripe customer ID (not our customer ID) + - status: String indicating success + - created: Unix timestamp + +Problems with using directly: + We don't use Stripe customer IDs (we have our own customer IDs) + Currency and amount require interpretation + Status is one field in their model, we care about the fact it succeeded + Stripe charge ID isn't the same as our order ID + We need to correlate back to our Order stream +``` + +### 3. Define Domain Translation Rules + +Map technical data to domain concepts: + +``` +Translation: External charge.succeeded → Domain PaymentAuthorized + +Mapping rules: + charge.id (Stripe) → paymentGatewayRef (store for reconciliation, don't use as primary) + charge.customer (Stripe) → Look up: Which of OUR customers has this Stripe ID? + charge.amount → paymentAmount (convert from cents) + charge.currency → paymentCurrency + created → timestamp +[NEED TO FIND] → orderId (Stripe doesn't tell us! This is critical—how do we know which order?) + +Problem identified: +Stripe webhook comes with charge details but NOT our order ID. + +Solutions: +A. Store Stripe charge ID in our Order when we initiate payment + When webhook arrives: charge.id → Look up in OrderPaymentReference + Find orderId → Create PaymentAuthorized event + +B. Store custom metadata in Stripe charge + When creating charge: Include our orderId in metadata + When webhook arrives: Extract orderId from metadata + +Choose A or B based on Stripe integration approach. +``` + +### 4. Handle Correlation + +External systems often don't include your IDs. Establish correlation: + +``` +Pattern: Correlation via Reference Tracking + +Our system flow: + 1. Order created in our system: order-123 + 2. We initiate payment with Stripe: + - Send amount, customer info + - Receive charge ID: ch_1234567890 + - Store reference: OrderPaymentReference { orderId: order-123, stripeChargeId: ch_1234567890 } + +When webhook arrives: + 1. Webhook: charge.succeeded { id: ch_1234567890, amount: 15000, ... } + 2. Look up: Find OrderPaymentReference where stripeChargeId = ch_1234567890 + 3. Get orderId from reference + 4. Create PaymentAuthorized event: { orderId: order-123, amount: 150.00, ... } + +Key insight: You must create the correlation bridge when initiating external action. +``` + +### 5. Define Translation Scenarios + +Specify translation logic for each external event: + +``` +External Event: charge.succeeded +Trigger: Stripe webhook arrives with charge details +Precondition: OrderPaymentReference exists for this charge ID +Translation logic: + 1. Extract charge.id from webhook + 2. Look up OrderPaymentReference.orderId + 3. Validate order exists and is in Confirmed state + 4. Create domain event: PaymentAuthorized { orderId, amount, timestamp, ... } +Success: Domain event produced +Failure scenarios: + - Charge ID not found in references → Log error, don't produce event (manual review) + - Order not in Confirmed state → Log error, don't produce event + - Duplicate webhook → Idempotent handling (check if event already exists) + +--- External Event: geofence_exit +Trigger: Guest leaves hotel area (GPS geofence) +Precondition: Guest has opted in to location tracking +Translation logic: + 1. Extract userId and geoFenceId from webhook + 2. Validate guest is currently in hotel + 3. Check geofence_exit is "hotel-front-entrance" (not just any geofence) + 4. Create domain event: GuestLeftHotel { guestId: userId, timestamp, ... } +Success: Domain event produced +Failure scenarios: + - Guest hasn't opted in → Don't produce event (respect privacy) + - Guest not checked in → Don't produce event (shouldn't be in geofence) + - Unknown geofence → Log error, don't produce event +``` + +### 6. Handle Duplicates and Ordering + +External systems may send duplicate webhooks: + +``` +Problem: Stripe retries charge.succeeded webhook +Webhook 1: charge.succeeded { id: ch_123 } → Arrives at 10:00 AM +Webhook 2: charge.succeeded { id: ch_123 } → Arrives at 10:05 AM (retry) + +Solution: Idempotent translation + +Check before creating event: + 1. Extract external ID: ch_123 + 2. Query: Does PaymentAuthorized event exist with paymentGatewayRef = ch_123? + 3. If yes: Do nothing (already processed) + 4. If no: Create event + +This requires storing the external ID in the event: +PaymentAuthorized event { + orderId: order-123, + amount: 150.00, + paymentGatewayRef: ch_123, ← Store external ID for deduplication + ... + } +``` + +### 7. Handle Partial or Missing Information + +External systems may not provide complete data: + +``` +External Event: geofence_exit + +Available data: + - userId + - geoFenceId + - timestamp + - latitude, longitude (raw GPS) + +Missing data: + - Guest name (not in webhook payload) + - Reason for leaving (not tracked) + - Expected return time (not available) + +Handling strategy: +A. Translation enriches from our system: + Domain event: GuestLeftHotel { + guestId: userId, ← From webhook + timestamp: ..., ← From webhook + guestName: "John Smith", ← Looked up from guest stream + roomNumber: "502", ← Looked up from guest stream + geoFenceId: "front-entrance" ← From webhook + } + +B. Some data we don't need: + We ignore: latitude, longitude (we just care that guest left) + +C. Some data we can infer: + We can assume: Guest is now outside hotel + Cleaning crew can visit room +``` + +## Output Format + +Present as: + +````markdown +# External Event Translation: [Domain Name] + +## External Systems & Events + +### System: [External System Name] + +**Connection Type**: [Webhook/API polling/WebSocket/Streaming] + +**Events Received**: +- event1_name +- event2_name +- event3_name + +--- + +## Translation Rules + +### External Event: [Event Name] + +**Source System**: [System name] + +**Technical Representation**: +```json +{ + "field1": "value", + "field2": "value" +} +``` + +**Domain Translation**: +| External Field | Our Field | Mapping | Notes | +|---|---|---|---| +| externalId | n/a | Stored for deduplication | Reference only | +| customer | [lookup] | Look up our customer ID | Must correlate | + +**Correlation Method**: +[How do we link back to our domain entities?] + +**Domain Event Produced**: +- Event Name: [EventName] +- Fields: [List with sources] + +**Translation Logic**: +``` +1. Extract from webhook +2. Validate preconditions +3. Enrich from our system +4. Create domain event +``` + +**Success Scenario**: +[What success looks like] + +**Failure Scenarios**: +- Scenario 1: Consequence +- Scenario 2: Consequence + +**Duplicate Handling**: [Idempotent strategy] + +--- [Repeat for each external event] + +--- + +## Correlation Reference + +Track how external IDs map to our domain: + +| Our Entity | External System | External ID Field | Storage | Lookup | +|---|---|---|---|---| +| Order | Stripe | charge.id | OrderPaymentReference | By charge ID | +| Guest | GPS Service | userId | Guest stream | By userId | + +--- + +## Failure & Recovery + +### Webhook Arrives for Non-existent Order +**Symptom**: Stripe sends charge.succeeded for unknown order +**Cause**: Race condition or data inconsistency +**Detection**: OrderPaymentReference lookup returns nothing +**Recovery**: Log error, queue for manual review + +### Duplicate Webhooks +**Symptom**: Same webhook received multiple times +**Cause**: Stripe retry mechanism or network duplication +**Detection**: Domain event already exists with same externalRef +**Recovery**: Idempotent check prevents duplicate event creation + +--- + +## Testing Recommendations + +- [ ] Test happy path: External event → Correct domain event +- [ ] Test missing correlation: External event arrives before our order created +- [ ] Test duplicate: Same webhook processed twice +- [ ] Test invalid data: Webhook with missing required fields +- [ ] Test partial data: Webhook with some fields missing +- [ ] Test ordering: Multiple webhooks arrive out of order +```` + +## Quality Checklist + +- [ ] Every external event type has translation rules +- [ ] Correlation mechanism defined (how to link back to domain entities) +- [ ] External IDs captured for deduplication +- [ ] Missing data handled (enrichment from our system) +- [ ] Duplicate webhook handling implemented (idempotent) +- [ ] Failure scenarios documented +- [ ] Manual review process for unhandled cases +- [ ] No raw external IDs leak into domain model +- [ ] All external data validated before translation +- [ ] Timestamp handling is consistent +- [ ] Sensitive data from external systems handled properly + +## Common Translation Patterns + +### Pattern 1: Webhook to Event (Simple Mapping) +``` +External webhook → Validate → Map fields → Create domain event +Example: Payment gateway → PaymentAuthorized +``` + +### Pattern 2: Webhook with Correlation Lookup +``` +External webhook → Extract correlation ID → Look up our entity → +Enrich data → Create domain event +Example: GPS location + guestId → Look up guest room → GuestLeftHotel +``` + +### Pattern 3: API Polling (Scheduled Fetch) +``` +Scheduled job → Call external API → Extract events → +Translate → Create domain events +Example: Inventory availability check every 5 minutes +``` + +### Pattern 4: Webhook with Missing Context +``` +External webhook (partial data) → Extract what we have → +Query our system for missing context → Enrich → Create domain event +Example: Order confirmation from third-party fulfillment with only order ID +``` + +## Key Principles + +1. **Correlation First**: Always establish how to link external events to domain entities +2. **No Leakage**: Don't expose external IDs/data structures in your event model +3. **Translate Intent**: Translate the business meaning, not just map fields +4. **Idempotent**: Always handle duplicate external events gracefully +5. **Validate Always**: Verify external data before trusting it +6. **Enrich from Source**: Look up context from your system, not external system +7. **Default Gracefully**: Handle missing data with sensible defaults or explicit failure + +## Integration Patterns to Avoid + + **Direct External IDs**: Using Stripe charge ID as our primary ID + **No Correlation**: Translating events without way to correlate back + **Schema Leakage**: Exposing external JSON structure in domain events + **Unvalidated Data**: Trusting external data without verification + **Duplicate Processing**: No idempotent check, processes same webhook twice diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-validating-event-models-checklist/SKILL.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-validating-event-models-checklist/SKILL.md new file mode 100644 index 0000000..59344d7 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-validating-event-models-checklist/SKILL.md @@ -0,0 +1,339 @@ +--- +name: eventmodeling-validating-event-models-checklist +description: >- + Validate event-sourced CQRS models against 16 architectural checks across + 7 phases. Identifies anti-patterns and confirms compliance with event sourcing + principles. Use when reviewing event models for production readiness or after + completing event modeling steps. Do not use for: reviewing incomplete or + in-progress models (use eventmodeling-validating-event-models), or for + elaborating new scenarios (use eventmodeling-elaborating-scenarios). +allowed-tools: Write +--- + +# Event Model Validation Checklist Skill + +**Purpose**: Validate any event-sourced CQRS event model against 16 architectural checks across 7 phases. Identifies anti-patterns and confirms compliance with event sourcing principles. + +**Applies To**: Any domain - e-commerce, banking, SaaS, marketplace, healthcare, etc. + +**When to Use**: +- After completing Step 2 (Event Plot) of 7-step event modeling +- After completing Step 7 (Scenarios) before declaring model complete +- When reviewing an existing event model for production readiness +- When suspicious of architectural issues in event design + +**What It Does**: +1. Systematically applies 16 validation checks across 7 phases +2. Identifies violations of event sourcing principles (domain-agnostic) +3. Flags anti-patterns (calculations as events, non-entity streams, etc.) +4. Verifies read model/event distinction +5. Confirms stream independence and business rule enforcement +6. Returns pass/fail verdict with evidence + +--- + +## Validation Phases (Domain-Agnostic) + +### Phase 1: Event Stream & Command Handler State Validation (3 checks) +- Check 1.1: Each event belongs to exactly one stream +- Check 1.2: Each command handler owns its own [CommandHandler]State class +- Check 1.3: No hard dependencies between command handlers (orchestrated via events only) + +**Anti-pattern to catch**: Sharing state across handlers or treating state as persistent aggregate + +### Phase 2: Event Quality Validation (3 checks) +- Check 2.1: Events represent domain facts, not calculations +- Check 2.2: Event data is immutable after creation +- Check 2.3: Event names use past tense (what actually happened) + +**Anti-pattern to catch**: Storing computed/aggregated data as events + +### Phase 3: Read Model vs Event Distinction (2 checks) +- Check 3.1: Each read model is NOT an event stream +- Check 3.2: Read model has natural query pattern + +**Anti-pattern to catch**: Confusing projections/calculations with domain facts + +### Phase 4: Business Rules Validation (2 checks) +- Check 4.1: Constraints enforced in command handler decision logic (encapsulated in [CommandHandler]State) +- Check 4.2: Event preconditions are explicit (what state must exist before command is valid) + +**Anti-pattern to catch**: Business rules scattered across handlers or encoded in event stream structure + +### Phase 5: Data Traceability (1 check) +- Check 5.1: Input → Event → Read Model traceability is complete + +**Anti-pattern to catch**: Command inputs that disappear or read model fields without source + +### Phase 6: Event Flow Validation (1 check) +- Check 6.1: No impossible event sequences (state machine is sound) + +**Anti-pattern to catch**: Events that can occur in invalid state combinations + +### Phase 7: Stream Independence (1 check) +- Check 7.1: Each stream can be versioned/restored independently + +**Anti-pattern to catch**: Hard dependencies between streams + +### Final Questions (3 checks) +- Question 1: Could an architect unfamiliar with this domain understand the model in 15 minutes? +- Question 2: Could you change your core algorithm/calculation without changing event history? +- Question 3: Could this be implemented in your target technology stack (e.g., TypeScript + PostgreSQL)? + +--- + +## Output Format + +The skill returns a validation report with: + +### For Each Check +``` + Check 1.2: Stream Root is Business Entity, Not Calculation +Status: PASS +Evidence: [Specific examples from your model] +``` + +### Anti-Patterns Identified (if any) +``` +CRITICAL: [Anti-pattern description] +Problem: [Why it violates event sourcing] +Violates: [Which checks fail] +Fix: [Recommended action] +``` + +### Final Verdict +``` +Status: PASS (or PASS WITH WARNINGS or FAIL) +Implementation Ready: YES (or NO - fix issues first) +Confidence: [percentage] +``` + +--- + +## Common Anti-Patterns (Domain-Agnostic) + +### 1. Calculation Events +``` + ANTI-PATTERN: +CalculationPerformed { + metric: 4.5 ← Mutable/recalculated + timestamp: T +} + + CORRECT: +- Event: SomeActionOccurred (immutable fact) +- ReadModel: MetricView (recalculated from events) +``` + +**Why**: Calculations change multiple times as source data changes. Events are immutable. + +### 2. Shared vs Handler-Owned State +``` + ANTI-PATTERN: +One shared "OrderAggregate" class used by all handlers +- ConfirmOrderHandler shares OrderAggregate state +- ShipOrderHandler modifies same OrderAggregate +- Result: Tight coupling, hard to parallelize + + CORRECT: +Each handler owns its own [CommandHandler]State class +- ConfirmOrderState (only ConfirmOrderHandler uses) +- ShipOrderState (only ShipOrderHandler uses) +- CancelOrderState (only CancelOrderHandler uses) +- All reconstruct state from same events, but independently +``` + +**Why**: Each handler is a micro-slice. Separate state classes maintain isolation, enable parallel teams, prevent merge conflicts. + +### 3. Circular Dependencies +``` + ANTI-PATTERN: +StreamA → EventA → affects +StreamB → EventB → affects +StreamA (circular!) + + CORRECT: +StreamA → EventA → Event Bus +StreamB → EventB → Event Bus +ReadModels ← consume (one-way only) +No feedback loops +``` + +**Why**: Circular dependencies make the system hard to reason about and test. + +### 4. Persistent State vs Ephemeral State +``` + ANTI-PATTERN: +Treat [CommandHandler]State as persistent entity +- Save SubmitReviewState to database after command +- Load it again next time +- Result: Duplicates event sourcing, loses audit trail + + CORRECT: +Reconstruct [CommandHandler]State on-demand +- Load events from stream +- Replay via evolve() to rebuild state +- Process command, emit outcome events +- Discard state (it's ephemeral, not persisted) +``` + +**Why**: State is derived from events, never stored. Events are source of truth. This enables consistent replay, audit trails, and time-travel debugging. + +--- + +## Questions to Ask During Validation + +**For each event stream**: +1. "Do all events in this stream share the same identity (streamId)?" +2. "Could these events occur in any order, or is sequence important?" +3. "Is every event in this stream an immutable fact that actually happened?" + +**For each command handler**: +1. "Does this handler own its own [CommandHandler]State class?" +2. "Is the state ephemeral (reconstructed per command, not persisted)?" +3. "Can I trace the state reconstruction: events → evolve() → decision?" + +**For each read model**: +1. "Is this calculated from events via a projection?" +2. "Does it answer a specific query need?" +3. "Could its data change due to new events or state changes?" + +**For system architecture**: +1. "Does each command handler operate independently (communicate via events only)?" +2. "Could I run two handlers' code in parallel without merge conflicts?" +3. "Are the only shared artifacts the event definitions?" + +--- + +## Success Criteria + + **Model is validated when**: +- All 16 checks pass (or have documented workarounds) +- No critical anti-patterns identified +- All 3 final questions answer YES +- Event sourcing principles clearly upheld +- Ready to proceed to code generation + + **Model needs fixes when**: +- Any check fails with clear evidence +- Anti-patterns identified with specific violations +- Final questions have NO answers +- Fixes are straightforward and targeted + + **Model should be redesigned when**: +- Multiple phases fail +- Architectural assumptions are fundamentally flawed +- Anti-patterns are systemic and pervasive +- Would require rewriting core event structure + +--- + +## Example Validation Patterns + +### Pattern: Calculation vs Event +When you see something like "CalculationDone" or "ReviewRatingUpdated": +- Ask: "Is this immutable and caused by a user/system action?" +- If NO → It's a read model, not an event +- Fix: Remove from events, create read model projection instead + +### Pattern: Shared vs Isolated State +When you see "ReviewAggregate" used by multiple handlers: +- Ask: "Could SubmitReviewHandler and ApproveReviewHandler work on separate files?" +- If NO → State classes aren't properly isolated +- Fix: Create SubmitReviewState and ApproveReviewState, each handler owns one + +### Pattern: Persistent vs Ephemeral State +When state is saved to database after a command: +- Ask: "Is this state only needed during command processing?" +- If YES → It's ephemeral, reconstruct from events instead +- Fix: Load events, replay via evolve(), process command, discard state + +### Pattern: Data That Doesn't Trace +When a read model field appears without source: +- Ask: "Where did this come from?" +- If no event source → Add event or remove field +- If sourced from calculation → Verify it's in projection, not event + +--- + +## Integration with Event Modeling Process + +**Recommended timing**: +``` +Step 1: Brainstorm Events +Step 2: The Plot (Sequence) + ↓ +→ RUN eventmodeling-validating-event-models-checklist (catch structural issues early) + ↓ +Fix any violations + ↓ +Step 3-7: Complete remaining steps + ↓ +→ RUN eventmodeling-validating-event-models-checklist again (final validation) + ↓ +PASS → Code generation +FAIL → Fix identified issues +``` + +Running the checklist after Step 2 prevents wasting time on later steps if core events are flawed. + +--- + +## Checklist Questions by Domain + +The skill applies the same 16 checks regardless of domain. Here's how to think about it in different contexts: + +**E-commerce domain**: +- Events: OrderCreated, OrderConfirmed, PaymentAuthorized, OrderShipped +- NOT events: OrderTotal, InventoryLevel, ShippingCost (these are read models) + +**Banking domain**: +- Events: AccountOpened, DepositReceived, WithdrawalProcessed, FundsTransferred +- NOT events: AccountBalance, InterestCalculated (these are read models) + +**SaaS domain**: +- Events: SubscriptionCreated, PaymentProcessed, PlanUpgraded, SubscriptionCancelled +- NOT events: MonthlyRecurringRevenue, ChurnRate (these are read models) + +**Healthcare domain**: +- Events: PatientRegistered, AppointmentScheduled, ProcedureCompleted, BillGenerated +- NOT events: PatientAge, AverageCost (these are read models) + +The principle is the same across all domains: **immutable facts as events, calculated results as read models**. + +--- + +## Tips for Best Results + +1. **Be specific**: List actual event names, command handler names, and state classes from your model +2. **Reference your documentation**: Link to or quote from your step 1-7 documents and micro-slice plans +3. **Provide context**: Explain what your domain is and how handlers will be parallelized +4. **Ask follow-ups**: If a check flags an issue, ask "How do I fix this specifically?" or "Can this handler be isolated?" +5. **Iterate**: Run again after making fixes to confirm all checks pass and handlers are properly isolated + +## Quality Checklist + +- [ ] All 16 checks evaluated — no check skipped without documented justification +- [ ] Every FAIL result includes the specific event, handler, or stream that violated the check +- [ ] Anti-patterns identified by name with the exact model element that triggered the flag +- [ ] Final verdict is one of: PASS / PASS WITH WARNINGS / FAIL — no ambiguous outcomes +- [ ] All 3 final architectural questions answered YES before declaring model ready for implementation +- [ ] Any FAIL result has a recommended fix, not just a problem statement + +--- + +## Related Skills + +- **eventmodeling-orchestrating-event-modeling**: Main skill coordinating the 7-step event modeling process +- **eventmodeling-brainstorming-events**: Extract events from requirements (Step 1) +- **eventmodeling-plotting-events**: Sequence events chronologically (Step 2) +- **eventmodeling-designing-event-models**: Design your complete event model +- **eventmodeling-validating-event-models**: Detailed validator with deep analysis + +--- + +## Validation Checklist Reference + +The 16-point checklist is defined in the **Validation Phases** section above. +Each check includes the anti-pattern to catch and questions to ask when evaluating your model. + diff --git a/plugins/trogonstack-eventmodeling/skills/eventmodeling-validating-event-models/SKILL.md b/plugins/trogonstack-eventmodeling/skills/eventmodeling-validating-event-models/SKILL.md new file mode 100644 index 0000000..8630794 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/skills/eventmodeling-validating-event-models/SKILL.md @@ -0,0 +1,367 @@ +--- +name: eventmodeling-validating-event-models +description: >- + Step 9 of Event Modeling - Validate event-sourced models for completeness, + consistency, and event sourcing principles. Ensures events are immutable facts, + state projections are deterministic, and commands are pure. Identifies gaps and + suggests improvements before code generation. Use when reviewing models before + code generation. Do not use for: the structured 23-check production checklist + (use eventmodeling-validating-event-models-checklist) or field-level + completeness verification (use eventmodeling-checking-completeness). +allowed-tools: Write +--- + +# Validating Event Models + +## Core Architectural Rule (Non-Negotiable) + + **CRITICAL: Every command must have its own minimal state projection (NOT a DDD Aggregate)** What DDD calls an "aggregate root" is actually a READ MODEL. Command handlers must NEVER use read models for validation. + +This is the primary validation gate. If a model violates this rule, it fails validation immediately. + +```text +VIOLATION EXAMPLE (WILL FAIL VALIDATION): +OrderAggregate { orderId, customerId, items[], total, status, paymentId, address, shippedAt, cancelledAt, ... } + ↑ This is a READ MODEL, not command state +Used by: ConfirmOrder, ShipOrder, CancelOrder, ApproveReturn + REJECTED: This is DDD aggregate pattern (a read model), not event sourcing command state + +CORRECT PATTERN (PASSES VALIDATION): +ConfirmOrderState { status, orderId } +ShipOrderState { status, orderId, paymentId } +CancelOrderState { status, orderId, createdAt } +ApproveReturnState { status, orderId, paymentId } + APPROVED: Each command has minimal state + +OrderSummaryView { orderId, customerId, items[], total, status, paymentId, ... } + OK: This is a READ MODEL for UI queries, separate from command state +``` + +## Purpose +Ensures event-sourced models are complete, correct, and follow pure event sourcing principles (minimal per-command state). + +## Workflow + +When given an event model, perform comprehensive validation: + +### 1. Event Stream Completeness Check + +Verify each event stream has: +- Clear stream name (identity) +- At least one event type +- Initial event (what creates the stream) +- State transitions documented +- Deterministic state projection + +**For each event:** +- Uses past tense (Created, Confirmed, etc.) +- Contains **only facts** (no computed fields) +- All data is **immutable** +- Unique semantics (no duplicates) +- Includes timestamp/causality info + +**For each state projection:** +- Can be deterministically rebuilt from events +- Replay logic is pure (no side effects) +- Used only for command validation +- Can be safely discarded and regenerated + +**For each command:** +- Clear input parameters +- Validation rules (against state) +- Resulting events specified (or rejection reason) +- Pure logic (no side effects except event appending) + +### 2. Consistency Checks + +- [ ] **Event-Stream Mapping**: Every event belongs to exactly one stream +- [ ] **Command Outcomes**: Every command produces events OR documents rejection +- [ ] **Deterministic Projections**: State can only be derived one way from events +- [ ] **No Side Effects in Projections**: Pure state reconstruction logic +- [ ] **Event Immutability**: No event data is ever modified +- [ ] **Naming Consistency**: Are naming patterns consistent? + - Commands: Verb present (CreateOrder, ConfirmPayment) + - Events: Verb past tense (OrderCreated, PaymentConfirmed) + - Streams: Entity type + identity (Order:123, Payment:456) + +### 3. Event Sourcing Principles Compliance + +Check against event sourcing fundamentals: + +- [ ] **Events are Facts**: Events describe what happened, not potential futures + - "OrderMayBeConfirmed" → "OrderConfirmed" + - "PaymentPending" (in events) → "PaymentInitiated", "PaymentAuthorized" + +- [ ] **Events are Immutable**: No modification of event data + - "Update OrderCreated event with new total" → "Append OrderTotalCorrected event" + +- [ ] **Complete Event Data**: Events contain all facts needed for state rebuild + - Event: "OrderConfirmed" (missing paymentId) → Event includes paymentId + +- [ ] **No Computed Fields in Events**: Only raw captured facts + - OrderCreated includes "totalTax" (computed) → Includes items + amounts, tax computed in projection + +- [ ] **Deterministic Projections**: Replaying events always produces same state + - Projection uses: for each event, do X + - Projection uses: external API call during replay + +- [ ] **Stream Identity Clear**: Stream name uniquely identifies entity + - Order:order-123, Customer:cust-456 + - Orders collection with Order1, Order2 + +- [ ] **State is Derived**: Current state always comes from replaying events + - "Load state: replay all events for Order:123" + - "Load state: query database Orders table" + +### 4. Event Flow Validation + +- [ ] **Command → Event Mapping**: Clear what each command produces +- [ ] **No Zombie Commands**: Commands that never produce events (read-only OK) +- [ ] **Event Versioning**: How are old events handled if structure changes? +- [ ] **Compensation Events**: How are errors/reversals handled? + - "PaymentFailed event appended when payment declined" + - "Update payment event to status=failed" +- [ ] **Cross-Stream Communication**: Through events or external process? + - "OrderConfirmed event triggers InventoryReservation command" + - "Order directly modifies Inventory state" + +### 5. Role & Actor Attribution Validation + +Verify that every command has explicit actor attribution from the Role Catalog: + +- [ ] **Role Catalog exists**: A Role Catalog was defined in Step 1 (eventmodeling-brainstorming-events) + - CRITICAL: No Role Catalog found — commands have no actor attribution + - PASS: Role Catalog with human roles and system actors defined + +- [ ] **Every command has actor attribution**: No command uses generic "User" + - CRITICAL: `CreateOrder` attributed to "User" (which user? Customer? Admin? Seller?) + - PASS: `CreateOrder` attributed to "Customer" (specific role from catalog) + +- [ ] **Every human role has at least one command path**: No orphaned roles + - WARNING: "Support Agent" in Role Catalog but has zero commands + - PASS: Every role has at least one command + +- [ ] **Every human role has at least one read model**: Roles can see system state + - WARNING: "Seller" has no read model — how do they see their data? + - PASS: Every role has at least one view + +- [ ] **Permission boundaries respected**: Commands are only issued by authorized roles + - CRITICAL: `OverrideOrderStatus` not restricted to Support Agent role + - PASS: Each command's role matches the permission boundary in the catalog + +**Validation Verdict**: +If no Role Catalog exists → **REJECT MODEL — Role Catalog is a prerequisite** +If any command lacks actor attribution → **REJECT MODEL — all commands must have explicit role/actor** + +### 6. Command State Read Models Validation (CRITICAL) + + **This is the PRIMARY validation gate. Violations are CRITICAL and must be fixed before approval.** Validate that **command state read models** are **minimal and command-specific**, not bundled like DDD aggregates. + +**Note**: These are read models semantically categorized as "Command State" (optimized for command validation), as opposed to "Query Models" (optimized for UI queries). + +**CRITICAL RULE CHECK**: + +- [ ] **Naming Convention Compliance** - For automation tooling + - CRITICAL: Interface named `OrderState` (ambiguous - command? query?) + - PASS: `ConfirmOrderState` (clear: command state for ConfirmOrder) + - PASS: `ShipOrderStateToDo` (clear: planned, needs implementation) + - PASS: `OrderQueryModel` (clear: query read model) + +- [ ] **NO shared state between commands** - This is the #1 rule + - CRITICAL: "OrderState used by ConfirmOrder, ShipOrder, CancelOrder, ApproveReturn" + - PASS: "ConfirmOrderState for ConfirmOrder, ShipOrderState for ShipOrder, etc." + +- [ ] **Each command has its own state interface** - CRITICAL: Only one OrderState interface for all commands + - PASS: ConfirmOrderState, ShipOrderState, CancelOrderState, ApproveReturnState + +- [ ] **No Full Aggregate State**: Commands don't load all entity fields upfront + - CRITICAL: "ConfirmOrder loads: { status, items[], total, shipping, paymentId, customer details, ... }" + - PASS: "ConfirmOrder loads only: { status, orderId }" + +- [ ] **State Only For Validation**: No unused fields in state + - "ShipOrderState has exactly: { status, orderId, paymentId } — all needed" + - CRITICAL: "ShipOrderState has: { status, orderId, paymentId, items[], total, address, ... } but only uses status and paymentId" + +- [ ] **Per-Command State Shapes**: Different interfaces for different commands + - ConfirmOrderState: { status, orderId } + - ShipOrderState: { status, orderId, paymentId } (DIFFERENT) + - CancelOrderState: { status, orderId, createdAt } + - CRITICAL: All use the same OrderState + +**Validation Verdict**: +If ANY command shares state with another command → **REJECT MODEL - CRITICAL VIOLATION** + +### 7. Command & State Validation + +- [ ] **State-Based Decisions**: Commands decide based on current state only +- [ ] **Valid State Transitions**: Document what state changes are allowed +```text +Draft → Confirmed (ConfirmOrder) +Draft → Cancelled (CancelOrder) +Confirmed → Shipped (ShipOrder) +Confirmed ↛ Draft (invalid) +``` +- [ ] **Preconditions Clear**: When can each command execute? + - "Can only confirm if state is Draft" + - "Can sometimes confirm" +- [ ] **Error Handling**: What happens if validation fails? + - "Reject with ValidationError, no events appended" + - "Append ErrorEvent and continue" + +### 8. Projection Validation + +- [ ] **Read Models Separate from Command State**: Read models are rich projections, NOT the command-validation state +- [ ] **Read Models Optional**: Are they needed or just convenience? +- [ ] **Serve Real Queries**: Each read model answers a specific question + - "OrderSummaryView serves 'get orders by customer' query" + - "OrderDetailsView duplicates all data from OrderState" +- [ ] **Consistent Update**: All relevant events update the read model +- [ ] **Regenerable**: Can be rebuilt from events at any time + +### 9. Issues & Recommendations Report + +Format findings as: + +```markdown +# Event Model Validation Report: [Domain] + +## Issues Found + +### Critical (Must Fix) +1. **Stream Root**: Order + **Issue**: No command for order cancellation + **Impact**: Cannot model cancellation requirement + **Fix**: Add CancelOrder command with OrderCancelled event + +2. **Event**: PaymentProcessed + **Issue**: Missing payment method in event data + **Impact**: Cannot determine if card declined, etc. + **Fix**: Add paymentMethod, authCode fields + +3. **State Design**: Order stream + **Issue**: ConfirmOrder loads full OrderState with items[], shipping, etc. + **Impact**: Violates minimal state principle + **Fix**: ConfirmOrder should load only: { status, orderId } + +### Warnings (Should Consider) +1. **Stream Root**: Order + **Issue**: Events contain computed total instead of raw amounts + **Recommendation**: Store line item amounts in event, compute total in read models + **Rationale**: Events are facts, computations belong in projections + +2. **ReadModel**: CustomerDashboard + **Issue**: Denormalizes data from 3 stream roots + **Recommendation**: Ensure dashboard is truly for querying, not command validation + **Rationale**: Read models support UI queries, not decision logic + +## Completeness Analysis + +| Aspect | Status | Details | +|--------|--------|---------| +| Stream Roots | Complete | 5 stream roots identified | +| Commands | 80% | Missing: ReactivateAccount | +| Events | Complete | 18 events cover all transitions | +| State Designs | 70% | Several have unnecessary fields for validation | +| Read Models | Complete | 4 views cover query needs | + +## Event Sourcing Compliance + +- Immutable Events: 100% +- Minimal Command State: 75% +- Stream Root Clarity: Clear identities +- Event Sourcing Pattern: Follows ES principles +- CQRS Separation: Command state vs Read models clear + +## Validation Summary + +**Overall Status**: Ready with recommendations + +**Blockers for Implementation**: 0 critical issues + +**Recommended Fixes**: +1. Add missing OrderCancelled event +2. Move PaymentMethod to its own minimal state projection +3. Document all implicit invariants explicitly + +**Ready for Code Generation**: Yes, after implementing recommendations + +## Next Steps +1. Review recommendations with domain expert +2. Update model with critical fixes +3. Proceed to code generation +``` + +## Validation Scoring + +Provide a score for each dimension (0-100): +- **Completeness**: Do all requirements have corresponding model elements? +- **Consistency**: Are all patterns applied uniformly? +- **Correctness**: Do business rules match domain expert knowledge? +- **Clarity**: Are invariants and constraints explicit? +- **Projection/Command-State Compliance**: Does every command use its own minimal state projection, with no command handler reading from a query/read model for validation? + +Overall: **Ready for Implementation** if all critical issues are resolved. + +## Common Issues to Flag + +| Issue | Pattern | Fix | +|-------|---------|-----| +| Missing cancellation flows | No "Cancelled" events | Add compensation paths | +| Implicit invariants | "Obviously can't do X" | Make invariants explicit | +| Command state too broad | Shared state used by 2+ commands | Split into per-command minimal state projections | +| Orphaned events | Events no one listens to | Link to projections or commands | +| No read models | Commands reading query/read models for validation | Add separate query read models; keep command state minimal | +| Circular dependencies | Projection A depends on B, B on A | Redesign stream boundaries | + +## Key Principles for Event Sourcing + +1. **Events are the source of truth**: Everything else is derived from them +2. **Immutable event log**: Events never change, only appended +3. **State is a projection**: Current state is built by replaying events +4. **Commands are pure decisions**: Validate against state, produce events or reject +5. **Projections are optional**: Can be rebuilt at any time +6. **Stream per entity**: Each entity has one append-only event stream + +## Success Criteria + +Your event model validation is successful when: + +- All requirements are captured in events +- Commands clearly trigger events +- Stream roots have clear, minimal boundaries +- Business rules are explicit invariants (not hidden assumptions) +- Read models serve actual query needs (not used by commands) +- Command state is minimal and command-specific (not shared across multiple commands) +- Events are immutable facts (past tense, no computed fields) +- State can be deterministically rebuilt from events +- All command-to-event mappings are documented +- Critical issues are resolved or documented as known limitations + +A model is **ready for code generation** if: +- No critical issues remain +- All command state follows naming convention (e.g., `[CommandName]State`) +- No state is shared between different commands +- All events are immutable facts +- All business rules are explicit +- A Role Catalog exists with all human roles and system actors +- Every command has explicit actor attribution from the Role Catalog + +## Quality Checklist + +- [ ] All events are immutable facts (past tense) +- [ ] No computed fields stored in events +- [ ] State projection is deterministic from events +- [ ] Commands validate against current state only +- [ ] Each command either produces events or rejects (no silent failures) +- [ ] Event causality/command-event mapping is clear +- [ ] State transitions are documented +- [ ] No direct references between streams +- [ ] Projections serve specific query needs (or are removed) +- [ ] Everything can be rebuilt from the event stream +- [ ] Command state naming follows `[CommandName]State` convention +- [ ] No state is shared between different commands +- [ ] All command state is minimal (only fields needed for validation) +- [ ] **Role Catalog exists with human roles and system actors** +- [ ] **Every command attributed to a specific role/actor (no generic "User")** +- [ ] **Every human role has at least one command and one read model** +- [ ] **Permission boundaries from Role Catalog are respected**