Skip to content

[main ← Feature/top3] 좋아요 수 기준 랭킹 Top3 부스를 반환하는 API 작성#115

Merged
milk-stone merged 7 commits intoknu-80:mainfrom
milk-stone:feature/top3
Mar 16, 2026
Merged

[main ← Feature/top3] 좋아요 수 기준 랭킹 Top3 부스를 반환하는 API 작성#115
milk-stone merged 7 commits intoknu-80:mainfrom
milk-stone:feature/top3

Conversation

@milk-stone
Copy link
Contributor

@milk-stone milk-stone commented Mar 16, 2026

✨ 구현한 기능

  • 좋아요 수 기준 랭킹 Top3 부스를 반환하는 API

📢 논의하고 싶은 내용

🎸 기타

Summary by CodeRabbit

  • 새로운 기능
    • 부스 상위 3개 조회 기능이 추가되었습니다. 좋아요 수 기준으로 정렬된 인기 부스의 ID, 이름, 좋아요 수를 최대 3개까지 반환합니다.
  • 문서
    • 해당 새 API 엔드포인트에 대한 설명이 API 문서(스웨거)에 추가되었습니다.

@milk-stone milk-stone added the Show PR은 만들지만 머지를 바로 하는 경우 (리뷰의 여지는 남겨둠) label Mar 16, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 16, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7f6819e3-3bf2-4f69-8a66-a70a92efbdbf

📥 Commits

Reviewing files that changed from the base of the PR and between 829df29 and fa378af.

📒 Files selected for processing (3)
  • src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java
  • src/main/java/kr/co/knuserver/presentation/booth/BoothApiController.java
  • src/main/java/kr/co/knuserver/presentation/booth/docs/BoothApiControllerDocs.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java

📝 Walkthrough

Walkthrough

상위 3개 부스 좋아요 랭킹을 반환하는 API와 이를 지원하는 서비스/레디스 조회 로직, 응답 DTO 및 Swagger 문서가 추가되었습니다. 컨트롤러는 서비스 호출로 결과를 반환합니다.

Changes

Cohort / File(s) Summary
API 컨트롤러 및 문서
src/main/java/kr/co/knuserver/presentation/booth/BoothApiController.java, src/main/java/kr/co/knuserver/presentation/booth/docs/BoothApiControllerDocs.java
GET /ranking/top3 엔드포인트 추가 및 Swagger 문서화. 컨트롤러가 boothQueryService.getTop3BoothRanking()을 호출하여 BoothTop3ResponseDto 리스트를 반환.
쿼리 서비스
src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java
getTop3BoothRanking() 메서드 추가: BoothLikeService.getTopRanking(10)으로 랭킹 ID·점수 확보, 부스 엔티티 조회, DTO 매핑·정렬(좋아요 내림차순·ID 오름차순) 후 상위 3개로 제한.
좋아요 랭킹 서비스(레디스)
src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java
레디스 ZSET에서 상위 N개를 역순으로 조회하는 getTopRanking(int limit) 메서드 추가(예외 처리 포함).
응답 DTO
src/main/java/kr/co/knuserver/presentation/booth/dto/BoothTop3ResponseDto.java
BoothTop3ResponseDto 레코드 추가(boothId, boothName, likeCount).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API as "BoothApiController"
    participant Query as "BoothQueryService"
    participant LikeSvc as "BoothLikeService (Redis)"
    participant Repo as "BoothRepository"

    Client->>API: GET /ranking/top3
    API->>Query: getTop3BoothRanking()
    Query->>LikeSvc: getTopRanking(10)
    LikeSvc-->>Query: ranking IDs + scores
    Query->>Repo: findAllById(ranking IDs)
    Repo-->>Query: Booth entities
    Query->>Query: map -> BoothTop3ResponseDto, sort by likeCount desc, id asc, limit 3
    Query-->>API: List<BoothTop3ResponseDto>
    API-->>Client: 200 ApiResponse(List)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • feat#90: 좋아요 기능 구현 #91 — 기존 랭킹/좋아요 기능을 확장하는 PR로, BoothLikeService.getTopRanking 및 관련 컨트롤러·서비스 변경과 직접 연관됨.

Poem

🐰 안녕, 나는 토끼예요,
좋아요로 쏙쏙 뽑힌 셋을 보았죠,
레디스에서 점수 불러와,
정렬해 담아 전하니 기쁘네 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 주요 변경사항을 명확하게 설명합니다. 좋아요 수 기준 랭킹 Top3 부스를 반환하는 API 작성이라는 핵심 변경사항을 정확히 반영하고 있습니다.
Description check ✅ Passed PR 설명이 템플릿 구조를 따르고 있으며, 구현한 기능 섹션이 완료되었습니다. 논의할 사항과 기타 섹션도 템플릿 형식을 유지하고 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a 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/kr/co/knuserver/application/booth/BoothQueryService.java (1)

