[FEAT] 다른 유저 공개 서재 전체(전체보기 페이지) API 구현, 다른 유저 공개 서재들 불러오기 API 구현, 다른 유저 프로필 조회 및 팔로잉 여부 조회 API 철회#121
[FEAT] 다른 유저 공개 서재 전체(전체보기 페이지) API 구현, 다른 유저 공개 서재들 불러오기 API 구현, 다른 유저 프로필 조회 및 팔로잉 여부 조회 API 철회#121icarus0616 wants to merge 5 commits into
Conversation
|
Caution Review failedThe pull request is closed. 📝 WalkthroughWalkthroughAdds public-facing user profile and public-shelf browsing: repository queries, DTOs, services, and controllers to list public shelves (with top-3 previews) and to fetch full shelf books with multiple sort options; also adds a native profile summary query and ApiResponse helpers for BaseSuccessCode. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant PublicShelvesCtrl as UserPublicShelvesController
participant PublicShelvesSvc as UserPublicShelvesService
participant ShelvesRepo as BookshelvesRepository
participant ItemsRepo as BookshelfItemsRepository
participant DB as Database
Client->>PublicShelvesCtrl: GET /api/v1/users/{userId}/shelves
PublicShelvesCtrl->>PublicShelvesSvc: listPublicShelves(userId)
PublicShelvesSvc->>ShelvesRepo: findByUser_IdAndIsPublicTrueOrderByIdAsc(userId)
ShelvesRepo->>DB: query public shelves
DB-->>ShelvesRepo: shelves
loop per shelf
PublicShelvesSvc->>ItemsRepo: countByShelf_Id(shelfId)
ItemsRepo->>DB: count query
DB-->>ItemsRepo: count
PublicShelvesSvc->>ItemsRepo: findTop3ByShelf_IdOrderByAddedAtDesc(shelfId)
ItemsRepo->>DB: top-3 query
DB-->>ItemsRepo: top-3 items
end
PublicShelvesSvc-->>PublicShelvesCtrl: UserPublicShelfListResponse
PublicShelvesCtrl-->>Client: 200 OK
sequenceDiagram
participant Client
participant PublicShelvesCtrl as UserPublicShelvesController
participant PublicShelvesSvc as UserPublicShelvesService
participant ShelvesRepo as BookshelvesRepository
participant ItemsRepo as BookshelfItemsRepository
participant DB as Database
Client->>PublicShelvesCtrl: GET /api/v1/users/{userId}/shelves/{shelfId}/books?sort=AUTHOR
PublicShelvesCtrl->>PublicShelvesSvc: listPublicShelfBooks(userId,shelfId,sort)
PublicShelvesSvc->>ShelvesRepo: existsByIdAndUser_IdAndIsPublicTrue(shelfId,userId)
ShelvesRepo->>DB: existence check
DB-->>ShelvesRepo: exists/false
alt exists
PublicShelvesSvc->>ItemsRepo: findByShelf_IdOrderByAddedAtDesc/Asc/Book_TitleAsc(...)
ItemsRepo->>DB: fetch books
DB-->>ItemsRepo: books
alt sort == AUTHOR
PublicShelvesSvc->>PublicShelvesSvc: in-memory sort by primary author then addedAt desc
end
PublicShelvesSvc-->>PublicShelvesCtrl: UserPublicShelfBooksResponse
else not exists
PublicShelvesSvc-->>PublicShelvesCtrl: throw SHELF_NOT_FOUND_OR_PRIVATE
end
PublicShelvesCtrl-->>Client: 200 OK / 404
sequenceDiagram
participant Client
participant ProfileCtrl as UsersProfileController
participant ProfileSvc as UserProfileService
participant ProfileQry as UserProfileQueryRepository
participant DB as Database
Client->>ProfileCtrl: GET /api/v1/users/{userId}/profile (auth)
ProfileCtrl->>ProfileSvc: getProfile(meId,userId)
ProfileSvc->>ProfileQry: findUserProfileSummary(meId,targetUserId)
ProfileQry->>DB: execute native SQL
DB-->>ProfileQry: projection (counts, flags)
ProfileQry-->>ProfileSvc: Optional<projection>
alt found
ProfileSvc->>ProfileCtrl: UserProfileResponse
else not found
ProfileSvc-->>ProfileCtrl: throw USER_NOT_FOUND
end
ProfileCtrl-->>Client: 200 OK / 404
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In
`@booklog/src/main/java/com/example/booklog/domain/users/dto/UserProfileResponse.java`:
- Around line 3-7: The UserProfileResponse record currently exposes email (PII)
and must not be returned for other-user public profile views; remove the email
field from the public record UserProfileResponse and update any builders/mappers
that construct UserProfileResponse (e.g., UserMapper.toUserProfileResponse or
similar factory methods) to stop populating or expecting email; if you still
need to return email for the account owner, introduce a separate record/type
(e.g., SelfUserProfileResponse) or add an explicit method that returns a
self-only response including email and update controller/service endpoints so
public profile endpoints use the sanitized UserProfileResponse while
self-profile endpoints use the self-only type.
In
`@booklog/src/main/java/com/example/booklog/domain/users/service/UserPublicShelvesService.java`:
- Around line 66-71: The switch on the variable sort in UserPublicShelvesService
can throw an NPE if sort is null; before the switch expression, defensively set
sort to the default (LATEST) when null (e.g., assign sort =
Objects.requireNonNullElse(sort, SortType.LATEST) or an equivalent
null-coalescing assignment) so the switch always receives a non-null value and
then proceed to call the repository methods (findByShelf_IdOrderByAddedAtDesc,
findByShelf_IdOrderByAddedAtAsc, findByShelf_IdOrderByBook_TitleAsc) as
currently written.
🧹 Nitpick comments (4)
booklog/src/main/java/com/example/booklog/domain/users/dto/UserPublicShelfListResponse.java (1)
6-15: Uselongfor count fields to avoid narrowing.Counts are derived from
longin the repository/service; usingintrisks overflow and forces casts. PreferlongfortotalCountandbookCount, and update the service mapping accordingly.🔧 Proposed DTO fix
public record UserPublicShelfListResponse( - int totalCount, + long totalCount, List<UserPublicShelfItem> items ) { /** 서재 카드 1개 */ public record UserPublicShelfItem( Long shelfId, String name, - int bookCount, + long bookCount, List<ShelfBookPreview> topBooks ) {} @@ /** 특정 서재 도서 전체 목록 응답(페이징 없음) */ public record UserPublicShelfBooksResponse( - int totalCount, + long totalCount, List<UserPublicShelfBookItem> items ) {}Also applies to: 26-30
booklog/src/main/java/com/example/booklog/domain/users/service/UserPublicShelvesService.java (2)
31-41: Reduce N+1 queries when building shelf cards.
countByShelf_IdandfindTop3...are executed per shelf, which can degrade performance for users with many shelves. Consider a batch query (e.g., fetch counts per shelf in one query and top3 via window/limit per shelf, or prefetch items then group in-memory) to reduce DB round-trips.
44-48: Avoid narrowinglong→intfor book counts.
countByShelf_Idreturnslongbut is cast toint, which can overflow. Align withlongcounts in the DTO.🔧 Proposed fix
return new UserPublicShelfListResponse.UserPublicShelfItem( shelf.getId(), shelf.getName(), - (int) bookCount, + bookCount, top3 );booklog/src/main/java/com/example/booklog/domain/users/repository/UserProfileQueryRepository.java (1)
26-33: Consider performance if this pattern is reused in list queries.The multiple correlated subqueries work fine for a single-user lookup since the
WHERE u.user_id = :targetUserIdlimits results to one row. However, if a similar query pattern is adapted for fetching multiple users, consider refactoring to use JOINs with GROUP BY or aggregate in the application layer to avoid N+1-like overhead.
| public record UserProfileResponse( | ||
| Long userId, | ||
| String nickname, | ||
| String email, | ||
| String avatarUrl, |
There was a problem hiding this comment.
Do not expose email in other-user profiles.
The PR targets public/other-user profile viewing; returning email is a PII leak and a compliance/privacy risk. Remove it from the public response or gate it to “self only.”
🔐 Proposed fix (public response)
public record UserProfileResponse(
Long userId,
String nickname,
- String email,
String avatarUrl,📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public record UserProfileResponse( | |
| Long userId, | |
| String nickname, | |
| String email, | |
| String avatarUrl, | |
| public record UserProfileResponse( | |
| Long userId, | |
| String nickname, | |
| String avatarUrl, |
🤖 Prompt for AI Agents
In
`@booklog/src/main/java/com/example/booklog/domain/users/dto/UserProfileResponse.java`
around lines 3 - 7, The UserProfileResponse record currently exposes email (PII)
and must not be returned for other-user public profile views; remove the email
field from the public record UserProfileResponse and update any builders/mappers
that construct UserProfileResponse (e.g., UserMapper.toUserProfileResponse or
similar factory methods) to stop populating or expecting email; if you still
need to return email for the account owner, introduce a separate record/type
(e.g., SelfUserProfileResponse) or add an explicit method that returns a
self-only response including email and update controller/service endpoints so
public profile endpoints use the sanitized UserProfileResponse while
self-profile endpoints use the self-only type.
| List<BookshelfItems> rows = switch (sort) { | ||
| case OLDEST -> bookshelfItemsRepository.findByShelf_IdOrderByAddedAtAsc(shelfId); | ||
| case TITLE -> bookshelfItemsRepository.findByShelf_IdOrderByBook_TitleAsc(shelfId); | ||
| case AUTHOR -> bookshelfItemsRepository.findByShelf_IdOrderByAddedAtDesc(shelfId); // 가져온 뒤 자바 정렬 | ||
| default -> bookshelfItemsRepository.findByShelf_IdOrderByAddedAtDesc(shelfId); // LATEST | ||
| }; |
There was a problem hiding this comment.
Guard against null sort to avoid NPE in switch.
If sort is null (e.g., service called outside controller), the switch will throw. Default to LATEST defensively.
🛡️ Proposed fix
- List<BookshelfItems> rows = switch (sort) {
+ PublicShelfBookSort safeSort = (sort != null) ? sort : PublicShelfBookSort.LATEST;
+ List<BookshelfItems> rows = switch (safeSort) {
case OLDEST -> bookshelfItemsRepository.findByShelf_IdOrderByAddedAtAsc(shelfId);
case TITLE -> bookshelfItemsRepository.findByShelf_IdOrderByBook_TitleAsc(shelfId);
case AUTHOR -> bookshelfItemsRepository.findByShelf_IdOrderByAddedAtDesc(shelfId); // 가져온 뒤 자바 정렬
default -> bookshelfItemsRepository.findByShelf_IdOrderByAddedAtDesc(shelfId); // LATEST
};🤖 Prompt for AI Agents
In
`@booklog/src/main/java/com/example/booklog/domain/users/service/UserPublicShelvesService.java`
around lines 66 - 71, The switch on the variable sort in
UserPublicShelvesService can throw an NPE if sort is null; before the switch
expression, defensively set sort to the default (LATEST) when null (e.g., assign
sort = Objects.requireNonNullElse(sort, SortType.LATEST) or an equivalent
null-coalescing assignment) so the switch always receives a non-null value and
then proceed to call the repository methods (findByShelf_IdOrderByAddedAtDesc,
findByShelf_IdOrderByAddedAtAsc, findByShelf_IdOrderByBook_TitleAsc) as
currently written.
#120
#119
#118
Summary by CodeRabbit