From domain-refactor
Refactor a backend domain to follow the 3-layer architecture pattern (Controller → Service → Entity). Use when asked to refactor a domain, add an entity layer, fix architecture violations, or align a domain with backend-architecture.md. Triggers on phrases like "refactor domain", "add entity", "fix architecture", "align with pattern", or "domain doesn't have an entity".
How this skill is triggered — by the user, by Claude, or both
Slash command
/domain-refactor:domain-refactorThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Refactor a backend domain to follow the 3-layer pattern documented in `docs/backend-architecture.md`.
Refactor a backend domain to follow the 3-layer pattern documented in docs/backend-architecture.md.
Announce at start: "I'm using the domain-refactor skill to audit and refactor this domain."
This is an interactive, incremental refactor. Never batch large changes without human review.
If the user hasn't specified a domain, ask which one. Domains live in apps/backend/src/api/<domain>/.
Read all files in the domain directory. Also read docs/backend-architecture.md for the reference patterns.
Produce an audit report listing every violation found, organized by category:
Missing entity layer
database.select, database.insert, database.update, database.delete, database.query) directly in the service? List each one.Business logic in controllers
Business logic in services that should be entity predicates
if (thing.status === 'x')) instead of calling an entity predicateEvent emission in services
eventBridge.emit() or eventBridge.emitMany() calls in the service that are paired with a single entity data operationSide effects in wrong layers
Present the audit and ask: "Here's what I found. Which categories should we address? Want to tackle all of them, or focus on specific ones?"
If the domain needs a new entity file, present what it should contain:
can* or is* predicate. Show the current service code and proposed entity signature.eventBridge call that should move into the entity alongside its paired data operation.Ask: "Does this look right for the new entity? Anything to add or remove?"
Work through changes one category at a time. After each category:
Order of operations:
After all changes:
yarn tsc:all to confirm compilationUse this to check each violation type:
Controller layer:
Service layer:
database.transaction(...))Entity layer:
can* → { allowed, reason }, is* → boolean)instanceId) alongside allowedeventBridge after data writesnull for not found (doesn't throw NotFoundError)resolve* methods for internal ID resolutionSync predicate (entity has the data already fetched by service):
canConvert(deal: Pick<Deal, 'convertedAt' | 'applicationId'>): { allowed: boolean; reason?: string } {
if (deal.convertedAt) return { allowed: false, reason: 'Already converted' };
return { allowed: true };
}
Async predicate with context (entity resolves internal state):
async canAddTodoItem(taskId: string): Promise<
{ allowed: true; instanceId: string } | { allowed: false; reason: string }
> {
const instance = await this.resolveInstance(taskId);
if (!instance) return { allowed: false, reason: 'No output found' };
return { allowed: true, instanceId: instance.instanceId };
}
Service enforcement:
const check = await entity.canDoThing(id);
if (!check.allowed) throw new ValidationError(check.reason);
await entity.doThing(check.resolvedId, data);
Entity event emission:
async createThing(data: CreateThingData) {
const [result] = await database.insert(things).values(data).returning();
await eventBridge.emit('thing.created', {
brandId: data.brandId,
data: { thingId: result.id },
});
return result;
}
dealEntity.ts and taskOutputsEntity.ts for referencenpx claudepluginhub franchiseai/claude-code-plugins --plugin domain-refactorImplements Clean Architecture, Hexagonal Architecture, and Domain-Driven Design for backend systems. Use when architecting new systems or refactoring for maintainability.
Enforces DDD tactical patterns including aggregates, value objects, entity identity, and bounded contexts when designing or modifying domain models.
Models complex business software around the domain using ubiquitous language, bounded contexts, aggregates, and entities/value objects to reduce miscommunication between technical and business teams.