100-123: 랭킹 변환/정렬 로직이 기존 메서드와 중복됩니다.

getBoothRanking()getTop3BoothRanking()의 흐름이 거의 동일해서 이후 정렬 기준/필드 변경 시 동시 수정 누락 위험이 있습니다. 공통 private helper로 추출해 중복을 줄이는 편이 안전합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java`
around lines 100 - 123, The getTop3BoothRanking() flow largely duplicates
getBoothRanking(); extract a private helper (e.g., buildSortedBoothDtoList or
toBoothTopResponses) that accepts the ranking source (either
Set<ZSetOperations.TypedTuple<String>> rawRanking or a BoothRanking) plus an
optional limit, does the null/empty checks, loads booths via
boothRepository.findAllById, maps to BoothTop3ResponseDto using
BoothRanking.getLikeCount, sorts by likeCount desc then boothId asc, and returns
the resulting List; then replace the body of getTop3BoothRanking() and
getBoothRanking() to call that helper with the appropriate ranking input and
limit (3 for top3) to remove duplication.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java`:
- Around line 101-122: The Top3 endpoint currently fetches the entire ranking
and all booth rows, causing unnecessary load; change BoothQueryService to call a
new limited Redis fetch (use boothLikeService.getTopRanking(3) instead of
getRanking()), construct BoothRanking from that limited set, collect only the
top N booth IDs, query the DB for only those IDs (use a repository method that
takes a List of IDs, e.g., boothRepository.findAllByIdIn or findByIdIn), then
map those results back to BoothTop3ResponseDto using
BoothRanking.getLikeCount(...) and preserve ordering by sorting according to the
limited ranking (or by using the ranking order) before returning the top 3.
Ensure any helper BoothRanking constructor/usage supports the reduced set and
keep mapping via BoothTop3ResponseDto(booth.getId(), booth.getName(),
boothRanking.getLikeCount(booth.getId())).

---

Nitpick comments:
In `@src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java`:
- Around line 100-123: The getTop3BoothRanking() flow largely duplicates
getBoothRanking(); extract a private helper (e.g., buildSortedBoothDtoList or
toBoothTopResponses) that accepts the ranking source (either
Set<ZSetOperations.TypedTuple<String>> rawRanking or a BoothRanking) plus an
optional limit, does the null/empty checks, loads booths via
boothRepository.findAllById, maps to BoothTop3ResponseDto using
BoothRanking.getLikeCount, sorts by likeCount desc then boothId asc, and returns
the resulting List; then replace the body of getTop3BoothRanking() and
getBoothRanking() to call that helper with the appropriate ranking input and
limit (3 for top3) to remove duplication.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8fd0ace3-d345-445d-a7c6-685e87214064

📥 Commits

Reviewing files that changed from the base of the PR and between ac1402e and a2550d1.

📒 Files selected for processing (4)
  • src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java
  • src/main/java/kr/co/knuserver/presentation/booth/BoothApiController.java
  • src/main/java/kr/co/knuserver/presentation/booth/docs/BoothApiControllerDocs.java
  • src/main/java/kr/co/knuserver/presentation/booth/dto/BoothTop3ResponseDto.java

Comment on lines +101 to +122
Set<ZSetOperations.TypedTuple<String>> rawRanking = boothLikeService.getRanking();
if (rawRanking == null || rawRanking.isEmpty()) {
return List.of();
}

BoothRanking boothRanking = new BoothRanking(rawRanking);
if (boothRanking.isEmpty()) {
return List.of();
}

List<Booth> booths = boothRepository.findAllById(boothRanking.boothIds());

return booths.stream()
.map(booth -> new BoothTop3ResponseDto(
booth.getId(),
booth.getName(),
boothRanking.getLikeCount(booth.getId())
))
.sorted(Comparator.comparingLong(BoothTop3ResponseDto::likeCount).reversed()
.thenComparingLong(BoothTop3ResponseDto::boothId))
.limit(3)
.toList();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Top3 API가 전체 랭킹/전체 부스를 읽어 확장 시 병목이 됩니다.

Line [101]에서 전체 랭킹을 가져오고, Line [111]에서 전체 ID를 DB 조회한 뒤 마지막에 3개만 자르고 있습니다. Top3 전용 API라서 요청당 비용이 불필요하게 큽니다.

