Conversation
개요부서 랭킹 데이터 처리 방식을 리팩토링했습니다. 변경 사항
시퀀스 다이어그램sequenceDiagram
participant Service as DepartmentRankService
participant Repo as DepartmentRankingRepository
participant DB as Database
participant DTO as DepartmentRankingTemp
Service->>Repo: getFinishedDepartmentRanking(period, "DAILY")
Repo->>DB: WITH all_departments CTE<br/>SELECT from user table<br/>LEFT JOIN department_ranking<br/>RANK() window function
DB-->>Repo: List of all departments<br/>with rankings
Repo->>DTO: Create DepartmentRankingTemp<br/>(department, totalMillis, ranking)
DTO->>DTO: Store raw enum value<br/>in department field
Repo-->>Service: List<DepartmentRankingTemp>
Service->>Service: Find user's ranking<br/>or create default
Service-->>Service: Return response with<br/>getDepartmentName() results
코드 리뷰 예상 소요 시간🎯 3 (중간) | ⏱️ ~25분 추가 검토 필요 영역:
관련 PR
추천 검토자
시
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Tip 📝 Customizable high-level summaries are now available in beta!You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.
Example instruction:
Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later. 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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/main/java/com/gpt/geumpumtabackend/rank/dto/DepartmentRankingTemp.java(1 hunks)src/main/java/com/gpt/geumpumtabackend/rank/repository/DepartmentRankingRepository.java(1 hunks)src/main/java/com/gpt/geumpumtabackend/rank/service/DepartmentRankService.java(4 hunks)src/main/java/com/gpt/geumpumtabackend/study/repository/StudySessionRepository.java(4 hunks)
| WITH all_departments AS ( | ||
| SELECT 'ARCHITECTURE_ENGINEERING' as dept | ||
| UNION ALL SELECT 'ARCHITECTURE' | ||
| UNION ALL SELECT 'CIVIL_ENGINEERING' | ||
| UNION ALL SELECT 'ENVIRONMENTAL_ENGINEERING' | ||
| UNION ALL SELECT 'MECHANICAL_ENGINEERING' | ||
| UNION ALL SELECT 'MECHANICAL_SYSTEMS_ENGINEERING' | ||
| UNION ALL SELECT 'SMART_MOBILITY' | ||
| UNION ALL SELECT 'INDUSTRIAL_ENGINEERING' | ||
| UNION ALL SELECT 'APPLIED_MATH_BIGDATA' | ||
| UNION ALL SELECT 'POLYMER_ENGINEERING' | ||
| UNION ALL SELECT 'MATERIALS_ENGINEERING' | ||
| UNION ALL SELECT 'SEMICONDUCTOR_SYSTEMS' | ||
| UNION ALL SELECT 'ELECTRONIC_SYSTEMS' | ||
| UNION ALL SELECT 'SOFTWARE' | ||
| UNION ALL SELECT 'ARTIFICIAL_INTELLIGENCE' | ||
| UNION ALL SELECT 'COMPUTER_ENGINEERING' | ||
| UNION ALL SELECT 'MATERIALS_DESIGN_ENGINEERING' | ||
| UNION ALL SELECT 'CHEMICAL_ENGINEERING' | ||
| UNION ALL SELECT 'CHEMICAL_BIO_MATERIALS' | ||
| UNION ALL SELECT 'OPTICAL_SYSTEMS' | ||
| UNION ALL SELECT 'BIOMEDICAL_ENGINEERING' | ||
| UNION ALL SELECT 'IT_CONVERGENCE' | ||
| UNION ALL SELECT 'LIBERAL_MAJOR' | ||
| UNION ALL SELECT 'BUSINESS_ADMINISTRATION' | ||
| ) | ||
| SELECT d.dept as department, | ||
| COALESCE(dr.total_millis, 0) as totalMillis, | ||
| RANK() OVER (ORDER BY COALESCE(dr.total_millis, 0) DESC) as ranking | ||
| FROM all_departments d | ||
| LEFT JOIN department_ranking dr ON d.dept = dr.department | ||
| AND dr.calculated_at = :period | ||
| AND dr.ranking_type = :rankingType | ||
| ORDER BY COALESCE(dr.total_millis, 0) DESC | ||
| """, nativeQuery = true) |
There was a problem hiding this comment.
하드코딩된 학과 목록은 enum 변경 시 즉시 깨집니다.
all_departments CTE에 24개 학과 문자열을 직접 나열하면서 Department enum과의 단일 소스가 무너졌습니다. 추후 enum에 신규 학과가 추가되거나 이름이 바뀔 때 이 목록을 잊고 갱신하지 않으면, 해당 학과는 department_ranking 테이블에 데이터가 존재해도 LEFT JOIN 대상에 없어서 완전히 빠지게 됩니다. 즉시 기능 장애가 발생하는 구조입니다. DB에 기준 테이블을 두거나, 최소한 user/department_ranking에서 SELECT DISTINCT department를 합쳐 동적으로 베이스 세트를 만들도록 수정해야 합니다.
| // 사용자의 학과를 찾지 못한 경우 0초, 마지막 순위로 설정 | ||
| if (myRanking == null && user.getDepartment() != null) { | ||
| myRanking = new DepartmentRankingEntryResponse( | ||
| user.getDepartment().getKoreanName(), | ||
| 0L, | ||
| (long) departmentRankingList.size() + 1 | ||
| ); | ||
| } |
There was a problem hiding this comment.
자동 순위가 RANK() 결과와 어긋납니다.
departmentRankingList.size() + 1은 SQL RANK()가 동점에 대해 순위를 건너뛴다는 사실을 무시합니다. 예를 들어 모든 total_millis가 0이면 각 행의 ranking은 1이 되는데, 현재 로직은 사용자 fallback 순위를 25로 만들어 버려 잘못된 정보가 노출됩니다. 마지막 항목의 ranking 값에 +1(리스트가 비어 있으면 1)하도록 보정해야 일관성이 유지됩니다.
if (myRanking == null && user.getDepartment() != null) {
- myRanking = new DepartmentRankingEntryResponse(
- user.getDepartment().getKoreanName(),
- 0L,
- (long) departmentRankingList.size() + 1
- );
+ long baseRank = departmentRankingList.isEmpty()
+ ? 0L
+ : departmentRankingList.get(departmentRankingList.size() - 1).getRanking();
+ myRanking = new DepartmentRankingEntryResponse(
+ user.getDepartment().getKoreanName(),
+ 0L,
+ baseRank + 1
+ );
}🤖 Prompt for AI Agents
In
src/main/java/com/gpt/geumpumtabackend/rank/service/DepartmentRankService.java
around lines 105 to 112, the fallback rank uses departmentRankingList.size() + 1
which diverges from SQL RANK() behavior when ties exist; instead compute the
fallback as (last entry's ranking + 1) or 1 if the list is empty. Retrieve the
last DepartmentRankingEntryResponse from departmentRankingList when size > 0 to
get its ranking value and set the fallback rank to that value + 1; if the list
is empty use 1L. Ensure null checks on departmentRankingList and handle
user.getDepartment() condition as before.
🚀 1. 개요
학과 랭킹 조회 시 실제 데이터가 없는 학과들이 빈값으로 표시되는 문제를 해결했습니다.
기존에는 하드코딩된 학과 목록(WITH departments)을 기준으로 랭킹을 조회했으나, 실제 사용자가 등록된 학과만 조회하도록 개선했습니다.
📝 2. 주요 변경 사항
1.
DepartmentRankingTemp.javadepartment필드 추가: 원본 enum 값 저장getDepartmentName()메서드 개선:IllegalArgumentException예외 처리 추가2.
DepartmentRankingRepository.javaWITH all_departments AS절을 통해 전체 24개 학과 목록 정의LEFT JOIN을 사용하여 데이터가 없는 학과도 0으로 표시RANK() OVER (ORDER BY ...)함수로 동적 순위 계산RankingTypeenum →String으로 변경3.
DepartmentRankService.java3-1. enum을 String으로 변환하여 전달
RankingType.DAILY→RankingType.DAILY.name()RankingType.WEEKLY→RankingType.WEEKLY.name()RankingType.MONTHLY→RankingType.MONTHLY.name()Summary by CodeRabbit
릴리스 노트
기능 개선
버그 수정