Agent skill
domain-sidnovais-healthcore
Implement a complete domain feature in an HC.LIS module — business rules, domain events, aggregate changes, and unit tests following DDD conventions.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/domain-sidnovais-healthcore
SKILL.md
/domain
You are a domain modeling expert for the HC.LIS Modular Monolith. Your job is to implement a complete domain feature — from business rules and domain events to entity/aggregate changes and unit tests — following every HC.LIS convention exactly.
Invocation format
/domain [ModuleName?] <requirement description>
Examples:
/domain TestOrders accept an exam/domain cancel an order item with a reason
Phase 1 — Resolve module
Extract ModuleName from the arguments (first PascalCase word).
- If not provided: list the subdirectories of
src/HC.LIS/HC.LIS.Modules/and ask the user to pick one. - If provided but the directory
src/HC.LIS/HC.LIS.Modules/{ModuleName}/does not exist: stop with a clear error — do not guess or create the module.
Phase 2 — Exploration (read-only, before writing any code)
Read these files to understand the module's domain model:
- List the directory tree of
src/HC.LIS/HC.LIS.Modules/{ModuleName}/Domain/to identify aggregates, entities, existing events, and existing rules. - Read the aggregate root file (e.g.,
Domain/Orders/Order.cs) — understand existing command methods,Apply()dispatch, andWhen()handlers. - Read relevant child entity files (e.g.,
Domain/Orders/OrderItem.cs) — understandCheckRule()patterns. - Read all existing domain event files in
Domain/{Aggregate}/Events/to understand naming and structure. - Read a sample business rule file from
Domain/{Aggregate}/Rules/to understand the exception+rule pattern. - Read the unit test file(s) under
Tests/UnitTests/to understandAssertPublishedDomainEvent<T>()andAssertBrokenRule<TRule>()usage. - Read any factory file (e.g.,
Tests/UnitTests/Orders/OrderFactory.cs) and the sample data file (e.g.,OrderSampleData.cs) to understand test setup.
Do NOT skip any of these reads — the generated code must fit into existing code, not invent new patterns.
Phase 3 — Clarify if needed
Before writing any code, check if any of these are ambiguous:
- Which aggregate or entity owns the behavior?
- What state transitions are involved? (e.g., which statuses block the action?)
- What parameters does the command take?
- Are there related rules that guard the transition?
If uncertain, ask the user one focused question. Do not generate speculative code.
Phase 4 — Generate all artifacts
Implement all of the following in one pass. Do not stop at one file.
4a. Domain event
File: src/HC.LIS/HC.LIS.Modules/{ModuleName}/Domain/{Aggregate}/Events/{Aggregate}{Action}DomainEvent.cs
Rules:
- Inherits
DomainEventfromHC.Core.Domain - Uses primary constructor syntax (C# 12+)
- Properties initialized inline from constructor parameters
- Store primitives only (Guid, string, DateTime, bool, int, decimal) — never value objects or entities
- File-scoped namespace (no outer
{}block)
Pattern:
using System;
using HC.Core.Domain;
namespace HC.LIS.Modules.{ModuleName}.Domain.{Aggregate}.Events;
public class {Aggregate}{Action}DomainEvent(
Guid {aggregateId},
// ... other primitive params
) : DomainEvent
{
public Guid {AggregateId} { get; } = {aggregateId};
// ... other properties
}
4b. Business rule(s)
File: src/HC.LIS/HC.LIS.Modules/{ModuleName}/Domain/{Aggregate}/Rules/Cannot{X}Rule.cs
One file per rule. The exception class and the rule class live in the same file — exception first, rule second.
Exception class rules:
- Name:
{Action}{X}Exception(e.g.,AcceptOrderItemMoreThanOnceException) - Inherits
BaseBusinessRuleException - Must have exactly 4 overloads:
(),(string message),(string message, Exception innerException),(IBusinessRule rule)
Rule class rules:
- Name:
Cannot{X}Rule(e.g.,CannotAcceptOrderItemMoreThanOnceRule) - Implements
IBusinessRule - Uses primary constructor; stores args in
private readonlyfields via body IsBroken()returns a bool expression against the field(s)ThrowException()callsthrow new {Exception}(this)Messageproperty returns a human-readable string
Pattern:
using HC.Core.Domain;
namespace HC.LIS.Modules.{ModuleName}.Domain.{Aggregate}.Rules;
public class {Action}{X}Exception : BaseBusinessRuleException
{
public {Action}{X}Exception() { }
public {Action}{X}Exception(string message) : base(message) { }
public {Action}{X}Exception(string message, System.Exception innerException) : base(message, innerException) { }
public {Action}{X}Exception(IBusinessRule rule) : base(rule) { }
}
public class Cannot{X}Rule(
{StateType} actualState
) : IBusinessRule
{
private readonly {StateType} _actualState = actualState;
public bool IsBroken() => /* condition */;
public void ThrowException() => throw new {Action}{X}Exception(this);
public string Message => "...";
}
4c. Aggregate root — add command method and When() handler
Edit the aggregate root file. Add:
-
A public command method:
- Creates a new domain event (primitives only — unwrap value objects)
- Calls
Apply(domainEvent) - Calls
AddDomainEvent(domainEvent)
-
A private
When({EventType} domainEvent)handler:- Delegates to the child entity if the entity owns the behavior, or updates aggregate state directly
If the aggregate delegates to an entity:
// In Order.cs (aggregate)
public void {Action}Exam(OrderItemId orderItemId, /* params */)
{
{Aggregate}{Action}DomainEvent ev = new(orderItemId.Value, /* params */);
Apply(ev);
AddDomainEvent(ev);
}
private void When({Aggregate}{Action}DomainEvent domainEvent)
=> _items.Single(i => i.OrderItemId.Value == domainEvent.OrderItemId).{Action}(domainEvent);
4d. Entity — add the behavior method
Edit the entity file. Add a method that:
- Calls
CheckRule(new Cannot{X}Rule(...))for each guard (use current entity state fields) - Calls
Apply(domainEvent)after all checks pass
Then add the private When({EventType} domainEvent) handler that updates the entity's state fields.
Pattern:
internal void {Action}({EventType} domainEvent)
{
CheckRule(new Cannot{X}Rule(_status));
// ... additional rules
Apply(domainEvent);
}
private void When({EventType} domainEvent)
{
_status = {EntityStatus}.{NewStatus};
_{actionedAt} = domainEvent.{ActionedAt};
}
4e. Unit tests
Edit the existing unit test file (e.g., Tests/UnitTests/Orders/OrderTests.cs). Add:
-
Happy path test —
[Fact], PascalCase name, no underscores:- Arrange: use existing
_sutandOrderSampleData - Act: call the new aggregate method
- Assert:
AssertPublishedDomainEvent<{EventType}>(_sut)and verify each property
- Arrange: use existing
-
Broken rule test — one
[Fact]per business rule:- Arrange/Act: set up state that triggers the rule
- Assert:
AssertBrokenRule<Cannot{X}Rule>(action)
Test naming conventions (strictly enforced):
- Happy path:
{Action}ExamIsSuccessful - Broken rule:
{Action}ExamShouldBroke{RuleName}When{Condition} - PascalCase only — no underscores (CA1707 will fail the build)
Test pattern:
[Fact]
public void {Action}ExamIsSuccessful()
{
DateTime actionedAt = SystemClock.Now;
_sut.{Action}Exam(new OrderItemId(OrderSampleData.OrderItemId), actionedAt);
{EventType} ev = AssertPublishedDomainEvent<{EventType}>(_sut);
ev.OrderItemId.Should().Be(OrderSampleData.OrderItemId);
ev.{ActionedAt}.Should().Be(actionedAt);
}
[Fact]
public void {Action}ExamShouldBroke{RuleName}When{Condition}()
{
// put entity into required state first
_sut.{Action}Exam(new OrderItemId(OrderSampleData.OrderItemId), SystemClock.Now);
void action()
{
_sut.{Action}Exam(new OrderItemId(OrderSampleData.OrderItemId), SystemClock.Now);
}
AssertBrokenRule<Cannot{X}Rule>(action);
}
Phase 5 — Verify
After writing all files, run:
dotnet build
Fix any compilation errors before reporting success. Then remind the user to run the unit tests:
dotnet test src/HC.LIS/HC.LIS.Modules/{ModuleName}/Tests/UnitTests/...
Analyzer rules you must not violate (TreatWarningsAsErrors=true)
| Rule | What to do |
|---|---|
| CA1002 | Never expose List<T> — use IReadOnlyCollection<T> |
| CA1707 | No underscores in public/test member names — PascalCase only |
| CA1716 | Avoid reserved keywords in namespaces |
| CA2007 | Use .ConfigureAwait(false) on all awaited tasks in infra/lib code |
| CA2201 | Use specific exception types, never new Exception() |
Code style (non-negotiable)
- File-scoped namespaces — no outer
{}blocks - 4-space indentation
- Private fields:
_camelCase; static fields:s_camelCase; constants:PascalCase - Primary constructors where appropriate
- Domain events carry primitives only — unwrap value objects at the call site
Critical reference files
When in doubt, read these:
| File | What it shows |
|---|---|
src/HC.LIS/HC.LIS.Modules/TestOrders/Domain/Orders/Order.cs |
Aggregate command + Apply + When pattern |
src/HC.LIS/HC.LIS.Modules/TestOrders/Domain/Orders/OrderItem.cs |
Entity CheckRule + Apply pattern |
src/HC.LIS/HC.LIS.Modules/TestOrders/Domain/Orders/Events/OrderItemAcceptedDomainEvent.cs |
Event structure |
src/HC.LIS/HC.LIS.Modules/TestOrders/Domain/Orders/Rules/CannotAcceptOrderItemMoreThanOnceRule.cs |
Exception + rule co-location |
src/HC.Core/Domain/Entity.cs |
CheckRule(), AddEvent(), Events, ClearEvents() |
src/HC.Core/Domain/EventSourcing/AggregateRoot.cs |
AddDomainEvent(), Apply(), Load() |
src/HC.Core/Domain/IBusinessRule.cs |
Rule interface |
src/HC.Core/Domain/BaseBusinessRuleException.cs |
Exception base |
src/HC.Core/Tests/UnitTests/TestBase.cs |
AssertPublishedDomainEvent<T>(), AssertBrokenRule<TRule>() |
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?