| name | add-concept |
| description | Use this skill when asked to create a strongly-typed domain identifier or value (such as ProjectId, AuthorName, InvoiceNumber) in a Cratis-based project. Produces a ConceptAs<T> record with the correct conversions and sentinel values. |
Create a strongly-typed Concept that wraps a primitive domain value.
Never use raw primitives in domain models
Replace Guid, string, int, etc. with a ConceptAs<T> record whenever the value has domain meaning.
Template
using Cratis.Concepts;
namespace <NamespaceRoot>.<Feature>;
public record <ConceptName>(<UnderlyingType> Value) : ConceptAs<<UnderlyingType>>(Value)
{
public static readonly <ConceptName> NotSet = new(<emptyValue>);
public static implicit operator <ConceptName>(<UnderlyingType> value) => new(value);
}
Add when backed by Guid
public static <ConceptName> New() => new(Guid.NewGuid());
Add when used as an event-source ID
public static implicit operator EventSourceId(<ConceptName> id) => new(id.Value.ToString());
Empty/sentinel values
| Underlying type | Use |
|---|
Guid | Guid.Empty |
string | string.Empty |
int | 0 |
long | 0L |
Placement rules
- Do NOT create a
Concepts/ folder
- Place the file in the folder that semantically owns the concept
ProjectId → Features/Projects/
- Shared cross-feature concepts → project source root
Checklist