npx claudepluginhub jwilger/claude-code-plugins --plugin sdlcThis skill uses the workspace's default tool permissions.
Dispatches parallel agents to independently tackle 2+ tasks like separate test failures or subsystems without shared state or dependencies.
Executes pre-written implementation plans: critically reviews, follows bite-sized steps exactly, runs verifications, tracks progress with checkpoints, uses git worktrees, stops on blockers.
Guides idea refinement into designs: explores context, asks questions one-by-one, proposes approaches, presents sections for approval, writes/review specs before coding.
Version: 1.0.0 Portability: High
Teaches Event Modeling facilitation based on Martin Dilger's "Understanding Eventsourcing" methodology, enabling systematic discovery of business domains and design of event-sourced systems through structured conversation.
Purpose: Reveal hidden domain knowledge, create shared understanding, and design systems that "don't lose information" through immutable event streams.
Scope:
The Principle: Store what happened (events), not just current state. Events are immutable facts that can be replayed, analyzed, and projected.
Why this matters: State-only systems lose the "why" behind current state. Event streams preserve full history, enabling audit trails, temporal queries, and business intelligence impossible with CRUD.
How to apply:
Example:
# ❌ State-only (information lost)
User { balance: $50 }
# Can't answer: How did they get $50? What transactions occurred?
# ✓ Event stream (complete history)
UserRegistered { userId: 123, initialBalance: $0 }
MoneyDeposited { userId: 123, amount: $100, timestamp: T1 }
MoneyWithdrawn { userId: 123, amount: $30, timestamp: T2 }
MoneyWithdrawn { userId: 123, amount: $20, timestamp: T3 }
# Can answer: How? When? Why? What sequence?
# Current state: Project events → balance = $50
The Principle: Event modeling is a structured conversation that surfaces hidden assumptions and creates shared understanding. You cannot skip steps because you think you understand.
Why this matters: Domain experts have tacit knowledge they don't know they have. The systematic process of event modeling extracts this knowledge through probing questions.
How to apply:
Example of revelation:
Facilitator: "What happens after the order is placed?"
Expert: "We fulfill it."
Facilitator: "And then what happens?"
Expert: "Well, first we check inventory..."
Facilitator: "And then?"
Expert: "If items are in stock, we reserve them."
Facilitator: "What if items aren't in stock?"
Expert: "Oh! We backorder them. I guess we need BackorderCreated event..."
# ↑ Hidden complexity revealed through questioning
The Principle: Events are immutable facts that happened, named in past tense using domain language that business experts understand.
Why this matters: Events form the foundation of system behavior and audit logs. Clear, business-aligned names make the system comprehensible to non-technical stakeholders.
Event naming rules:
How to apply:
❌ Bad (technical, present tense):
- ProcessPayment
- UpdateUser
- DeleteItem
✓ Good (business, past tense):
- PaymentReceived
- EmailAddressChanged
- ItemRemovedFromCart
The Principle: Start with broad domain discovery before diving deep into any single workflow.
Why this matters: Jumping into detailed workflow design without understanding the broader domain leads to siloed thinking and missing connections between workflows.
The Two Phases:
How to apply:
# Phase 1: Domain Discovery (broad)
- Business: E-commerce platform
- Actors: Customers, Sellers, Admins
- Major processes: Product browsing, ordering, payment, fulfillment, returns
- External systems: Stripe (payment), ShipStation (shipping)
- Workflows to model: Order placement, Returns, Inventory management
- Start with: Order placement (most critical)
# Phase 2: Workflow Design (deep, one at a time)
- Order placement workflow: User goal → Events → Commands → Read Models → Automations
- Returns workflow: (separate branch, after order placement)
- Inventory management: (separate branch, after returns)
Rationale: Event modeling is a facilitation technique for revealing domain knowledge, not a technical design exercise. Keep it focused on business behavior.
Scenario: Starting a new project or major feature.
Phase 1: Domain Discovery
Questions to ask:
Example (E-commerce):
1. Business: Online marketplace connecting sellers and buyers
2. Actors:
- Customers (buy products)
- Sellers (list products, fulfill orders)
- Admins (moderate, handle disputes)
3. Major processes:
- Product catalog management
- Order placement and fulfillment
- Payment processing
- Returns and refunds
- Shipping and tracking
4. External systems:
- Stripe (payments)
- ShipStation (shipping)
- Sendgrid (email)
5. Workflows to model:
- Order placement (critical path)
- Product listing
- Returns processing
6. Start with: Order placement (generates revenue, most complex)
Output: docs/event_model/domain/overview.md
Phase 2: Workflow Design (per workflow)
The Seven Steps:
Step 1: Identify User Goal
Question: "What is the user trying to accomplish?"
Answer: "Customer wants to purchase products"
Goal: Complete a purchase from cart to payment
Step 2: Brainstorm Events (sticky-note style)
Question: "What facts need recording?"
Events (no order yet):
- OrderPlaced
- PaymentReceived
- InventoryReserved
- OrderConfirmationSent
- ShippingAddressValidated
- TaxCalculated
- ...
Step 3: Order Events Chronologically
Timeline (left to right):
1. ShippingAddressValidated
2. TaxCalculated
3. OrderPlaced
4. PaymentReceived
5. InventoryReserved
6. OrderConfirmationSent
Step 4: Identify Commands
For each event, what triggered it?
ShippingAddressValidated ← ValidateShippingAddress
TaxCalculated ← CalculateTax
OrderPlaced ← PlaceOrder
PaymentReceived ← (external: Stripe webhook)
InventoryReserved ← ReserveInventory (automation)
OrderConfirmationSent ← SendOrderConfirmation (automation)
Step 5: Design Read Models
Question: "What does each actor need to see?"
Customer needs:
- OrderSummary (items, total, status)
- ShippingAddress
- PaymentStatus
Seller needs:
- OrdersToFulfill (list)
- InventoryLevels
Admin needs:
- AllOrders (dashboard)
- PaymentIssues (monitoring)
Step 6: Find Automations
Event → Process → Command → Event
OrderPlaced → CheckInventory → ReserveInventory → InventoryReserved
PaymentReceived → SendConfirmation → SendOrderConfirmation → OrderConfirmationSent
Step 7: Map External Integrations
External System → Translation → Internal Event
Stripe webhook → process payment data → PaymentReceived
ShipStation API → track shipment → ShipmentDispatched
Output: docs/event_model/workflows/order-placement.md
Pattern 1: State Change
Command → Event (only way to modify state)
PlaceOrder → OrderPlaced
CancelOrder → OrderCancelled
AddItemToCart → ItemAddedToCart
Pattern 2: State View
Events → Read Model (query stored events)
[OrderPlaced, ItemAdded, ItemAdded, ItemRemoved] → ShoppingCart
[UserRegistered, EmailChanged, PasswordReset] → UserProfile
Command Independence: Commands derive their inputs from user-provided
data and the event stream — never from read models. No ReadModel → Command
edges should appear in diagrams. If a command needs to check whether something
already happened (e.g., idempotency guard), it checks the event stream, not a
read model.
No Infrastructure Read Models: Read models represent meaningful domain projections. Infrastructure preconditions ("does directory exist?", "is service running?") that are implicit in the command's execution context do not need their own read model.
Pattern 3: Automation
Event → Read Model (todo list) → Process → Command → Event
All four components required:
1. Triggering event
2. Read model consulted (the "todo list")
3. Conditional process logic (a decision based on state)
4. Resulting command producing new events
If there is no read model and no conditional logic, it is NOT an automation —
it is a command producing multiple events. Model as a single State Change slice.
TRUE automation:
OrderPlaced → UnfulfilledOrders (read model) → CheckInventory (if in stock) → ReserveInventory → InventoryReserved
NOT an automation:
PlaceOrder → [OrderPlaced, AuditLogCreated] (unconditional co-production, one Command slice)
Pattern 4: Translation
External Data → Internal Event (anti-corruption layer)
StripeWebhook{charge.succeeded} → PaymentReceived
PayPalIPN{payment_status: completed} → PaymentReceived
ShipStationWebhook{shipped} → ShipmentDispatched
Note: Translation slices handle external business data (payment confirmations, shipping updates). Generic infrastructure (event persistence, message transport) is NOT a Translation — it is cross-cutting implementation detail that does not belong in any workflow's slice list.
Good Vertical Slice:
Name: "Customer can place an order"
Flow:
[View Cart] → PlaceOrder → OrderPlaced → [Show Confirmation]
Complete:
- UI component (cart page, checkout button)
- Command handler (PlaceOrder)
- Event (OrderPlaced)
- Read model update (OrderSummary)
- UI update (confirmation page)
Value: Customer can complete purchase
Testable: End-to-end in isolation
Bad Slices (avoid):
❌ "Set up order database" - Technical, no user value
❌ "Implement order system" - Too broad, not independently testable
❌ "Create Order table" - Implementation detail, not behavior
Slice characteristics:
Slice Independence: Slices sharing an event schema are independent — the event schema is the shared contract. Command slices test by asserting on produced events; view slices test with synthetic event fixtures. Neither needs the other implemented first. No artificial dependency chains.
Principle: Every read model attribute must trace back to an event.
Example:
Read Model: OrderSummary
- orderId ← OrderPlaced.orderId
- customerId ← OrderPlaced.customerId
- items ← ItemAdded, ItemRemoved events
- totalAmount ← OrderPlaced.totalAmount
- shippingAddress ← ShippingAddressValidated.address
- status ← OrderPlaced, PaymentReceived, OrderShipped, OrderDelivered
✓ All fields trace to events (information complete)
Missing data example:
Read Model: OrderSummary
- estimatedDelivery ← ??? (no event provides this)
Problem: Need ShippingEstimateCalculated event
or
Solution: Calculate from ShippingAddressValidated + ShippingMethod
Works well with:
Prerequisites:
Problem: Discussing databases, APIs, frameworks during event modeling
Solution: Stop. Event modeling is about behavior, not implementation. Architecture decisions come later.
Example:
❌ Bad:
"We'll store orders in PostgreSQL with a relational schema..."
✓ Good:
"OrderPlaced event contains order data. Read models built from events."
Problem: "I understand the domain, let's skip brainstorming events"
Solution: Follow all seven steps. The process reveals hidden knowledge.
Problem: Events named CreateOrderDTO, ProcessPaymentTransaction
Solution: Use business language: OrderPlaced, PaymentReceived
Problem: Stopping too early, missing edge cases and automations
Solution: Keep asking. After every event, every answer, keep probing.
Example:
"Order is placed"
→ "And then what happens?"
"Payment is processed"
→ "And then what happens?"
"Inventory is reserved"
→ "And then what happens?"
"Confirmation email is sent"
→ "And then what happens?"
"Order appears in seller dashboard"
→ "And then what happens?" (continue until workflow complete)
Problem: Jumping between workflows during design
Solution: Complete one workflow fully (all seven steps) before starting next. Use separate branches/PRs.
User Goal: Create an account to access the platform
Step 2: Brainstorm Events
- UserRegistered
- EmailVerificationSent
- EmailVerified
- WelcomeEmailSent
- ProfileCreated
Step 3: Order Chronologically
1. UserRegistered (user submits form)
2. EmailVerificationSent (system sends email)
3. EmailVerified (user clicks link)
4. ProfileCreated (system creates profile)
5. WelcomeEmailSent (system sends welcome)
Step 4: Identify Commands
RegisterUser → UserRegistered
(automatic) → EmailVerificationSent
VerifyEmail → EmailVerified
(automatic) → ProfileCreated
(automatic) → WelcomeEmailSent
Step 5: Design Read Models
User sees:
- RegistrationStatus (pending, verified)
System needs:
- UnverifiedUsers (admin monitoring)
- UserProfile (for authenticated users)
Step 6: Find Automations
UserRegistered → GenerateVerificationToken → SendVerificationEmail → EmailVerificationSent
EmailVerified → CreateDefaultProfile → CreateProfile → ProfileCreated
ProfileCreated → SendWelcome → SendWelcomeEmail → WelcomeEmailSent
Step 7: Map External Integrations
SendGrid API → email sent status → EmailDelivered (optional tracking)
Vertical Slice:
"User can register and verify email"
UI: Registration form → Submit
Command: RegisterUser
Events: UserRegistered, EmailVerificationSent
UI: "Check your email" message
UI: Email link → Click
Command: VerifyEmail
Events: EmailVerified, ProfileCreated
UI: "Account verified" redirect to dashboard
User Goal: Purchase items from cart
Initial Brainstorm:
- OrderPlaced
- PaymentReceived
- InventoryReserved
Facilitation reveals edge cases:
Facilitator: "What if payment fails?"
Expert: "We retry 3 times, then mark order as failed"
Added events:
- PaymentFailed
- PaymentRetried
- OrderFailed
Facilitator: "What if inventory isn't available?"
Expert: "We backorder and notify customer"
Added events:
- InventoryUnavailable
- BackorderCreated
- BackorderNotificationSent
Complete Event Timeline:
Happy path:
1. OrderPlaced
2. PaymentReceived
3. InventoryReserved
4. OrderConfirmationSent
Payment failure path:
1. OrderPlaced
2. PaymentFailed
3. PaymentRetried
4. PaymentFailed
5. PaymentRetried
6. PaymentReceived (or OrderFailed after 3 retries)
Inventory unavailable path:
1. OrderPlaced
2. PaymentReceived
3. InventoryUnavailable
4. BackorderCreated
5. BackorderNotificationSent
Automations:
PaymentFailed → WaitAndRetry → RetryPayment → (PaymentReceived or PaymentFailed)
InventoryUnavailable → CheckBackorder → CreateBackorder → BackorderCreated
State Change (explicit):
User clicks "Place Order" button
→ PlaceOrder command
→ OrderPlaced event
→ Order aggregate state changes to "Pending"
State View (projection):
Events:
- ItemAddedToCart{productId: 1, quantity: 2}
- ItemAddedToCart{productId: 2, quantity: 1}
- ItemRemovedFromCart{productId: 1, quantity: 1}
Read Model (ShoppingCart):
- items: [
{productId: 1, quantity: 1}, # 2 added - 1 removed
{productId: 2, quantity: 1}
]
- totalItems: 2
Automation (workflow):
OrderPlaced event published
↓
InventoryService listens
↓
Checks available inventory
↓
Publishes ReserveInventory command
↓
InventoryReserved event published
Translation (anti-corruption):
Stripe webhook payload:
{
"event": "charge.succeeded",
"data": {
"id": "ch_123",
"amount": 5000,
"currency": "usd"
}
}
↓ Translation layer
Internal event:
PaymentReceived {
paymentId: "ch_123",
orderId: "<our-order-id>",
amount: Money(50.00, USD),
timestamp: "2026-02-04T10:30:00Z",
source: "Stripe"
}
Use these questions to drive event modeling sessions:
Domain Discovery:
User Goal:
Events:
Timeline:
Commands:
Read Models:
Automations:
Edge Cases:
Use this checklist to verify event modeling quality:
Domain Discovery:
Per Workflow:
Event Quality:
Information Completeness:
ReadModel → Command data flows (commands depend on user inputs and event stream)Source Documentation:
Related Skills:
External Resources:
Extraction Source: sdlc plugin (event-modeling.md, docs/event-modeling/methodology.md) Extraction Date: 2026-02-04 Last Updated: 2026-02-04 Compatibility: High portability (universal methodology, any tech stack) License: MIT