feat(user) Expose embedded users as CompactUserDto in comments, ratings, tags and meal plan shares (spec 003) #32

Merged
araemer merged 5 commits from 003-compact-user-in-embedded-dtos into stage 2026-10-11 06:17:32 +00:00
Owner

Spec 003: docs/features/003-compact-user-in-embedded-dtos.md (recipe-platform#22). Contract PR: recipe-platform#46.
Plan: docs/plans/003-compact-user-in-embedded-dtos.md

CommentDto.createdByUser, RatingDto.createdByUser, EnrichedTagDto.createdByUser and MealPlanShareDto.sharedWithUser are now built as CompactUserDto (id, user name, first and last name, avatar). Email and role of the embedded user no longer leave the API in these responses, also when that user is the caller or the caller is an admin. Besides email and role, the embedded user's createdAt, updatedAt, version and createdBy are gone, and a name that is not set is an absent key instead of null.

What was implemented

Plan step Done
1 — Contract pin contract.ref → 0f2e4006995362d60686ce328c1edbb292188ed3
2 — Mappers CommentDtoEntityMapper, RatingDtoEntityMapper, EnrichedTagMapper, MealPlanShareDtoEntityMapper take CompactUserMapper instead of UserDtoEntityMapper; JSDoc and inline comments updated. Mapping logic and guards unchanged
3 — Factories The six factories (Comment, Rating, Tag, MealPlan, Recipe, AiRecipeGeneration) build and pass a CompactUserMapper
4 — Tests The four mapper tests assert the embedded user with toEqual on the exact compact object, plus explicit "email" in / "role" in checks. RecipeDtoEntityMapper.test.ts and MealPlanDtoEntityMapper.test.ts cover the embedded case (comment and rating inside a recipe, share inside a meal plan). 9 new tests
5 — Documentation Stale "full user" wording replaced in two resources, TagApplicationService, the two entities and three bullets of docs/architecture.md

No route, repository query, handler or Bruno file changed. UserDtoEntityMapper and everything behind /user/me, login, passkey login and admin user management are untouched; their tests are unedited and green.

Deviations from the plan

One, recorded in the plan's Deviations section, decided in the implementation:

  • Step 5: comment in RecipeRepository.findById() reworded. The plan puts repositories out of scope, but its own check (grep for "full user object" in src returns nothing) finds this JSDoc line. It is reworded like the others. Comment only, no change to the query.

Judgment calls

  • Each test file defines the expected compact user once as an EXPECTED_COMPACT_USER constant instead of repeating the literal in every assertion.
  • The plan asks for JSDoc on the constructor of EnrichedTagMapper only; CommentDtoEntityMapper's constructor got a one-line @param JSDoc as well, since the class was being documented anyway.
  • Steps 1 to 3 are one commit, because the repo does not compile in between.

Verification

Check Result
../recipe-platform on 0f2e400 yes
npm run build clean
npm test 57 files, 620 tests, all green (611 before)
Type check of the six changed test files (tests are excluded from tsc; checked with a temporary tsconfig) no errors
grep of step 3: UserDtoEntityMapper outside tests only CompactUserMapper.ts, AuthHandler.ts, AuthHandlerFactory.ts, PasskeyApplicationService.ts, PasskeyServiceFactory.ts, UserApplicationService.ts, UserServiceFactory.ts (and its own file)
grep of step 5 no hits
Lint the repo defines no linter
npm run test:integration not run — not required, no shopping list item write is touched

Not verified: the responses of a running server were not called; the evidence is the mapper tests.

The contract_pin check stays red until the contract PR (recipe-platform#46) is merged; it has to be re-run then.

🤖 Generated with Claude Code

Spec 003: [docs/features/003-compact-user-in-embedded-dtos.md](https://git.raemer.net/araemer/recipe-platform/src/branch/main/docs/features/003-compact-user-in-embedded-dtos.md) (recipe-platform#22). Contract PR: recipe-platform#46. Plan: [docs/plans/003-compact-user-in-embedded-dtos.md](https://git.raemer.net/araemer/recipe-backend/src/branch/003-compact-user-in-embedded-dtos/docs/plans/003-compact-user-in-embedded-dtos.md) `CommentDto.createdByUser`, `RatingDto.createdByUser`, `EnrichedTagDto.createdByUser` and `MealPlanShareDto.sharedWithUser` are now built as `CompactUserDto` (id, user name, first and last name, avatar). Email and role of the embedded user no longer leave the API in these responses, also when that user is the caller or the caller is an admin. Besides email and role, the embedded user's `createdAt`, `updatedAt`, `version` and `createdBy` are gone, and a name that is not set is an absent key instead of `null`. ## What was implemented | Plan step | Done | |---|---| | 1 — Contract pin | `contract.ref` → `0f2e4006995362d60686ce328c1edbb292188ed3` | | 2 — Mappers | `CommentDtoEntityMapper`, `RatingDtoEntityMapper`, `EnrichedTagMapper`, `MealPlanShareDtoEntityMapper` take `CompactUserMapper` instead of `UserDtoEntityMapper`; JSDoc and inline comments updated. Mapping logic and guards unchanged | | 3 — Factories | The six factories (`Comment`, `Rating`, `Tag`, `MealPlan`, `Recipe`, `AiRecipeGeneration`) build and pass a `CompactUserMapper` | | 4 — Tests | The four mapper tests assert the embedded user with `toEqual` on the exact compact object, plus explicit `"email" in` / `"role" in` checks. `RecipeDtoEntityMapper.test.ts` and `MealPlanDtoEntityMapper.test.ts` cover the embedded case (comment and rating inside a recipe, share inside a meal plan). 9 new tests | | 5 — Documentation | Stale "full user" wording replaced in two resources, `TagApplicationService`, the two entities and three bullets of `docs/architecture.md` | No route, repository query, handler or Bruno file changed. `UserDtoEntityMapper` and everything behind `/user/me`, login, passkey login and admin user management are untouched; their tests are unedited and green. ## Deviations from the plan One, recorded in the plan's Deviations section, decided in the implementation: - **Step 5: comment in `RecipeRepository.findById()` reworded.** The plan puts repositories out of scope, but its own check (`grep` for "full user object" in `src` returns nothing) finds this JSDoc line. It is reworded like the others. Comment only, no change to the query. ## Judgment calls - Each test file defines the expected compact user once as an `EXPECTED_COMPACT_USER` constant instead of repeating the literal in every assertion. - The plan asks for JSDoc on the constructor of `EnrichedTagMapper` only; `CommentDtoEntityMapper`'s constructor got a one-line `@param` JSDoc as well, since the class was being documented anyway. - Steps 1 to 3 are one commit, because the repo does not compile in between. ## Verification | Check | Result | |---|---| | `../recipe-platform` on `0f2e400` | yes | | `npm run build` | clean | | `npm test` | 57 files, 620 tests, all green (611 before) | | Type check of the six changed test files (tests are excluded from `tsc`; checked with a temporary tsconfig) | no errors | | `grep` of step 3: `UserDtoEntityMapper` outside tests | only `CompactUserMapper.ts`, `AuthHandler.ts`, `AuthHandlerFactory.ts`, `PasskeyApplicationService.ts`, `PasskeyServiceFactory.ts`, `UserApplicationService.ts`, `UserServiceFactory.ts` (and its own file) | | `grep` of step 5 | no hits | | Lint | the repo defines no linter | | `npm run test:integration` | not run — not required, no shopping list item write is touched | Not verified: the responses of a running server were not called; the evidence is the mapper tests. The `contract_pin` check stays red until the contract PR (recipe-platform#46) is merged; it has to be re-run then. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
docs(plan) Add the implementation plan for spec 003
All checks were successful
/ test (pull_request) Successful in 1m9s
/ contract_pin (pull_request) Successful in 2s
183fb7fd52
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat(mappers) Expose embedded users of comments, ratings, tags and meal plan shares as CompactUserDto
Some checks failed
/ contract_pin (pull_request) Has been cancelled
/ test (pull_request) Has been cancelled
c9af37749c
Moves the contract pin to 0f2e400 and switches the four mappers and their
six factories from UserDtoEntityMapper to CompactUserMapper, so email and
role of another user no longer leave the API in these responses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test(mappers) Assert that embedded users carry no email or role
Some checks failed
/ test (pull_request) Has been cancelled
/ contract_pin (pull_request) Has been cancelled
dc3c4d1fe6
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs(mappers) Describe embedded users as CompactUserDto in comments and architecture.md
Some checks failed
/ test (pull_request) Successful in 1m10s
/ contract_pin (pull_request) Failing after 3s
cbd3502a7d
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
araemer changed title from WIP: feat(user) Expose embedded users as CompactUserDto in comments, ratings, tags and meal plan shares (spec 003) to feat(user) Expose embedded users as CompactUserDto in comments, ratings, tags and meal plan shares (spec 003) 2026-10-04 06:50:16 +00:00
test(mappers) Realign the mapper declarations in MealPlanDtoEntityMapper.test
All checks were successful
/ test (pull_request) Successful in 1m9s
/ contract_pin (pull_request) Successful in 2s
9d63219c62
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
araemer merged commit 757ad895e1 into stage 2026-10-11 06:17:32 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
araemer/recipe-backend!32
No description provided.