-
Notifications
You must be signed in to change notification settings - Fork 1
[LNK-26] 상세 피드 조회 시 이전 다음 피드 id 추가 #74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The head ref may contain hidden characters: "feat/LNK-26-Leenk-\uC0C1\uC138-\uD53C\uB4DC-\uC870\uD68C-\uC2DC-\uC774\uC804-\uB2E4\uC74C-\uD53C\uB4DC-id-\uCD94\uAC00"
Conversation
Walkthrough피드 네비게이션 기능을 추가합니다. 현재 피드 기준의 이전/다음 피드 조회(커서 기반), 관련 DTO/레코드, 저장소 쿼리, 서비스·유스케이스·매퍼·컨트롤러 변경 및 DB 인덱스가 도입되었습니다. Changes
Sequence DiagramsequenceDiagram
participant Client
participant Controller
participant Usecase
participant FeedGetService
participant FeedRepository
participant FeedMapper
Client->>Controller: GET /feeds/{feedId}/navigation
Controller->>Usecase: getFeedNavigation(feedId, userId, prevSize, nextSize)
Usecase->>Usecase: validateSize(prevSize/nextSize)
Usecase->>FeedGetService: getFeed(feedId)
FeedGetService->>FeedRepository: findById(feedId)
FeedRepository-->>FeedGetService: current Feed
FeedGetService-->>Usecase: current Feed
Usecase->>FeedGetService: findPrevFeedsWithHasMore(current, blockedUsers, prevSize)
FeedGetService->>FeedRepository: findPrevFeeds(createDate, blockedIds, pageSize+1)
FeedRepository-->>FeedGetService: prevFeeds (+maybe one)
FeedGetService-->>Usecase: FeedNavigationResult(prevFeeds, hasMore)
Usecase->>FeedGetService: findNextFeedsWithHasMore(current, blockedUsers, nextSize)
FeedGetService->>FeedRepository: findNextFeeds(createDate, blockedIds, pageSize+1)
FeedRepository-->>FeedGetService: nextFeeds (+maybe one)
FeedGetService-->>Usecase: FeedNavigationResult(nextFeeds, hasMore)
Usecase->>Usecase: 미디어/링크된 사용자 데이터 수집
Usecase->>FeedMapper: toFeedNavigationResponse(current, prev, next, mediaMap, userMap, flags)
FeedMapper-->>Usecase: FeedNavigationResponse
Usecase-->>Controller: FeedNavigationResponse
Controller-->>Client: CommonResponse<FeedNavigationResponse>
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25분
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/main/java/leets/leenk/domain/feed/presentation/FeedController.java (1)
56-61: 파라미터 범위 검증을 컨트롤러 레벨에서도 추가하는 것을 권장합니다.현재
prevSize와nextSize파라미터의 범위 검증이 usecase 레이어(validateSize메서드)에서만 이루어지고 있습니다. 컨트롤러 레벨에서 Bean Validation을 추가하면 다음과 같은 이점이 있습니다:
- Fail-fast 원칙에 따라 조기에 잘못된 요청을 거부
- 명확한 400 Bad Request 응답 제공
- API 문서와 실제 검증 로직의 일관성 확보
다음과 같이 검증 어노테이션을 추가할 수 있습니다:
@RequestParam(required = false) - @Parameter(description = "이전 피드 개수 (0~3)", example = "1") + @Parameter(description = "이전 피드 개수 (0~3)", example = "1") + @Min(0) @Max(3) Integer prevSize, @RequestParam(required = false) - @Parameter(description = "다음 피드 개수 (0~3)", example = "1") + @Parameter(description = "다음 피드 개수 (0~3)", example = "1") + @Min(0) @Max(3) Integer nextSizeimports에 추가:
+import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Max;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/main/java/leets/leenk/domain/feed/application/dto/response/FeedNavigationResponse.java(1 hunks)src/main/java/leets/leenk/domain/feed/application/mapper/FeedMapper.java(1 hunks)src/main/java/leets/leenk/domain/feed/application/usecase/FeedUsecase.java(3 hunks)src/main/java/leets/leenk/domain/feed/domain/entity/Feed.java(1 hunks)src/main/java/leets/leenk/domain/feed/domain/repository/FeedRepository.java(2 hunks)src/main/java/leets/leenk/domain/feed/domain/service/FeedGetService.java(2 hunks)src/main/java/leets/leenk/domain/feed/domain/service/dto/FeedNavigationResult.java(1 hunks)src/main/java/leets/leenk/domain/feed/presentation/FeedController.java(1 hunks)src/main/java/leets/leenk/domain/feed/presentation/ResponseCode.java(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-12T14:17:56.674Z
Learnt from: hyxklee
Repo: Leets-Makers/Leenk-BE PR: 54
File: src/main/java/leets/leenk/domain/feed/domain/service/LinkedUserDeleteService.java:18-18
Timestamp: 2025-08-12T14:17:56.674Z
Learning: The LinkedUser entity in the Leenk-BE project has a unique constraint on the combination of feed_id and user_id columns (UniqueConstraint(columnNames = {"feed_id", "user_id"})), which requires explicit flush() calls after delete operations to prevent constraint violations during the delete-and-recreate pattern used in feed updates.
Applied to files:
src/main/java/leets/leenk/domain/feed/application/usecase/FeedUsecase.javasrc/main/java/leets/leenk/domain/feed/domain/entity/Feed.java
📚 Learning: 2025-08-12T14:17:56.674Z
Learnt from: hyxklee
Repo: Leets-Makers/Leenk-BE PR: 54
File: src/main/java/leets/leenk/domain/feed/domain/service/LinkedUserDeleteService.java:18-18
Timestamp: 2025-08-12T14:17:56.674Z
Learning: In the Leenk-BE project, the LinkedUser entity has DB unique constraints that require explicit flush() calls after deleteAllByFeed operations to prevent constraint violations when recreating the relationships immediately afterward.
Applied to files:
src/main/java/leets/leenk/domain/feed/application/usecase/FeedUsecase.java
🧬 Code graph analysis (3)
src/main/java/leets/leenk/domain/feed/application/usecase/FeedUsecase.java (3)
src/main/java/leets/leenk/domain/feed/domain/service/FeedGetService.java (1)
Service(18-105)src/main/java/leets/leenk/domain/media/domain/service/MediaGetService.java (1)
Service(13-51)src/main/java/leets/leenk/domain/feed/domain/service/LinkedUserGetService.java (1)
Service(14-27)
src/main/java/leets/leenk/domain/feed/application/dto/response/FeedNavigationResponse.java (1)
src/main/java/leets/leenk/global/sqs/application/dto/SqsMessageEvent.java (1)
Builder(6-16)
src/main/java/leets/leenk/domain/feed/domain/service/FeedGetService.java (2)
src/main/java/leets/leenk/domain/feed/application/usecase/FeedUsecase.java (1)
Service(41-352)src/main/java/leets/leenk/domain/user/domain/service/blockuser/UserBlockService.java (1)
Service(11-28)
🔇 Additional comments (4)
src/main/java/leets/leenk/domain/feed/application/dto/response/FeedNavigationResponse.java (1)
8-25: LGTM! 커서 기반 페이지네이션 구조가 잘 설계되었습니다.record 타입을 사용하여 불변 DTO를 간결하게 구현했으며, 무한 스크롤에 필요한 모든 정보(현재 피드, 이전/다음 피드 목록, hasMore 플래그)를 적절하게 포함하고 있습니다. Swagger 문서화도 충분합니다.
src/main/java/leets/leenk/domain/feed/domain/service/FeedGetService.java (3)
47-70: LGTM! 이전 피드 조회 로직이 올바르게 구현되었습니다.size+1 패턴을 사용한
hasMore판단과 ASC 조회 후 역정렬하는 로직이 명확합니다. 차단 사용자 필터링도 적절하게 처리되고 있으며, 주석이 상세하여 유지보수성이 좋습니다.
77-97: LGTM! 다음 피드 조회 로직이 올바르게 구현되었습니다.DESC 조회로 이미 정렬된 결과를 반환하는 로직이 명확하며,
findPrevFeedsWithHasMore와의 차이점(역정렬 불필요)이 주석으로 잘 설명되어 있습니다.
99-104: LGTM! 중복 코드 제거를 위한 좋은 리팩토링입니다.기존
findAll메서드(라인 30-33)에서 반복되던 로직을 헬퍼 메서드로 추출하여 코드 중복을 제거했습니다.
| "WHERE f.createDate > :currentCreateDate " + | ||
| "AND f.deletedAt IS NULL " + | ||
| "AND (:blockedUserIds IS NULL OR u.id NOT IN :blockedUserIds) " + | ||
| "ORDER BY f.createDate ASC") | ||
| List<Feed> findPrevFeeds( | ||
| @Param("currentCreateDate") LocalDateTime currentCreateDate, | ||
| @Param("blockedUserIds") List<Long> blockedUserIds, | ||
| Pageable pageable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
컬렉션 파라미터에 null을 넘겨 즉시 실패합니다
FeedGetService.findPrevFeedsWithHasMore/findNextFeedsWithHasMore에서 차단 사용자가 없을 때 blockedUserIds.isEmpty() ? null : blockedUserIds로 이 쿼리를 호출합니다. 하지만 Hibernate 6에서는 컬렉션 파라미터에 null을 바인딩하는 순간 IllegalArgumentException: Collection parameter value must not be null가 발생하여 대부분의 사용자(차단 목록이 비어 있음)에게 네비게이션 API가 바로 500을 뱉게 됩니다. 파라미터를 절대 null로 보내지 않도록 하고(빈 리스트 그대로 전달하거나 분기하여 다른 쿼리를 호출), 필요하다면 이 조건을 단순화해주세요.
예시 수정:
--- a/src/main/java/leets/leenk/domain/feed/domain/service/FeedGetService.java
+++ b/src/main/java/leets/leenk/domain/feed/domain/service/FeedGetService.java
@@
- List<Feed> feeds = feedRepository.findPrevFeeds(
- currentFeed.getCreateDate(),
- blockedUserIds.isEmpty() ? null : blockedUserIds,
- pageable
- );
+ List<Long> filteredBlockedIds = blockedUserIds;
+ List<Feed> feeds = feedRepository.findPrevFeeds(
+ currentFeed.getCreateDate(),
+ filteredBlockedIds,
+ pageable
+ );
@@
- List<Feed> feeds = feedRepository.findNextFeeds(
- currentFeed.getCreateDate(),
- blockedUserIds.isEmpty() ? null : blockedUserIds,
- pageable
- );
+ List<Long> filteredBlockedIds = blockedUserIds;
+ List<Feed> feeds = feedRepository.findNextFeeds(
+ currentFeed.getCreateDate(),
+ filteredBlockedIds,
+ pageable
+ );(필요하다면 빈 리스트일 때는 조건 자체를 생략하는 전용 쿼리로 분기해도 됩니다.) 이 수정이 없으면 네비게이션 기능이 정상 동작하지 않습니다.
Also applies to: 46-54
🤖 Prompt for AI Agents
In src/main/java/leets/leenk/domain/feed/domain/repository/FeedRepository.java
around lines 31-38 (and similarly 46-54), the query binds a collection parameter
:blockedUserIds which is sometimes passed as null causing Hibernate 6 to throw
IllegalArgumentException; change the repository methods so they never bind null
for collection parameters — either accept an empty list and adjust the JPQL/SQL
to handle empty collections (e.g., use (:blockedUserIds IS EMPTY OR u.id NOT IN
:blockedUserIds) or move the "u.id NOT IN :blockedUserIds" clause into an
alternate query when blockedUserIds.isEmpty()), or overload/branch to a
different query that omits the blockedUserIds condition when the list is empty;
ensure callers pass Collections.emptyList() instead of null if you keep a single
query.
soo0711
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
클로드 코드 짱이네욥.. 개행만 추가하면 될 것 같습니당
인덱스로 쿼리를 개선하는 것도 좋네요!
수고하셨습니다 ~
1winhyun
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고생하셨습니다!!
| @Schema(description = "더 다음 피드 존재 여부", example = "true") | ||
| boolean hasMoreNext | ||
| ) { | ||
| } No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
개행 처리 부탁드려요!!
| List<Feed> feeds, | ||
| boolean hasMore | ||
| ) { | ||
| } No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
마찬가지로 개행처리 부탁드려요!!
| * ASC로 조회한 결과를 최신순(DESC)으로 역정렬하여 반환 | ||
| * 한 번의 쿼리로 피드 목록과 추가 피드 존재 여부를 함께 반환 | ||
| */ | ||
| public FeedNavigationResult findPrevFeedsWithHasMore(Feed currentFeed, List<UserBlock> blockedUsers, int size) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이전 피드를 조회하는 찾을 때 반드시 이전에 만들어진 모든 피드를 반환해야하는건가요?
각 피드를 조회할 때마다 이전 하나와 이후 하나의 피드, 총 두개만 추가로 같이 반환해도 가능할 것 같다는 생각이 들었습니다.
즉, 어느 한 피드를 조회할 경우 이전 피드와 다음 피드가 함께 조회되며 만약 이전 피드를 조회하면 그 피드의 바로 이전 피드와 바로 다음 피드(처음에 얘기한 '어느 한 피드'가 곧 '바로 다음 피드'가 되겠죠?)가 같이 조회되도록 하는 것입니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현재 입력한 값(여기서는 size가 되겟죠) (기본값은 1) 만큼만 조회해서 위아래로 붙여서 반환하고 있습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아 넵 알겠습니다!! 확인했습니다!!
| * DESC로 조회하므로 그대로 반환 | ||
| * 한 번의 쿼리로 피드 목록과 추가 피드 존재 여부를 함께 반환 | ||
| */ | ||
| public FeedNavigationResult findNextFeedsWithHasMore(Feed currentFeed, List<UserBlock> blockedUsers, int size) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
마찬가지로 다음 피드를 조회하는 찾을 때 반드시 이후에 만들어진 모든 피드를 반환해야하는건가요?
각 피드를 조회할 때마다 이전 하나와 이후 하나의 피드, 총 두개만 추가로 같이 반환해도 가능할 것 같다는 생각이 들었습니다.
Related issue 🛠
작업 내용 💻
세부사항
스크린샷 📷
같이 얘기해보고 싶은 내용이 있다면 작성 📢
Summary by CodeRabbit
릴리스 노트
New Features
Performance