business-logic-entry-point-domain-entity-payload-types
Domain Entity Payload Types for Business Logic Entry Points
Goal
When a business-logic entry point returns domain-entity data, the payload type must be the domain-entity type itself.
Do not transform or map a domain entity into another return payload type at the business-logic entry point. If the payload is meant to carry a Customer, return Customer. If it is meant to carry several Order entities, return a collection of Order. Keep the domain-entity type intact.
This rule applies to the payload type, not merely to the runtime value. The return signature must expose the domain-entity type directly.
What Counts as In Scope
Apply this skill to code that does one or more of these things:
- defines the success payload of a business-logic entry point
- defines a
...QueryHandlerSuccessor...CommandHandlerSuccesstype that carries domain-entity data - maps domain entities into intermediate payload types at business-logic boundaries
- returns one or more domain entities from business logic
- introduces DTO, view-model, projection, response-model, or similar wrapper types where the payload is supposed to contain domain-entity data
Domain Entity Payload Rule
-
Use the domain-entity type directly whenever the payload contains domain-entity data.
- Return
Customer, notCustomerPayload. - Return
Order, notOrderDto. - Return
List<Order>orOrder[], notOrderListItem[], when the payload is meant to contain domain entities.
- Return
-
Do not map domain entities into alternate payload types at business-logic entry points.
- Do not introduce conversion layers whose only purpose is to reshape domain-entity data before returning it from business logic.
- Keep entity-to-payload mapping out of the business-logic entry point when the intended payload is the entity itself.
-
Keep wrapper success types aligned with the entity rule.
- If a
...QueryHandlerSuccessor...CommandHandlerSuccesstype contains domain-entity data, its relevant fields must use the domain-entity type directly. - Use collections, optionals, or other container types around the domain-entity type only when the business result truly requires that shape.
- If a
-
Preserve other entry-point rules.
- If another rule requires a non-create command handler to return the project's empty equivalent, keep that rule.
- If another rule allows a create command handler to return only created IDs, keep that rule.
- Apply this skill only in the cases where the entry point is supposed to return domain-entity data.
Detection Workflow
-
Identify whether the payload is meant to contain domain-entity data.
- Check the business meaning of the returned value.
- Determine whether the caller is receiving actual entities from the domain layer rather than identifiers or non-entity summaries.
-
Inspect the declared return types.
- Look for payload wrappers, DTOs, response models, projections, or other types inserted between the business-logic entry point and the domain entity.
- Check whether those types merely duplicate the entity shape or rename fields without changing the business meaning.
-
Trace mapping code.
- Look for
toDto,toPayload,toResponse,fromEntity, or similar conversions at the business-logic entry point. - Treat entity-to-payload mapping at that boundary as a violation when the payload is intended to contain domain-entity data.
- Look for
Writing or Changing Business-Logic Payloads
-
Start from the business result.
- Decide whether the entry point is supposed to return domain entities, entity IDs, or some other business result.
- Apply this skill only when the result should contain domain-entity data.
-
Use the entity type directly in the return signature.
- If one entity is returned, use the entity type directly.
- If several entities are returned, use a collection of that entity type.
- If the payload is wrapped in a success type, put the entity type directly inside that wrapper.
-
Remove redundant mapping.
- Delete or avoid payload types that only mirror the entity shape for the business-logic boundary.
- Delete or avoid conversion code that only repackages the entity without changing the intended business result.
-
Keep the domain meaning intact.
- Preserve the entity's type, identity, and behavior contract as represented by the domain layer.
- Do not flatten or rename entity fields merely to satisfy a business-logic return payload shape.
Examples
Use this:
type FindCustomerByIdQueryHandlerSuccess = {
customer: Customer
}
Not this:
type CustomerPayload = {
id: CustomerId
name: string
}
type FindCustomerByIdQueryHandlerSuccess = {
customer: CustomerPayload
}
Use this:
type ListOrdersQueryHandlerSuccess = {
orders: Order[]
}
Not this:
type OrderListItem = {
id: OrderId
total: Money
}
type ListOrdersQueryHandlerSuccess = {
orders: OrderListItem[]
}
Review Questions
When reading or reviewing code, ask:
- Is this entry point supposed to return domain-entity data?
- If so, does the payload type use the domain-entity type directly?
- Is there any DTO, payload type, response model, or mapping layer inserted without changing the intended business result?
- Would removing the mapping leave the business meaning unchanged?
- Does this code violate another entry-point rule, such as returning only IDs for create commands?
If the answer is yes, apply this skill.
Report the Outcome
When finishing the task:
- state which business-logic entry points were identified or changed
- state which payload fields now use domain-entity types directly
- state which redundant payload types or mappings were removed or avoided
- state any other entry-point rule that still constrained the final return shape
More from code-sherpas/agent-skills
neverthrow-wrap-exceptions
Capture exceptions and promise failures with `neverthrow` instead of hand-written `try/catch` in TypeScript and JavaScript code. Use when wrapping synchronous functions that may throw, promise-returning functions that may throw before returning, existing `PromiseLike` values that may reject, or third-party APIs such as parsers, database clients, HTTP clients, file-system helpers, serializers, and SDK calls. Prefer `Result.fromThrowable` for synchronous throwers, `ResultAsync.fromThrowable` for promise-returning functions that may throw or reject, and `ResultAsync.fromPromise` when you already have a `PromiseLike` value in hand. Only keep `try/catch` when the language construct, cleanup requirement, or framework boundary truly requires it.
11atomic-design
Create or update web UI components with a strict reuse-first workflow. Use when building, refactoring, restyling, or extending frontend or template components while minimizing raw DOM or HTML by reusing or generalizing existing components first.
10write-persistence-representations
Create or update persistence-layer data representations in any stack, including ORM entities, schema definitions, table mappings, document models, collection definitions, and similar database-facing code. Use when agents needs to add or change persisted fields, identifiers, relationships, indexes, timestamps, auditing fields, or storage mappings in frameworks, libraries, or ORMs such as Prisma, TypeORM, Sequelize, Drizzle, Mongoose, Hibernate/JPA, Doctrine, Ecto, Active Record, or equivalent persistence technologies.
7business-logic
Identify, interpret, review, or write business logic in code. Use when an agent needs to decide whether code expresses business rules, business algorithms, or business workflows, or when it must implement, preserve, or refactor code that creates, stores, or transforms data according to real business policies.
7immutable-domain-entities
Require the immutable design pattern for domain entities. Use when an agent needs to create, modify, review, or interpret domain entities and should preserve identity while expressing state changes through new immutable instances. Domain entities must be modeled as immutable classes, not as plain type aliases or interfaces paired with standalone functions.
7update-agent-skills
Update agent skills installed with the `skills` CLI. Use when asked to refresh installed skills, keep a project's skills current, or troubleshoot cases where `npx skills update` reports that everything is up to date. For project-scoped installs, a no-change update must immediately run the bundled reinstall script so tracked skills from `skills-lock.json` are reinstalled without extra investigation.
7