Generate domain layer components (entities, value objects, repository interfaces, events, errors). Use when adding entities to existing context, creating value objects for validation, or defining domain-specific errors (e.g., "Create Product entity with Price VO", "Add Customer with Email").
Generate domain layer components including entities, value objects, repository interfaces, domain events, and errors following Domain-Driven Design principles.
Creates pure business logic components for the domain layer with zero framework dependencies:
Use when you need to:
Examples:
export class EntityName {
private constructor(
private readonly id: string,
private name: string,
private readonly createdAt: Date,
private updatedAt: Date
) {}
static create(data: CreateData): EntityName {
const id = randomUUID();
const now = new Date();
const entity = new EntityName(id, data.name, now, now);
entity.validate();
return entity;
}
static reconstitute(data: PersistedData): EntityName {
return new EntityName(
data.id,
data.name,
data.createdAt,
data.updatedAt
);
}
getId(): string { return this.id; }
getName(): string { return this.name; }
changeName(newName: string): void {
this.name = newName;
this.updatedAt = new Date();
}
private validate(): void {
if (!this.name) throw new InvalidDataError('Name required');
}
}
export class Email {
private readonly value: string;
private constructor(value: string) {
this.value = value;
}
static create(value: string): Email {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(value)) {
throw new InvalidEmailError(value);
}
return new Email(value.toLowerCase());
}
getValue(): string {
return this.value;
}
equals(other: Email): boolean {
return this.value === other.value;
}
}
export interface IEntityRepository {
save(entity: EntityName): Promise<void>;
findById(id: string): Promise<EntityName | null>;
findByEmail(email: Email): Promise<EntityName | null>;
findAll(limit?: number, offset?: number): Promise<EntityName[]>;
delete(id: string): Promise<void>;
exists(id: string): Promise<boolean>;
}
export class EntityCreated {
constructor(
public readonly entityId: string,
public readonly name: string,
public readonly timestamp: Date = new Date()
) {}
}
export class DomainError extends Error {
constructor(
message: string,
public readonly code: string
) {
super(message);
this.name = this.constructor.name;
}
}
export class EntityNotFoundError extends DomainError {
constructor(id: string) {
super(`Entity with ID '${id}' not found`, 'ENTITY_NOT_FOUND');
}
}
MUST DO:
create() and reconstitute() methodsMUST NOT:
any types/src/contexts/{Context}/domain/
├── entities/
│ └── {entity}.entity.ts
├── value-objects/
│ ├── email.vo.ts
│ ├── phone-number.vo.ts
│ └── {custom}.vo.ts
├── repositories/
│ └── {entity}.repository.interface.ts
├── events/
│ ├── {entity}-created.event.ts
│ ├── {entity}-updated.event.ts
│ └── {entity}-deleted.event.ts
├── errors/
│ └── {context}.errors.ts
└── index.ts
The skill can generate these common value objects:
After generation, verify:
create() and reconstitute() methods presentUpdate the domain barrel export (domain/index.ts):
export * from './entities/{entity}.entity';
export * from './value-objects/{vo}.vo';
export * from './repositories/{entity}.repository.interface';
export * from './errors/{context}.errors';
export * from './events/{entity}.events';
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer