[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6X3SCVFB00B00M507HARSFS":3,"skill-same:01M6X3SCVFB00B00M507HARSFS":88},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":28,"publishedAt":49,"linkOnly":50,"markdownContent":51,"markdownBody":52,"frontMatter":53,"refName":61,"commitSha":62,"skillDirectory":63,"forksCount":14,"repositoryHtmlUrl":64,"repositoryHomepageUrl":65,"ownerHtmlUrl":66,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":67,"install":68,"resources":81},"01M6X3SCVFB00B00M507HARSFS","domain-driven-design",null,"Domain-Driven Design strategic and tactical patterns — bounded contexts, aggregates, value objects, context mapping. Use when modeling a complex business domain, defining microservice boundaries, designing aggregates, establishing a ubiquitous language, or refactoring a big ball of mud into well-defined contexts.","projectious-work\u002Fprocesskit","projectious-work","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F263889726?v=4","01M6N97TJJ118WQ35CHRV8RD0E","projectious.work","01M6N97TPWJPF0BMKYQ4PBY5W8",0,"MIT","https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Farchive\u002Fprocesskit-install-20261101\u002Fcontext\u002Ftemplates\u002Fprocesskit\u002Fv0.7.0\u002Fskills\u002Fdomain-driven-design\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48],"domain driven design","driven","domain","design","tactical","when","value","mud","v1","strategic","modeling","aggregates","objects","use","business","work","refactoring","ubiquitous language","microservice","architecture","2026-11-10 10:12:30",false,"---\nname: domain-driven-design\ndescription: |\n  Domain-Driven Design strategic and tactical patterns — bounded contexts, aggregates, value objects, context mapping. Use when modeling a complex business domain, defining microservice boundaries, designing aggregates, establishing a ubiquitous language, or refactoring a big ball of mud into well-defined contexts.\nmetadata:\n  processkit:\n    apiVersion: processkit.projectious.work\u002Fv1\n    id: SKILL-domain-driven-design\n    version: \"1.1.0\"\n    created: 2026-04-06T00:00:00Z\n    category: architecture\n---\n\n# Domain-Driven Design\n\n## Intro\n\nDDD has two halves: strategic design (bounded contexts, context maps,\nubiquitous language) and tactical design (aggregates, entities, value\nobjects, domain events, repositories). Use it when the business logic\nis the differentiator and the cost of getting the model wrong is\nhigh.\n\n## Overview\n\n### Ubiquitous language\n\nBefore writing any code, build a shared vocabulary with domain\nexperts. Identify key terms and write down precise definitions.\nReject technical jargon in the model — use `Order`, `Shipment`,\n`PolicyRenewal`, not `EntityManager` or `ServiceHandler`. If two\nteams use the same word differently, that is a strong signal of two\ndistinct bounded contexts. Maintain a glossary in the project docs;\nclass names, method names, and variable names should all reflect the\nlanguage.\n\n### Strategic design — bounded contexts\n\nA bounded context is a boundary within which a single domain model\nand ubiquitous language apply. To find them:\n\n- Map the business capabilities (ordering, billing, shipping,\n  inventory).\n- Look for linguistic boundaries — where the same word means\n  different things (`Product` in catalog vs warehouse).\n- Align with team ownership — one team per context is ideal.\n- Start coarse, split later. Merging contexts is harder than\n  splitting.\n\nEach bounded context has its own domain model (its own `Customer`\nclass, not shared), its own data store or schema, and communicates\nwith others through well-defined interfaces.\n\n### Context mapping\n\nDefine how bounded contexts relate. The deeper reference lives in\n`references\u002Fddd-building-blocks.md`.\n\n| Pattern | Relationship | Use when |\n|---|---|---|\n| Shared Kernel | Two contexts share a small common model | Tightly coupled teams co-evolving a shared piece |\n| Customer-Supplier | Upstream supplies, downstream consumes | Clear dependency, upstream accommodates downstream |\n| Conformist | Downstream conforms to upstream's model | You cannot influence upstream (third-party API) |\n| Anti-Corruption Layer | Downstream translates upstream's model | Protecting your model from a legacy or external system |\n| Open Host Service | Upstream provides a well-defined protocol | Many consumers, upstream publishes a stable API |\n| Published Language | Shared interchange format (JSON schema, Avro) | Cross-context communication needs a neutral format |\n| Separate Ways | No integration | Contexts have no meaningful interaction |\n\nDefault recommendation: use an Anti-Corruption Layer when integrating\nwith any external or legacy system. It prevents foreign concepts from\nleaking into your domain.\n\n### Tactical design — aggregates\n\nAn aggregate is a cluster of domain objects treated as a single unit\nfor data changes. Rules:\n\n- **One aggregate root** — external references point only at the\n  root.\n- **Protect invariants** — the aggregate enforces business rules\n  within its boundary.\n- **Small aggregates** — prefer small aggregates that reference each\n  other by ID, not by object reference.\n- **One transaction modifies one aggregate** — cross-aggregate\n  consistency is eventual.\n- **Identity** — aggregate roots have a globally unique ID; internal\n  entities have locally unique IDs.\n\nThe classic mistake is making aggregates too large. If `Order`\ncontains `Customer` contains `Address`, any address change locks the\nentire order. Reference `customerId` instead.\n\n### Entities, value objects, and domain events\n\n**Entities** have identity and a lifecycle. Two entities with\nidentical attributes but different IDs are different. Implement\nequality by ID.\n\n**Value objects** are defined entirely by their attributes and are\nimmutable. Two value objects with the same attributes are equal.\nPrefer `EmailAddress` over `String`, `Money` over `float`.\n\n**Domain events** record something meaningful that has happened.\nNamed in past tense (`OrderPlaced`, `PaymentReceived`,\n`InventoryReserved`), immutable, carry enough data for consumers to\nreact without querying back, and published only after the state\nchange is persisted.\n\n### Repositories, services, factories\n\n- **Repositories** provide collection-like access to aggregates. One\n  per aggregate root. Interface in the domain layer, implementation\n  in infrastructure. Methods speak domain (`find_pending_by_customer`),\n  not SQL.\n- **Domain services** hold logic that does not naturally belong to a\n  single entity (e.g. `TransferService.transfer(from, to, amount)`).\n  Stateless. Use sparingly — most logic should live on aggregates.\n- **Factories** encapsulate complex creation when validation,\n  defaults, or multi-step initialization are involved.\n\n### Example workflows\n\n- **E-commerce domain:** identify contexts (Catalog, Ordering,\n  Payment, Shipping, Inventory). Aggregates: `Product` in Catalog,\n  `Order` with `OrderLine` in Ordering, `Shipment` in Shipping. Value\n  objects: `Money`, `Address`, `SKU`. Ordering integrates with\n  Inventory through events (reserve stock); Payment uses an ACL to\n  the gateway.\n- **Reviewing a god aggregate:** a `Customer` containing `Orders`,\n  `Addresses`, `PaymentMethods`, and `Preferences` locks the world on\n  any address change. Split into `Customer` (profile), `Order`\n  (references customerId), `PaymentMethod` (references customerId),\n  each its own aggregate.\n- **Splitting a monolith:** map existing code to business\n  capabilities via event storming. Identify contexts by linguistic\n  boundaries and team ownership. Propose a context map with ACLs at\n  legacy boundaries and pub\u002Fsub between contexts. Extract the most\n  independent context first.\n\n## Gotchas\n\nAgent-specific failure modes — provider-neutral pause-and-self-check items:\n\n- **Anemic domain model — entities as data bags with all logic in services.** When `Order` is a plain struct with getters and setters and all business logic lives in `OrderService`, you get the complexity of objects without the benefit of encapsulation. The aggregate cannot enforce its own invariants. Move business behavior onto entities and aggregates so they protect their own rules.\n- **God aggregate that locks everything.** An `Order` aggregate that contains the full `Customer`, all their `Addresses`, their `PaymentMethods`, and their `Preferences` means any address change locks the entire customer's orders. Cross-aggregate references should be by ID, not by object reference. One transaction modifies one aggregate.\n- **Defining bounded contexts prematurely before understanding the domain.** Starting with microservices boundaries drawn on a whiteboard before any code is written produces contexts that split along technical lines (auth service, data service) rather than domain lines. Work in a modular monolith first, discover actual linguistic and team-ownership boundaries through usage, then extract.\n- **Shared database tables across bounded contexts.** Two bounded contexts reading and writing the same `users` table are not actually bounded — they are tightly coupled through the database schema. Every schema change must coordinate across contexts. Each bounded context must own its data store or, at minimum, its own schema within a shared database.\n- **Publishing domain events before persisting the state change.** Publishing an `OrderSubmitted` event before the database write commits means the event is out in the world but the state change failed — consumers react to an event whose cause doesn't exist. Use the outbox pattern: write event and state change in the same transaction; publish from the outbox asynchronously.\n- **Using technical event names instead of domain language.** `UserEntityUpdatedEvent` describes an implementation detail. `CustomerEmailVerified` describes something that happened in the domain. Events must be named in past tense using ubiquitous language so they are meaningful to domain experts, not just developers.\n- **Treating value objects as mutable.** A `Money` object that can have its `amount` mutated after construction is not a value object — it is a mutable entity without identity. Value objects must be immutable: to \"change\" a value, create a new instance. Immutability makes equality-by-value safe and enables value objects to be shared.\n\n## Full reference\n\n### Aggregate example\n\n```python\nclass Order:  # Aggregate root\n    def __init__(self, order_id, customer_id):\n        self.id = order_id\n        self.customer_id = customer_id  # reference by ID, not object\n        self.lines = []                  # internal entities\n        self.status = \"draft\"\n\n    def add_line(self, product_id, quantity, unit_price):\n        if self.status != \"draft\":\n            raise DomainError(\"Cannot modify a submitted order\")\n        self.lines.append(OrderLine(product_id, quantity, unit_price))\n\n    def submit(self):\n        if not self.lines:\n            raise DomainError(\"Cannot submit empty order\")\n        self.status = \"submitted\"\n        return OrderSubmitted(self.id, self.total())\n```\n\nExternal code should reference only `Order` and call `add_line` \u002F\n`submit`; nothing reaches into `OrderLine` directly. The root\nenforces every invariant in the cluster.\n\n### Value object example\n\n```python\n@dataclass(frozen=True)\nclass Money:\n    amount: Decimal\n    currency: str\n\n    def __post_init__(self):\n        if self.amount \u003C 0:\n            raise ValueError(\"Amount cannot be negative\")\n        if self.currency not in VALID_CURRENCIES:\n            raise ValueError(f\"Invalid currency: {self.currency}\")\n\n    def add(self, other: \"Money\") -> \"Money\":\n        if self.currency != other.currency:\n            raise DomainError(\"Cannot add different currencies\")\n        return Money(self.amount + other.amount, self.currency)\n```\n\nSelf-validating, immutable, equal-by-attributes. To \"change\" a value,\nconstruct a new instance.\n\n### Domain event example\n\n```python\n@dataclass(frozen=True)\nclass OrderSubmitted:\n    order_id: str\n    customer_id: str\n    total: Money\n    items: list[OrderLineSnapshot]\n    occurred_at: datetime\n```\n\nPast tense. Immutable. Carries the data consumers need so they do\nnot have to call back to the producing service. Published only after\nthe state change is persisted.\n\n### Repository example\n\n```python\n# Domain layer — interface\nclass OrderRepository(Protocol):\n    def find_by_id(self, order_id: OrderId) -> Order | None: ...\n    def save(self, order: Order) -> None: ...\n    def find_pending_by_customer(\n        self, customer_id: CustomerId\n    ) -> list[Order]: ...\n\n# Infrastructure layer — implementation\nclass PostgresOrderRepository:\n    def find_by_id(self, order_id: OrderId) -> Order | None:\n        row = self.db.query(\"SELECT ... WHERE id = %s\", order_id)\n        return self._to_aggregate(row) if row else None\n```\n\nThe interface speaks domain language and returns fully reconstituted\naggregates. The infrastructure implementation hides SQL and ORM\ndetails.\n\n### Anti-patterns\n\n- **Anemic domain model** — entities are data bags with\n  getters\u002Fsetters and all logic lives in services. Move behavior onto\n  entities and aggregates.\n- **God aggregate** — one massive aggregate that locks everything.\n  Split into smaller aggregates connected by ID references.\n- **Leaking context** — using another context's types directly.\n  Introduce an ACL or map to local types.\n- **Premature contexts** — defining bounded contexts before\n  understanding the domain. Start with a modular monolith and\n  discover boundaries through usage.\n- **Shared database** — multiple contexts reading and writing the\n  same tables. Each context owns its own store or at least its own\n  schema.\n- **Technical event names** (`OrderUpdatedEvent`) instead of domain\n  names (`OrderSubmitted`).\n- **Publishing events before persisting state** — leads to\n  inconsistency on failure. Use the outbox pattern.\n- **Comparing entities by attributes** instead of ID.\n- **Exposing setters** — use intention-revealing methods like\n  `change_email`, not `set_email`.\n\n### Pattern selection notes\n\n- **Shared Kernel** is high-coupling. Use only within a single team.\n- **Anti-Corruption Layer** is the default for external integrations\n  — it isolates your model from foreign concepts.\n- **Open Host Service + Published Language** is best when many\n  consumers depend on a stable upstream API.\n","# Domain-Driven Design\n\n## Intro\n\nDDD has two halves: strategic design (bounded contexts, context maps,\nubiquitous language) and tactical design (aggregates, entities, value\nobjects, domain events, repositories). Use it when the business logic\nis the differentiator and the cost of getting the model wrong is\nhigh.\n\n## Overview\n\n### Ubiquitous language\n\nBefore writing any code, build a shared vocabulary with domain\nexperts. Identify key terms and write down precise definitions.\nReject technical jargon in the model — use `Order`, `Shipment`,\n`PolicyRenewal`, not `EntityManager` or `ServiceHandler`. If two\nteams use the same word differently, that is a strong signal of two\ndistinct bounded contexts. Maintain a glossary in the project docs;\nclass names, method names, and variable names should all reflect the\nlanguage.\n\n### Strategic design — bounded contexts\n\nA bounded context is a boundary within which a single domain model\nand ubiquitous language apply. To find them:\n\n- Map the business capabilities (ordering, billing, shipping,\n  inventory).\n- Look for linguistic boundaries — where the same word means\n  different things (`Product` in catalog vs warehouse).\n- Align with team ownership — one team per context is ideal.\n- Start coarse, split later. Merging contexts is harder than\n  splitting.\n\nEach bounded context has its own domain model (its own `Customer`\nclass, not shared), its own data store or schema, and communicates\nwith others through well-defined interfaces.\n\n### Context mapping\n\nDefine how bounded contexts relate. The deeper reference lives in\n`references\u002Fddd-building-blocks.md`.\n\n| Pattern | Relationship | Use when |\n|---|---|---|\n| Shared Kernel | Two contexts share a small common model | Tightly coupled teams co-evolving a shared piece |\n| Customer-Supplier | Upstream supplies, downstream consumes | Clear dependency, upstream accommodates downstream |\n| Conformist | Downstream conforms to upstream's model | You cannot influence upstream (third-party API) |\n| Anti-Corruption Layer | Downstream translates upstream's model | Protecting your model from a legacy or external system |\n| Open Host Service | Upstream provides a well-defined protocol | Many consumers, upstream publishes a stable API |\n| Published Language | Shared interchange format (JSON schema, Avro) | Cross-context communication needs a neutral format |\n| Separate Ways | No integration | Contexts have no meaningful interaction |\n\nDefault recommendation: use an Anti-Corruption Layer when integrating\nwith any external or legacy system. It prevents foreign concepts from\nleaking into your domain.\n\n### Tactical design — aggregates\n\nAn aggregate is a cluster of domain objects treated as a single unit\nfor data changes. Rules:\n\n- **One aggregate root** — external references point only at the\n  root.\n- **Protect invariants** — the aggregate enforces business rules\n  within its boundary.\n- **Small aggregates** — prefer small aggregates that reference each\n  other by ID, not by object reference.\n- **One transaction modifies one aggregate** — cross-aggregate\n  consistency is eventual.\n- **Identity** — aggregate roots have a globally unique ID; internal\n  entities have locally unique IDs.\n\nThe classic mistake is making aggregates too large. If `Order`\ncontains `Customer` contains `Address`, any address change locks the\nentire order. Reference `customerId` instead.\n\n### Entities, value objects, and domain events\n\n**Entities** have identity and a lifecycle. Two entities with\nidentical attributes but different IDs are different. Implement\nequality by ID.\n\n**Value objects** are defined entirely by their attributes and are\nimmutable. Two value objects with the same attributes are equal.\nPrefer `EmailAddress` over `String`, `Money` over `float`.\n\n**Domain events** record something meaningful that has happened.\nNamed in past tense (`OrderPlaced`, `PaymentReceived`,\n`InventoryReserved`), immutable, carry enough data for consumers to\nreact without querying back, and published only after the state\nchange is persisted.\n\n### Repositories, services, factories\n\n- **Repositories** provide collection-like access to aggregates. One\n  per aggregate root. Interface in the domain layer, implementation\n  in infrastructure. Methods speak domain (`find_pending_by_customer`),\n  not SQL.\n- **Domain services** hold logic that does not naturally belong to a\n  single entity (e.g. `TransferService.transfer(from, to, amount)`).\n  Stateless. Use sparingly — most logic should live on aggregates.\n- **Factories** encapsulate complex creation when validation,\n  defaults, or multi-step initialization are involved.\n\n### Example workflows\n\n- **E-commerce domain:** identify contexts (Catalog, Ordering,\n  Payment, Shipping, Inventory). Aggregates: `Product` in Catalog,\n  `Order` with `OrderLine` in Ordering, `Shipment` in Shipping. Value\n  objects: `Money`, `Address`, `SKU`. Ordering integrates with\n  Inventory through events (reserve stock); Payment uses an ACL to\n  the gateway.\n- **Reviewing a god aggregate:** a `Customer` containing `Orders`,\n  `Addresses`, `PaymentMethods`, and `Preferences` locks the world on\n  any address change. Split into `Customer` (profile), `Order`\n  (references customerId), `PaymentMethod` (references customerId),\n  each its own aggregate.\n- **Splitting a monolith:** map existing code to business\n  capabilities via event storming. Identify contexts by linguistic\n  boundaries and team ownership. Propose a context map with ACLs at\n  legacy boundaries and pub\u002Fsub between contexts. Extract the most\n  independent context first.\n\n## Gotchas\n\nAgent-specific failure modes — provider-neutral pause-and-self-check items:\n\n- **Anemic domain model — entities as data bags with all logic in services.** When `Order` is a plain struct with getters and setters and all business logic lives in `OrderService`, you get the complexity of objects without the benefit of encapsulation. The aggregate cannot enforce its own invariants. Move business behavior onto entities and aggregates so they protect their own rules.\n- **God aggregate that locks everything.** An `Order` aggregate that contains the full `Customer`, all their `Addresses`, their `PaymentMethods`, and their `Preferences` means any address change locks the entire customer's orders. Cross-aggregate references should be by ID, not by object reference. One transaction modifies one aggregate.\n- **Defining bounded contexts prematurely before understanding the domain.** Starting with microservices boundaries drawn on a whiteboard before any code is written produces contexts that split along technical lines (auth service, data service) rather than domain lines. Work in a modular monolith first, discover actual linguistic and team-ownership boundaries through usage, then extract.\n- **Shared database tables across bounded contexts.** Two bounded contexts reading and writing the same `users` table are not actually bounded — they are tightly coupled through the database schema. Every schema change must coordinate across contexts. Each bounded context must own its data store or, at minimum, its own schema within a shared database.\n- **Publishing domain events before persisting the state change.** Publishing an `OrderSubmitted` event before the database write commits means the event is out in the world but the state change failed — consumers react to an event whose cause doesn't exist. Use the outbox pattern: write event and state change in the same transaction; publish from the outbox asynchronously.\n- **Using technical event names instead of domain language.** `UserEntityUpdatedEvent` describes an implementation detail. `CustomerEmailVerified` describes something that happened in the domain. Events must be named in past tense using ubiquitous language so they are meaningful to domain experts, not just developers.\n- **Treating value objects as mutable.** A `Money` object that can have its `amount` mutated after construction is not a value object — it is a mutable entity without identity. Value objects must be immutable: to \"change\" a value, create a new instance. Immutability makes equality-by-value safe and enables value objects to be shared.\n\n## Full reference\n\n### Aggregate example\n\n```python\nclass Order:  # Aggregate root\n    def __init__(self, order_id, customer_id):\n        self.id = order_id\n        self.customer_id = customer_id  # reference by ID, not object\n        self.lines = []                  # internal entities\n        self.status = \"draft\"\n\n    def add_line(self, product_id, quantity, unit_price):\n        if self.status != \"draft\":\n            raise DomainError(\"Cannot modify a submitted order\")\n        self.lines.append(OrderLine(product_id, quantity, unit_price))\n\n    def submit(self):\n        if not self.lines:\n            raise DomainError(\"Cannot submit empty order\")\n        self.status = \"submitted\"\n        return OrderSubmitted(self.id, self.total())\n```\n\nExternal code should reference only `Order` and call `add_line` \u002F\n`submit`; nothing reaches into `OrderLine` directly. The root\nenforces every invariant in the cluster.\n\n### Value object example\n\n```python\n@dataclass(frozen=True)\nclass Money:\n    amount: Decimal\n    currency: str\n\n    def __post_init__(self):\n        if self.amount \u003C 0:\n            raise ValueError(\"Amount cannot be negative\")\n        if self.currency not in VALID_CURRENCIES:\n            raise ValueError(f\"Invalid currency: {self.currency}\")\n\n    def add(self, other: \"Money\") -> \"Money\":\n        if self.currency != other.currency:\n            raise DomainError(\"Cannot add different currencies\")\n        return Money(self.amount + other.amount, self.currency)\n```\n\nSelf-validating, immutable, equal-by-attributes. To \"change\" a value,\nconstruct a new instance.\n\n### Domain event example\n\n```python\n@dataclass(frozen=True)\nclass OrderSubmitted:\n    order_id: str\n    customer_id: str\n    total: Money\n    items: list[OrderLineSnapshot]\n    occurred_at: datetime\n```\n\nPast tense. Immutable. Carries the data consumers need so they do\nnot have to call back to the producing service. Published only after\nthe state change is persisted.\n\n### Repository example\n\n```python\n# Domain layer — interface\nclass OrderRepository(Protocol):\n    def find_by_id(self, order_id: OrderId) -> Order | None: ...\n    def save(self, order: Order) -> None: ...\n    def find_pending_by_customer(\n        self, customer_id: CustomerId\n    ) -> list[Order]: ...\n\n# Infrastructure layer — implementation\nclass PostgresOrderRepository:\n    def find_by_id(self, order_id: OrderId) -> Order | None:\n        row = self.db.query(\"SELECT ... WHERE id = %s\", order_id)\n        return self._to_aggregate(row) if row else None\n```\n\nThe interface speaks domain language and returns fully reconstituted\naggregates. The infrastructure implementation hides SQL and ORM\ndetails.\n\n### Anti-patterns\n\n- **Anemic domain model** — entities are data bags with\n  getters\u002Fsetters and all logic lives in services. Move behavior onto\n  entities and aggregates.\n- **God aggregate** — one massive aggregate that locks everything.\n  Split into smaller aggregates connected by ID references.\n- **Leaking context** — using another context's types directly.\n  Introduce an ACL or map to local types.\n- **Premature contexts** — defining bounded contexts before\n  understanding the domain. Start with a modular monolith and\n  discover boundaries through usage.\n- **Shared database** — multiple contexts reading and writing the\n  same tables. Each context owns its own store or at least its own\n  schema.\n- **Technical event names** (`OrderUpdatedEvent`) instead of domain\n  names (`OrderSubmitted`).\n- **Publishing events before persisting state** — leads to\n  inconsistency on failure. Use the outbox pattern.\n- **Comparing entities by attributes** instead of ID.\n- **Exposing setters** — use intention-revealing methods like\n  `change_email`, not `set_email`.\n\n### Pattern selection notes\n\n- **Shared Kernel** is high-coupling. Use only within a single team.\n- **Anti-Corruption Layer** is the default for external integrations\n  — it isolates your model from foreign concepts.\n- **Open Host Service + Published Language** is best when many\n  consumers depend on a stable upstream API.\n",{"name":5,"metadata":54,"description":60},{"processkit":55},{"id":56,"created":57,"version":58,"category":48,"apiVersion":59},"SKILL-domain-driven-design",1775433600000,"1.1.0","processkit.projectious.work\u002Fv1","Domain-Driven Design strategic and tactical patterns — bounded contexts, aggregates, value objects, context mapping. Use when modeling a complex business domain, defining microservice boundaries, designing aggregates, establishing a ubiquitous language, or refactoring a big ball of mud into well-defined contexts.\n","main","4876a92620ee792aac2ac9a1a806322d8a572367","archive\u002Fprocesskit-install-20261101\u002Fcontext\u002Ftemplates\u002Fprocesskit\u002Fv0.7.0\u002Fskills\u002Fdomain-driven-design","https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit","https:\u002F\u002Fprojectious-work.github.io\u002Fprocesskit\u002F","https:\u002F\u002Fgithub.com\u002Fprojectious-work","2026-11-09 00:53:29",{"source":8,"skillName":5,"commands":69,"prompt":79,"zipAvailable":80},[70,73,76],{"tool":71,"command":72},"npx","npx skills add projectious-work\u002Fprocesskit --skill domain-driven-design",{"tool":74,"command":75},"bunx","bunx skills add projectious-work\u002Fprocesskit --skill domain-driven-design",{"tool":77,"command":78},"pnpm","pnpm dlx skills add projectious-work\u002Fprocesskit --skill domain-driven-design","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Farchive\u002Fprocesskit-install-20261101\u002Fcontext\u002Ftemplates\u002Fprocesskit\u002Fv0.7.0\u002Fskills\u002Fdomain-driven-design\u002FSKILL.md",true,[82],{"path":83,"resourceType":84,"resourceTypeDesc":85,"sizeBytes":86,"sourceHtmlUrl":87},"references\u002Fddd-building-blocks.md","REFERENCE","参考文档",6847,"https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Farchive\u002Fprocesskit-install-20261101\u002Fcontext\u002Ftemplates\u002Fprocesskit\u002Fv0.7.0\u002Fskills\u002Fdomain-driven-design\u002Freferences\u002Fddd-building-blocks.md",[89,113,133,154,170,188],{"skillNo":90,"name":91,"nameZh":6,"description":92,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":93,"categories":94,"keywords":98,"publishedAt":49},"01M6X5MTC89B4ZGXW3JVSQCPF8","skill-management","Manage Skill package manifests as v1 ontology entities.","https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Fsrc\u002Fcontext\u002Fskills\u002Fprocesskit\u002Fskill-management\u002FSKILL.md",[95],{"categoryNo":96,"categoryName":97,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[99,100,101,102,103,104,44,105,106,107,91,108,109,110,37,111,112],"management","skill management","create","update","package","alpha","list","manage","ontology","get","as","manifests","skill package","transition",{"skillNo":114,"name":115,"nameZh":6,"description":116,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":117,"categories":118,"keywords":120,"publishedAt":49},"01M6X5MCV74NHW5MEDNHZRF2C8","schema-management","Manage generated processkit schema contracts through deterministic MCP rebuild and inspection workflows.","https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Fsrc\u002Fcontext\u002Fskills\u002Fprocesskit\u002Fschema-management\u002FSKILL.md",[119],{"categoryNo":96,"categoryName":97,"taxonomyType":21,"taxonomyTypeDesc":22},[99,121,122,123,124,125,104,44,126,127,106,128,129,130,108,131,132],"schema","schema management","MCP","workflows","validation","generated","rebuild","contracts","wed","deterministic","contract","mode",{"skillNo":134,"name":135,"nameZh":6,"description":136,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":137,"categories":138,"keywords":139,"publishedAt":49},"01M6X5M5G6YJ96AMZGSCZJ1D13","proposition-management","Record claims, risks, beliefs, world facts, WSJF estimates, and assumptions through the Proposition interface.","https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Fsrc\u002Fcontext\u002Fskills\u002Fprocesskit\u002Fproposition-management\u002FSKILL.md",[],[99,140,141,101,102,142,104,44,143,144,145,146,108,147,148,149,150,151,152,153],"proposition","proposition management","index","log","world","record","query","creation","event","interface","updates","facts","claims","WSJF",{"skillNo":155,"name":156,"nameZh":6,"description":157,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":158,"categories":159,"keywords":160,"publishedAt":49},"01M6X5KMQ83QN9M6MPWZM7344F","ontology-management","Manage generated v1 ontology entities that do not require a dedicated domain server.","https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Fsrc\u002Fcontext\u002Fskills\u002Fprocesskit\u002Fontology-management\u002FSKILL.md",[],[99,107,161,101,104,162,163,126,164,143,106,165,31,108,166,167,148,168,37,169],"ontology management","lifecycle","archive","roadmap","do","iteration","keep","measurement","generic",{"skillNo":171,"name":172,"nameZh":6,"description":173,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":174,"categories":175,"keywords":176,"publishedAt":49},"01M6X5KCY2DN3SM21RERSFNEBT","okf-compatibility","Import, export, and validate conformant Open Knowledge Format bundles.","https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Fsrc\u002Fcontext\u002Fskills\u002Fprocesskit\u002Fokf-compatibility\u002FSKILL.md",[],[177,178,179,180,104,181,182,183,44,184,185,186,187],"okf","compatibility","okf compatibility","validate","open","knowledge","format","export","bundles","bundle","import",{"skillNo":189,"name":190,"nameZh":6,"description":191,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":192,"categories":193,"keywords":194,"publishedAt":49},"01M6X5JA8S5PNGJVFW4EQY8T83","capability-management","Manage versioned Capability entities and their governed lifecycle.","https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Fsrc\u002Fcontext\u002Fskills\u002Fprocesskit\u002Fcapability-management\u002FSKILL.md",[],[99,195,196,101,102,142,104,162,44,105,143,197,106,145,108,167,148,149,198,112],"capability","capability management","queries","changes"]