⚡ 제안 수정안 (Top N만 조회하도록 경로 축소)
-        Set<ZSetOperations.TypedTuple<String>> rawRanking = boothLikeService.getRanking();
+        // 예: Redis에서 상위 후보만 조회 (여유 버퍼 포함)
+        Set<ZSetOperations.TypedTuple<String>> rawRanking = boothLikeService.getTopRanking(10);
// BoothLikeService 쪽 예시 (별도 파일 변경)
public Set<ZSetOperations.TypedTuple<String>> getTopRanking(int limit) {
    try {
        return redisTemplate.opsForZSet().reverseRangeWithScores(RANKING_KEY, 0, limit - 1);
    } catch (DataAccessException e) {
        log.warn("[Ranking] Redis 조회 실패, 빈 셋 반환", e);
        return Collections.emptySet();
    }
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java`
around lines 101 - 122, The Top3 endpoint currently fetches the entire ranking
and all booth rows, causing unnecessary load; change BoothQueryService to call a
new limited Redis fetch (use boothLikeService.getTopRanking(3) instead of
getRanking()), construct BoothRanking from that limited set, collect only the
top N booth IDs, query the DB for only those IDs (use a repository method that
takes a List of IDs, e.g., boothRepository.findAllByIdIn or findByIdIn), then
map those results back to BoothTop3ResponseDto using
BoothRanking.getLikeCount(...) and preserve ordering by sorting according to the
limited ranking (or by using the ranking order) before returning the top 3.
Ensure any helper BoothRanking constructor/usage supports the reduced set and
keep mapping via BoothTop3ResponseDto(booth.getId(), booth.getName(),
boothRanking.getLikeCount(booth.getId())).

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java (1)

74-81: limit 경계값 검증을 추가해 주세요.

Line [76]에서 limit - 1을 바로 사용하고 있어, limit <= 0 입력 시 의도하지 않은 범위 조회가 발생할 수 있습니다. 메서드 초입에서 방어 로직을 두는 편이 안전합니다.

제안 코드
 public Set<ZSetOperations.TypedTuple<String>> getTopRanking(int limit) {
+    if (limit <= 0) {
+        return Collections.emptySet();
+    }
     try {
         return redisTemplate.opsForZSet().reverseRangeWithScores(RANKING_KEY, 0, limit - 1);
     } catch (DataAccessException e) {
         log.warn("[Ranking] Redis 조회 실패, 빈 셋 반환", e);
         return Collections.emptySet();
     }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java` around
lines 74 - 81, The getTopRanking method uses limit - 1 directly which yields
incorrect ranges for limit <= 0; add a defensive check at the start of
getTopRanking to handle non-positive limits (e.g., if limit <= 0 return
Collections.emptySet()) and only call
redisTemplate.opsForZSet().reverseRangeWithScores(RANKING_KEY, 0, limit - 1)
when limit is positive, preserving the existing DataAccessException catch and
log.
src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java (1)

101-101: 후보 버퍼 값 10은 상수로 분리하는 것을 권장합니다.

Line [101] 매직넘버를 상수화하면 의도 전달과 운영 튜닝이 쉬워집니다.

제안 코드
 public class BoothQueryService {
+    private static final int TOP3_CANDIDATE_LIMIT = 10;
 
     private final BoothRepository boothRepository;
     private final BoothImageRepository boothImageRepository;
     private final BoothLikeService boothLikeService;
@@
     public List<BoothTop3ResponseDto> getTop3BoothRanking() {
-        Set<ZSetOperations.TypedTuple<String>> rawRanking = boothLikeService.getTopRanking(10);
+        Set<ZSetOperations.TypedTuple<String>> rawRanking = boothLikeService.getTopRanking(TOP3_CANDIDATE_LIMIT);
         if (rawRanking == null || rawRanking.isEmpty()) {
             return List.of();
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java` at
line 101, The literal 10 passed to boothLikeService.getTopRanking(...) is a
magic number; introduce a descriptive constant (e.g., TOP_RANKING_LIMIT) in
BoothQueryService and replace the literal with that constant when calling
getTopRanking to improve readability and make tuning easier; optionally consider
making it a configurable property if runtime adjustment is needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java`:
- Around line 74-81: The getTopRanking method uses limit - 1 directly which
yields incorrect ranges for limit <= 0; add a defensive check at the start of
getTopRanking to handle non-positive limits (e.g., if limit <= 0 return
Collections.emptySet()) and only call
redisTemplate.opsForZSet().reverseRangeWithScores(RANKING_KEY, 0, limit - 1)
when limit is positive, preserving the existing DataAccessException catch and
log.

In `@src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java`:
- Line 101: The literal 10 passed to boothLikeService.getTopRanking(...) is a
magic number; introduce a descriptive constant (e.g., TOP_RANKING_LIMIT) in
BoothQueryService and replace the literal with that constant when calling
getTopRanking to improve readability and make tuning easier; optionally consider
making it a configurable property if runtime adjustment is needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6e9f09f6-8320-4bd1-8b4c-67241ecf3cb5

📥 Commits

Reviewing files that changed from the base of the PR and between a2550d1 and 829df29.

📒 Files selected for processing (2)
  • src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java
  • src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java

# Conflicts:
#	src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java
@milk-stone milk-stone merged commit 534d9d4 into knu-80:main Mar 16, 2026
2 checks passed
@milk-stone milk-stone deleted the feature/top3 branch March 16, 2026 08:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Show PR은 만들지만 머지를 바로 하는 경우 (리뷰의 여지는 남겨둠)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant