--- description: List/detail (and write responses that reuse the mapper) embed FK relations as objects via pickRelation globs: "src/modules/**/*.ts,src/common/http/response/**/*.ts" alwaysApply: false --- # Relation Response Objects List, detail, and write handlers that reuse the same mapper MUST embed foreign keys as nested objects, not bare ids. ## Field lists - Default catalog fields: `DEFAULT_RELATION_FIELDS` (`id`, `code`, `name`) from `src/common/http/response/` - Override per entity with a module/local constant (users: `USER_RELATION_FIELDS` = `id`, `username`) - Use `pickRelation(source, fields)` only — do not hand-roll partial copies ## Mapping - Request DTOs still accept `*Id` (`divisionId`); the response key is the relation name (`division`, not `divisionId`) - Null FK → `null` (not omitted) - Never expose secrets (`passwordHash`, tokens) in relation objects - Load relations in the repository (joins or batch-load); map with `pickRelation` in the service ```typescript // BAD return { divisionId: branch.divisionId, createdBy: branch.createdBy } // GOOD return { division: pickRelation(branch.division, DEFAULT_RELATION_FIELDS), createdBy: pickRelation(branch.createdByUser, USER_RELATION_FIELDS), } ```