You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: skills/df-ddd-event-storming-design/SKILL.md
+83Lines changed: 83 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -239,6 +239,78 @@ Do not regenerate the whole model unless the user asks or the existing model is
239
239
- Treat CQRS as a modeling perspective: commands change business state through the domain model; queries are satisfied by read models.
240
240
- Read models should record their information sources, but query needs must not create domain events by themselves. A read-model-only field can come from current-state lookup, query-side joins, technical projection inputs, external sources, or accepted event payloads.
241
241
- Iterate when commands, events, aggregates, or read models do not explain each other.
242
+
- Treat commands, events, aggregate state, aggregate methods, and read-model fields as design claims that need proof. If the proof is only "the table/API/page has this field", downgrade the item to discovery material until a business rule or consumer proves it belongs.
243
+
244
+
## Design Proof Gates
245
+
246
+
Use these gates before finalizing commands, events, aggregates, aggregate methods, or read models. They are mandatory when reviewing or persisting a model.
- non-query consumer: actor option, command-side rule, policy/process, aggregate relationship, lifecycle, or downstream business capability affected by the fact
255
+
- read-model impact, if any: which projection changes and which fields change
256
+
257
+
Keep brainstormed but rejected events only in `候选事件池与筛选`, not in the formal `领域事件清单` or aggregate event list. If an item only repairs a projection, display, report, cache, operation log, or troubleshooting view, reject it as a domain event and record the alternative source.
258
+
259
+
### Command Granularity Gate
260
+
261
+
Design commands from actor intent or external fact input boundaries, not from permutations of possible events.
262
+
263
+
- One command may produce multiple events when those outcomes belong to the same actor intent and consistency boundary.
264
+
- Do not create separate commands merely because different event combinations are possible.
265
+
- Do not create one "apply/sync/update all" command unless the initiating actor or external system is actually submitting one authoritative fact package and the aggregate can make the decision coherently.
266
+
- When a command can produce multiple events, explain why the events are the result of one business decision instead of independent actions.
267
+
268
+
### Aggregate State Necessity Gate
269
+
270
+
For every aggregate state item or property, prove at least one direct use:
271
+
272
+
- a command/business method reads it to decide whether an action is allowed
273
+
- an invariant or uniqueness rule depends on it
274
+
- it affects event production, rejection, splitting, or payload enrichment
275
+
- it represents identity, lifecycle, ownership, parentage, or another state needed to enforce consistency
276
+
277
+
If no current or confirmed future business method uses the state item, remove it from the aggregate design. Reclassify it as read-model data, persistence metadata, audit/log material, synchronization metadata, or unresolved discovery material.
278
+
279
+
### Identity And Uniqueness Gate
280
+
281
+
Model identity and uniqueness by actor/source, not as one generic "name/code must be unique" rule.
282
+
283
+
For each uniqueness rule, record:
284
+
285
+
- who relies on it: human actor, import operator, external master system, downstream system, or policy
286
+
- identity fields and scope: tenant, company, parent, external ID, code, name, effective date, or other boundary
- conflict result: reject, correct, merge, override, ignore, or log-only
289
+
290
+
If different actors use different identity rules, keep them as separate rules even when they touch the same subject.
291
+
292
+
### Lifecycle Removal Gate
293
+
294
+
For delete, unregister, close, archive, disable, or decommission behavior, prove:
295
+
296
+
- the exact business meaning of removal
297
+
- the real blocking business fact, not just indirect structural children
298
+
- whether historical references remain valid
299
+
- whether restoration exists as a real business capability; if not, do not add restore commands or events
300
+
- which downstream actor, policy, rule, or read model changes after removal
301
+
302
+
### Read Model Source Gate
303
+
304
+
For every read-model field, record its source:
305
+
306
+
- accepted domain event payload or projection
307
+
- current-state lookup from command-side persistence
308
+
- query-side join
309
+
- technical projection input
310
+
- audit/log/troubleshooting source
311
+
- external read source
312
+
313
+
Do not add a domain event only to populate a read-model field. A missing read-model field is a sourcing question first and a domain-event gap only when a non-query business consumer exists.
242
314
243
315
## Traceability Rules
244
316
@@ -534,13 +606,19 @@ Before finalizing, check:
534
606
- Every important event has an affected actor, subject, command-side rule, policy/process, aggregate, or downstream business relationship.
535
607
- Current-domain state-changing events are published by aggregates unless a clear exception is recorded.
536
608
- Every command has the information it needs from command fields plus aggregate state/history.
609
+
- Every command is justified by actor intent or an external fact input boundary, not by an arbitrary event-combination permutation.
610
+
- If one command may publish multiple events, those events are explained as outcomes of one business decision inside one consistency boundary.
537
611
- Meaningful command outcomes are represented as events.
538
612
- Generic events such as `信息已变更` have been replaced by specific facts or explicitly justified.
613
+
- Rejected candidate events are not retained in accepted event catalogs, aggregate event lists, or implementation-alignment lists.
539
614
- Every read model records whether each field comes from accepted events, current-state lookup, query-side joins, technical projection inputs, enriched payloads, or external read sources.
540
615
- Every read-model-only field is marked as query-side data, technical projection input, current-state lookup, audit/log material, or external-source data instead of being promoted to a domain event.
541
616
- Policies do not hide aggregate invariants.
542
617
- Domain services do not become procedural service layers.
543
618
- Aggregates are derived from behavior, rules, identity, lifecycle, and invariants, not tables, CRUD resources, or noun lists.
619
+
- Every aggregate property is directly used by at least one command/business method, invariant, uniqueness rule, event production decision, lifecycle decision, or consistency relationship.
620
+
- Human-maintained identity rules and external-system identity rules are separated when they use different scopes or keys.
621
+
- Removal/decommission rules identify the real blocking business fact, historical-reference behavior, and downstream consequence.
544
622
- Aggregates are neither too large nor too fragmented.
545
623
- Query needs do not pollute aggregate state.
546
624
@@ -560,6 +638,11 @@ Refuse or correct these patterns:
560
638
- Treating external master-data sync as a simple upsert when ordering, dependency, failure, or conflict resolution has business meaning.
561
639
- Creating domain events for technical actions the business does not care about.
562
640
- Creating domain events only because a read model, page, report, cache, or projection needs a field refreshed.
641
+
- Keeping rejected candidate events in final event lists, aggregate files, or implementation checklists.
642
+
- Creating command permutations from possible event combinations instead of actor intent or external fact input.
643
+
- Adding "source type", "current status", "description", display names, or other fields to aggregate state when no aggregate method or invariant uses them.
644
+
- Collapsing different identity rules into one generic uniqueness statement when human actors and upstream systems use different scopes or keys.
645
+
- Adding restore behavior because it is technically possible when no business capability exists.
563
646
- Putting report/page/query fields into aggregates for convenience.
564
647
- Putting most business rules into command handlers, application services, listeners, repositories, or policies.
565
648
- Splitting bounded contexts before understanding the current problem domain.
Copy file name to clipboardExpand all lines: skills/df-ddd-event-storming-design/references/anti-patterns.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -14,6 +14,12 @@
14
14
- Upsert sync modeling: treat external master-data synchronization as a simple create/update when the business cares about dependency ordering, conflict handling, missing parent records, retries, or failure status.
15
15
- Read model leakage: add page/report fields to aggregate state only because a query needs them.
16
16
- Projection-driven event: create a domain event only because a read model, page, report, cache, or projection needs a field refreshed.
17
+
- Rejected candidate leakage: keep brainstormed-but-rejected events in final event catalogs, aggregate event lists, or implementation-alignment checklists.
18
+
- Command permutation explosion: create commands from possible event combinations rather than actor intent, external fact input, and consistency boundary.
19
+
- Unused aggregate state: add properties to an aggregate because a table, API, projection, or UI has them even though no aggregate method, invariant, uniqueness rule, lifecycle rule, or event decision uses them.
20
+
- Generic uniqueness rule: collapse actor-specific identity rules into a single "name/code must be unique" statement when human maintenance and upstream systems use different scopes, keys, or conflict handling.
21
+
- Invented restoration: add restore commands/events only because deletion is modeled, without a confirmed restoration business capability.
22
+
- Indirect removal guard: block removal by structural children rather than the real business fact that matters to the domain.
17
23
- Framework-shaped domain: treat controllers, DTOs, repositories, or packages as the domain model.
18
24
- Unproduced event: keep a domain event without a command, policy, process, or external fact that can produce it.
19
25
- Unexplained read source: define a read model field without identifying whether it comes from accepted events, current-state lookup, query-side joins, technical projection input, enriched payloads, audit/log data, external sources, or a confirmed domain-event gap.
0 commit comments