Conversation
Redis INCR을 활용한 원자적 클릭 수 누적, KST 자정 자동 초기화(ShedLock), 클릭 랭킹 조회 시 rank 필드 및 resetAt(다음 자정 ISO8601) 제공 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | Summary |
|---|---|
Controller backend/src/main/java/moadong/club/controller/ClubClickController.java |
/api/game 경로 아래에 POST /click (클릭 기록) 및 GET /ranking (순위 조회) 엔드포인트를 포함하는 새로운 REST 컨트롤러 추가. |
Payloads backend/src/main/java/moadong/club/payload/request/ClubClickRequest.java, backend/src/main/java/moadong/club/payload/response/ClubClickResponse.java, backend/src/main/java/moadong/club/payload/response/ClubClickRankingResponse.java |
클릭 요청 데이터 및 응답 데이터를 정의하는 불변 레코드 타입 추가. ClubClickRankingResponse는 순위 항목 리스트(clubs)와 다음 초기화 시간(resetAt)을 포함하고, 중첩된 ClubRankItem 레코드를 정의. |
Service backend/src/main/java/moadong/club/service/ClubClickService.java |
Redis를 이용한 클릭 수 증가(recordClick), 순위 계산 및 조회(getRanking), 그리고 ShedLock을 통한 매일 자정(KST) 데이터 초기화(resetDailyClicks) 기능을 구현하는 새로운 서비스 클래스 추가. |
Sequence Diagram(s)
sequenceDiagram
participant Client
participant Controller as ClubClickController
participant Service as ClubClickService
participant Redis
rect rgba(100, 150, 255, 0.5)
Note over Client,Redis: 클릭 기록 흐름
Client->>Controller: POST /api/game/click<br/>(clubName, ctAt)
Controller->>Service: recordClick(clubName)
Service->>Redis: INCR club:click:{clubName}
Redis-->>Service: clickCount
Service-->>Controller: ClubClickResponse
Controller-->>Client: 200 OK
end
rect rgba(100, 255, 150, 0.5)
Note over Client,Redis: 순위 조회 흐름
Client->>Controller: GET /api/game/ranking
Controller->>Service: getRanking()
Service->>Redis: KEYS club:click:*
Redis-->>Service: key list
Service->>Redis: MGET (각 key에 대한 값)
Redis-->>Service: counts
Service->>Service: 정렬 및 순위 계산
Service-->>Controller: ClubClickRankingResponse
Controller-->>Client: 200 OK
end
rect rgba(255, 150, 100, 0.5)
Note over Service,Redis: 매일 자정 초기화 (ShedLock)
Service->>Service: resetDailyClicks() 자동 실행<br/>(매일 00:00 KST)
Service->>Redis: DEL club:click:*
Redis-->>Service: 삭제 완료
Service->>Service: 로그 기록
end
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 minutes
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | Docstring coverage is 0.00% 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 제목이 주요 변경사항을 명확하게 요약하고 있습니다. 동아리 클릭 게임 API 추가는 이 PR의 핵심 변경사항이며, 제목은 간결하고 구체적입니다. |
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing Touches
📝 Generate docstrings
- Create stacked PR
- Commit on current branch
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
feature/mouse-game
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 @coderabbitai help to get the list of available commands and usage tips.
Test Results123 tests 123 ✅ 17s ⏱️ Results for commit 93e9fdb. ♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
backend/src/main/java/moadong/club/payload/request/ClubClickRequest.java (1)
3-3: 사용되지 않는ctAt필드는 요청 계약에서 제거하는 편이 좋겠습니다.현재
backend/src/main/java/moadong/club/controller/ClubClickController.java의 Line 29와backend/src/main/java/moadong/club/service/ClubClickService.java의 Line 35-38에서는clubName만 사용하고 있어서,ctAt는 무엇을 보내도 무시됩니다. 공개 API에 의미 없는 입력 필드를 남겨두면 클라이언트 혼란과 향후 호환성 부담만 늘어납니다. 시간이 필요하면 클라이언트 입력 대신 서버에서 기록하는 쪽이 안전합니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/src/main/java/moadong/club/payload/request/ClubClickRequest.java` at line 3, The ClubClickRequest record includes an unused ctAt field which should be removed; update the request contract by deleting the ctAt component from the ClubClickRequest declaration so it only exposes clubName, then update any usages/constructors or deserialization expectations accordingly (inspect ClubClickController and ClubClickService which currently only use clubName) and ensure server-side timestamping/logging is performed where needed instead of relying on a client-supplied ctAt.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@backend/src/main/java/moadong/club/controller/ClubClickController.java`:
- Around line 26-29: The controller currently passes unvalidated
ClubClickRequest.clubName() into Redis via clubClickService.recordClick,
allowing arbitrary/empty/oversized keys; add validation annotations (e.g.,
`@NotBlank` and `@Size`(max=...)) to the ClubClickRequest fields (the clubName
property) and change the controller method recordClick to accept a validated
request by adding `@Valid` to the parameter (and annotate the controller class
with `@Validated` if your setup requires it) so Spring will reject blank/too-long
inputs before calling clubClickService.recordClick.
In `@backend/src/main/java/moadong/club/service/ClubClickService.java`:
- Around line 41-42: getRanking and resetDailyClicks currently call
stringRedisTemplate.keys(CLICK_KEY_PATTERN) which will block Redis as the club
count grows; refactor to use a Sorted Set for click counts (use ZINCRBY when
incrementing clicks instead of per-key INCR) and implement getRanking to call
ZREVRANGE (with scores) to return top-N in constant time; for resetDailyClicks
replace KEYS+bulk DEL with a SCAN-based iterator (scan with MATCH club:click:*
and process in small batches, using pipeline/unlink or batched DEL) to avoid
long blocking operations; update references to CLICK_KEY_PATTERN, getRanking,
resetDailyClicks and stringRedisTemplate interactions accordingly.
- Around line 23-27: ClubClickService is currently annotated with
`@ConditionalOnProperty` which prevents the bean from being created when
scheduling.enabled=false and breaks injection into ClubClickController; make
ClubClickService unconditional (remove `@ConditionalOnProperty` from the
ClubClickService class) so recordClick() and getRanking() stay available, then
extract the scheduled logic (resetDailyClicks()) into a new scheduler component
class (e.g., ClubClickScheduler) annotated with `@Component` and
`@ConditionalOnProperty`(name="scheduling.enabled", havingValue="true",
matchIfMissing=true) and move the `@Scheduled` method resetDailyClicks() there,
wiring the new scheduler with ClubClickService via constructor injection.
---
Nitpick comments:
In `@backend/src/main/java/moadong/club/payload/request/ClubClickRequest.java`:
- Line 3: The ClubClickRequest record includes an unused ctAt field which should
be removed; update the request contract by deleting the ctAt component from the
ClubClickRequest declaration so it only exposes clubName, then update any
usages/constructors or deserialization expectations accordingly (inspect
ClubClickController and ClubClickService which currently only use clubName) and
ensure server-side timestamping/logging is performed where needed instead of
relying on a client-supplied ctAt.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d744ab84-69f5-4690-a6fa-97d41e1830af
📒 Files selected for processing (5)
backend/src/main/java/moadong/club/controller/ClubClickController.javabackend/src/main/java/moadong/club/payload/request/ClubClickRequest.javabackend/src/main/java/moadong/club/payload/response/ClubClickRankingResponse.javabackend/src/main/java/moadong/club/payload/response/ClubClickResponse.javabackend/src/main/java/moadong/club/service/ClubClickService.java
scheduling.enabled=false 시 서비스 빈 자체가 생성되지 않아 API 엔드포인트가 동작하지 않는 문제 수정. @ConditionalOnProperty를 ClubClickService에서 제거하고, resetDailyClicks 스케줄 작업만 ClubClickScheduler로 분리. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
#️⃣연관된 이슈
📝작업 내용
Summary
POST /api/game/click— clubName별 클릭 수를 Redis INCR으로 원자적 누적GET /api/game/ranking— 클릭 수 기준 내림차순 랭킹 반환 (rank 필드, resetAt 포함)작업사항
club:click:{clubName}StringRedisTemplate사용으로 INCR 직렬화 충돌 방지GET /api/club/search/?keyword=호출 → 매칭동아리명 드롭다운 표시
중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
새로운 기능