Claude-skill-registry add-domain-entity
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/add-domain-entity" ~/.claude/skills/majiayu000-claude-skill-registry-add-domain-entity && rm -rf "$T"
skills/data/add-domain-entity/SKILL.mdAdd Domain Entity
Create domain layer components for a new entity following DDD patterns.
Prerequisites
- Database table created (use add-database-table skill first)
- SQLBoiler model generated via
make migrate.up
Quick Workflow
1. Domain Model → internal/domain/model/{entity}.go 2. Domain Error → internal/domain/errors/errors.go 3. Repository Interface → internal/domain/repository/{entity}.go 4. Marshaller → internal/infrastructure/{db}/internal/marshaller/{entity}.go 5. Repository Impl → internal/infrastructure/{db}/repository/{entity}.go 6. Generate Mocks → make generate.mock
Step 1: Create Domain Model
Location:
internal/domain/model/{entity}.go
Create the entity struct, constructor, update methods, and type aliases.
Key requirements:
- Use
for ID generation in constructorid.New() - Set both
andCreatedAt
to the same time parameterUpdatedAt - Define
for relations (always nil in constructor)ReadonlyReference - Create slice type alias:
type Examples []*Example
See: references/domain-model-patterns.md
Step 2: Add Domain Error
Location:
internal/domain/errors/errors.go
Add a not-found error for the entity:
ExampleNotFoundErr = NewNotFoundError("E2xxxxx", "Example not found")
Follow error code conventions from
.claude/rules/domain-errors.md.
Step 3: Create Repository Interface
Location:
internal/domain/repository/{entity}.go
Define the repository interface with standard CRUD operations and query structs.
Key requirements:
- Add
directive for mock generation//go:generate - Use
for optional enum/custom type filter fieldsnullable.Type[T] - Embed
/BaseGetOptions
in query structsBaseListOptions
See: references/repository-patterns.md
Step 4: Create Marshaller
Location:
internal/infrastructure/{mysql|postgresql|spanner}/internal/marshaller/{entity}.go
Convert between DB models and domain models.
Key requirements:
- Related entity's
must remain nil (no recursive loading)ReadonlyReference - Use var declaration pattern for nullable timestamp fields
- Include both
andToModel
functionsToDBModel
See: references/marshaller-patterns.md
Step 5: Create Repository Implementation
Location:
internal/infrastructure/{mysql|postgresql|spanner}/repository/{entity}.go
Implement the repository interface using SQLBoiler.
Key requirements:
- Use
for all DB operationstransactable.GetContextExecutor(ctx) - Implement
helper for reusable filter logicbuildListQuery - Implement
helper for relation loadingbuildPreload - Use base helper functions:
,addForUpdateFromBaseGetOptionsaddForUpdateFromBaseListOptions
See: references/repository-patterns.md
Step 6: Generate Mocks
make generate.mock
This generates mock implementations in
internal/domain/repository/mock/.
Checklist
Domain Model
- Entity struct with all fields
-
for relations (if any)ReadonlyReference - Constructor with
andid.New()ReadonlyReference: nil - Update method using
types for optional fieldsnull.* - Slice type alias (
)Examples []*Example - Helper methods on slice (
,IDs()
)MapByID()
Status/Enum Types (if needed)
- Type definition with
as first constantUnknown -
andString()
methodsValid() -
constructorNew{Type}(str string)
Repository
- Interface with
directive//go:generate - Query structs with
for optional enumsnullable.Type[T] - Domain error added for not-found case
Implementation
- Marshaller with
,ToModel
,ToDBModel
,ToModelsToDBModels - Marshaller handles
correctlyReadonlyReference - Repository implementation with all CRUD methods
-
andbuildListQuery
helpersbuildPreload - Mocks generated
Next Steps
After creating domain entity, use add-api-endpoint skill to create:
- Usecase input/output structs
- Interactor interface and implementation
- Protocol Buffers definition
- gRPC handler