perf(profile): resolve follower list targets without loading the full profile - #215
Merged
Conversation
… profile GET /profiles/:username/followers and /following called GetProfileUseCase purely to turn a username into a user id. That use case also counts the user's posts, and after the articleCount change it counts their published articles too - so every page of a follower list ran two aggregate queries whose results were thrown away. Username resolution moves into GetFollowersUseCase and GetFollowingUseCase, which now take a username and resolve it through the profile repository. The HTTP contract is unchanged, including the 404 for an unknown username: the use cases throw the same NotFoundError the controller's profile lookup used to raise. Without that, the endpoint would have started answering an empty 200 instead. The existing e2e suite covered shape, pagination and the empty case but not the unknown-username 404, which is precisely the contract this change could have broken silently. It does now. The controller keeps getProfileUseCase - getProfile still uses it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
github-actions Bot
pushed a commit
that referenced
this pull request
Aug 25, 2026
# [1.7.0](v1.6.0...v1.7.0) (2026-08-25) ### Features * **article:** drop the markdown body from list responses ([#213](#213)) ([628d897](628d897)) * **profile:** expose published articleCount on the profile response ([#214](#214)) ([1b030bf](1b030bf)) ### Performance Improvements * **profile:** resolve follower list targets without loading the full profile ([#215](#215)) ([b855269](b855269))
|
🎉 This PR is included in version 1.7.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
10 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
GET /profiles/:username/followersand/followingcalledGetProfileUseCasepurely to turn a username into a user id:That use case also counts the user's posts — and after #214 it counts their published articles too. So every page of a follower list ran two aggregate queries whose results were discarded.
Username resolution moves into
GetFollowersUseCase/GetFollowingUseCase, which now take ausernameand resolve it throughIProfileRepository. Two fewer queries per page, and the use cases become self-contained rather than depending on the controller to have done a lookup first.The contract this could have broken silently
An unknown username currently returns 404, because
GetProfileUseCasethrowsNotFoundError. Move the lookup without moving the error and the endpoint quietly starts answering an empty 200 instead — a wrong answer, not a failure, and nothing in the suite would have noticed.The existing e2e covers item shape, pagination and the empty-list case but not the unknown-username 404. It does now, on both endpoints, and there are unit tests asserting the use cases throw
NotFoundErrorand never reach the follow repository.Verification
lint,format:check,buildclean; 759 unit tests pass.New unit tests: the username is resolved before listing and the resolved id is what reaches
getFollowers/getFollowing; an unknown username throwsNotFoundErrorand short-circuits.While updating those tests I also fixed a pre-existing type error in
get-following.usecase.test.ts— itsbaseInputwas missing the requiredcurrentUserId. It ran fine because vitest strips types without checking; see the note below.The response envelope
{ data, meta: { limit, offset, count } }is byte-identical. No DI change —profileRepositoryis already registered and awilix CLASSIC resolves it by name.Note
Third of three, and the optional one. #213 (list payload) and #214 (articleCount) are both merged-ready and independent of this.
Note
Separate finding worth its own issue: test files are not type-checked anywhere.
pnpm buildusestsconfig.build.json, which excludestests/; vitest strips types via esbuild without checking; eslint ignorestests/**. Runningtsc -p tsconfig.json --noEmitsurfaces 7 files with type errors that all pass at runtime — some predating the article work, some introduced by it. Atypecheckscript wired into the Quality Checks job would close that gap.Type of Change
Checklist
feature/,fix/,chore/,docs/)🤖 Generated with Claude Code