business-logic-typical-domain-entity-entry-points
Typical Domain-Entity Entry Points for Business Logic
Goal
When deciding which business-logic entry points to implement around a domain-entity type, prefer a standard set of entry points instead of inventing ad hoc operations.
Treat the domain entity as the organizing center. Start from the entity type, then choose the entry point kind that matches the business operation:
- create
- update
- find by id
- search
- delete by id
- explicit mark-as operations for finite-state changes
- explicit assign or add operations for entity associations
- explicit check-whether-can-be operations for boolean feasibility checks
Basic Entry Points
Given a domain-entity type, prefer these basic entry points:
-
create- Creates a new domain entity.
-
update- Updates only fields whose value space is effectively infinite or quasi-infinite.
- Typical examples:
string,int,decimal,url,date,datetime, text fields, free-form names, descriptions, notes, counters, limits, and similar values.
-
find by id- Returns exactly one entity by its identity or fails when it does not exist.
-
search- Returns a collection of entities or results.
- Supports filtering by any field or combination of fields.
- Supports pagination and sorting.
-
delete by id- Deletes the entity identified by its id.
-
check whether ... can be ...- Returns a boolean indicating whether a business operation is currently allowed.
Choose the Entry Point by Operation Kind
Use update only for quasi-unbounded fields
Use update when the operation changes fields whose possible values are open-ended or effectively unbounded.
Examples:
updateUserupdateCourseupdateRole
Typical fields for update:
- name
- description
- phone
- url
- amount
- date
- datetime
- numeric limits or thresholds
Do not use update for finite-state or relationship-changing operations when a more explicit entry point is appropriate.
Use find by id for one-or-fail retrieval
Use a dedicated find by id entry point when the caller needs one specific entity by identity.
Examples:
findUserByIdfindCourseByIdfindRoleByIdfindPermissionById
The operation should either return the requested entity or fail according to the project's error convention.
Use search for filtering, sorting, and pagination
Use search when callers need to retrieve entities by arbitrary criteria, combinations of criteria, sorting, or pagination.
Examples:
searchUserssearchCoursessearchRolessearchPermissions
Search should be the flexible query entry point:
- filter by one field
- filter by multiple fields
- sort
- paginate
Finite-State Changes Need Explicit Mark-As Entry Points
When the business operation changes a field with only a small set of possible values, do not hide that transition inside update.
Use an explicit entry point that names the new business state.
Typical finite-state fields:
- enum-based status fields
- boolean fields that represent status
- lifecycle flags whose values carry business meaning
Examples:
markUserAsEnabledmarkRoleAsDisabledmarkCourseAsCancelledmarkUserAsDisabled
Use this pattern when the change is really a business state transition, not just a free-form field edit.
Relationship Changes Need Explicit Assign or Add Entry Points
When the business operation associates one domain entity with another in a one-to-many or many-to-many relationship, do not hide that change inside update.
Use an explicit relationship entry point that names the association operation.
Examples:
assignPermissionToRoleaddUserToCourseremoveUserFromCourseunassignPermissionFromRole
Choose the verb that matches the business meaning of the association:
assignaddremoveunassign
Prefer the most specific business verb that fits the relationship.
Feasibility Checks Need Explicit Check-Whether Entry Points
When the business operation is to ask whether something can be done right now, use an explicit check-whether entry point that returns a boolean.
Use this pattern when the caller needs a yes-or-no answer about whether an action is currently allowed before attempting it.
Examples:
checkWhetherPostCanBePublishedcheckWhetherUserCanBeDisabledcheckWhetherCourseCanBeCancelledcheckWhetherRoleCanBeDeletedcheckWhetherPermissionCanBeAssignedToRole
Use this kind of entry point for business permission or feasibility checks, not for performing the action itself.
CQS Alignment
When the project is following Command-Query Separation:
create,update,delete by id,mark as ...,assign ..., andadd ...are commandsfind by id,search, andcheck whether ... can be ...are queries
Keep this skill focused on choosing the right entry point kind. If other skills already govern CQS return shapes, signatures, or payload typing, keep those rules too.
Detection Workflow
-
Start from the domain entity.
- Identify the primary entity type the requested operation acts on.
-
Identify the real business operation.
- Is the caller creating, editing open-ended fields, retrieving by id, searching, deleting, changing a finite state, associating entities, or checking whether an action is allowed?
-
Choose the standard entry point kind first.
- Prefer the standard entry point kind before inventing a custom one.
-
Reject overloaded
updateoperations when the meaning is more specific.- If the change is a finite-state transition, use
mark as .... - If the change is an association, use
assign ...oradd .... - If the operation is a yes-or-no feasibility check, use
check whether ... can be ....
- If the change is a finite-state transition, use
Writing or Changing Entry Points
-
Begin with the standard set.
- Check whether the requested behavior is simply
create,update,find by id,search,delete by id, orcheck whether ... can be ....
- Check whether the requested behavior is simply
-
Use
updatenarrowly.- Restrict
updateto quasi-unbounded fields. - Do not let
updateabsorb business state transitions or association operations.
- Restrict
-
Name state transitions explicitly.
- Prefer
mark as ...naming when the operation changes a finite-state field. - Make the resulting business state obvious in the entry point name.
- Prefer
-
Name associations explicitly.
- Prefer verbs like
assignoraddwhen the operation connects one entity to another. - Make both sides of the relationship obvious in the entry point name.
- Prefer verbs like
-
Keep
searchbroad and structured.- Let
searchhandle combinations of filters, ordering, and pagination instead of creating many narrow list-style entry points by default.
- Let
-
Use explicit check-whether entry points for boolean business decisions.
- Prefer
check whether ... can be ...naming when the caller needs to know whether an action is allowed. - Return a boolean instead of overloading a command or search operation for that purpose.
- Prefer
Examples
Prefer this set for a User entity:
createUserupdateUserfindUserByIdsearchUsersdeleteUserByIdmarkUserAsEnabledmarkUserAsDisabledaddUserToCoursecheckWhetherUserCanBeDisabled
Prefer this set for a Role entity:
createRoleupdateRolefindRoleByIdsearchRolesdeleteRoleByIdassignPermissionToRoleunassignPermissionFromRolecheckWhetherRoleCanBeDeleted
Prefer this set for a Course entity:
createCourseupdateCoursefindCourseByIdsearchCoursesdeleteCourseByIdmarkCourseAsCancelledaddUserToCoursecheckWhetherCourseCanBeCancelled
Prefer this set for a Permission entity:
createPermissionupdatePermissionfindPermissionByIdsearchPermissionsdeletePermissionByIdassignPermissionToRolecheckWhetherPermissionCanBeAssignedToRole
Prefer this set for a Post entity:
createPostupdatePostfindPostByIdsearchPostsdeletePostByIdmarkPostAsCancelledcheckWhetherPostCanBePublished
Avoid these overloaded choices when a more specific entry point exists:
updateUserStatusupdateRolePermissionsupdateTeamMembers
Prefer instead:
markUserAsEnabledassignPermissionToRoleaddUserToCoursecheckWhetherPostCanBePublished
Review Questions
When reading or reviewing code, ask:
- Which domain entity is this entry point organized around?
- Is this operation really create, update, find by id, search, delete by id, or check whether something can be done?
- If not, is it actually a finite-state transition that should be
mark as ...? - If not, is it actually an association that should be
assign ...oradd ...? - If not, is it actually a feasibility check that should be
check whether ... can be ...? - Is
updatebeing overloaded with responsibilities better expressed as explicit business operations?
If the answer is yes, apply this skill.
Report the Outcome
When finishing the task:
- state which domain-entity entry points were identified or changed
- state which standard entry point kinds were used
- state where
updatewas replaced by explicitmark as ...,assign ...,add ..., orcheck whether ... can be ...operations - state how the final entry points align with the entity's business operations
More from code-sherpas/agent-skills
neverthrow-return-types
Require `neverthrow`-based return types in TypeScript and JavaScript code whenever the surrounding technology allows it. Use when creating, refactoring, reviewing, or extending standalone functions, exported module functions, class methods, object methods, service methods, repository methods, and similar APIs that should expose explicit success and failure result types in their signatures. Prefer `Result<T, E>` for synchronous code and `ResultAsync<T, E>` for asynchronous code. Only skip a `neverthrow` return type when a framework, library, runtime interface, or externally imposed contract is incompatible and requires a different return shape.
16neverthrow-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-entry-point-repository-operations
Require repository interfaces to expose a standard set of operations with specific signatures and naming conventions. Use when an agent needs to create, modify, review, or interpret repository interfaces used by business-logic entry points. Repositories must offer findById (fails when entity is absent — never returns null or optional), create (returns created entity), update (returns updated entity), search (returns collection), and deleteById (returns nothing). Do not use a generic "save" operation — always distinguish between create and update explicitly.
6domain-entity
Identify, interpret, review, or write domain entities in code. Use when an agent needs to decide whether a domain entity is defined by a stable identity that persists over time, or when it must implement, preserve, or refactor entity lifecycle, invariants, and behavior around domain data. When writing or changing a domain entity, use a class or the closest class-like construct the project stack supports. Do not model domain entities as plain type aliases or interfaces paired with standalone functions.
6