Conversation
- 추후에 수정필요!!
…-category-color-add [hotfix] alias color 빠진 api 1개 수정 + category color 값을 반환해야하는 요구사항에 따라 코드 수정
WalkthroughJWT 인증 필터에 쿠키 기반 토큰 조회가 추가되었고, 방 관련 응답 DTO들에 aliasColor/categoryColor 필드가 확장되었습니다. 카테고리 색상 조회를 위해 Port/Adapter/Repository 계층에 메서드가 추가되었으며, 관련 서비스들이 신규 필드를 매핑하도록 수정되었습니다. 일부 DTO는 빌더 방식으로 전환되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant JwtFilter as JwtAuthenticationFilter
participant App as Application
Client->>JwtFilter: HTTP 요청
alt Authorization 헤더에 Bearer 토큰 존재
JwtFilter->>JwtFilter: 헤더에서 토큰 추출
else 헤더에 없음/무효
JwtFilter->>JwtFilter: 쿠키 목록 탐색 후 이름=JWT_HEADER_KEY 토큰 추출
end
JwtFilter->>App: 토큰 설정 후 체인 진행(또는 토큰 없음 처리)
sequenceDiagram
participant Client
participant Service as RoomShowRecruitingDetailViewService
participant Port as RoomQueryPort
participant Repo as CategoryJpaRepository
participant Adapter as RoomQueryPersistenceAdapter
Client->>Service: 방 모집 상세 조회
Service->>Port: findAliasColorOfCategory(room.category)
Port->>Adapter: 위임
Adapter->>Repo: findAliasColorByValue(category.value)
Repo-->>Adapter: Optional<String> color
Adapter-->>Port: color 또는 예외
Port-->>Service: color
Service-->>Client: categoryColor 포함한 응답(Builder)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
Test Results383 tests 383 ✅ 31s ⏱️ Results for commit 2a19181. |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (4)
src/main/java/konkuk/thip/common/security/filter/JwtAuthenticationFilter.java (1)
86-86: 로그 레벨 조정 제안 — 토큰 없음은 INFO보다 DEBUG가 적절운영 환경에서 불필요한 로그 노이즈를 줄이기 위해 DEBUG 레벨이 적절합니다.
- log.info("토큰이 없습니다."); + log.debug("토큰이 없습니다.");src/main/java/konkuk/thip/room/application/port/out/RoomQueryPort.java (1)
41-46: Port에 표현 계층 색상 문자열 반환 도입 — 장기적으로 도메인/쿼리 결과에 통합 권장임시 메서드로 표기된 만큼, 중장기적으로는:
- Category 자체가 표현 속성(예: color)을 내포하거나,
- CategoryInfo/CategoryViewProps 같은 VO/DTO로 color를 함께 반환하거나,
- 관련 조회 쿼리에 join하여 한 번에 가져오도록 리파인
하는 방향이 응집도/성능 측면에서 유리합니다. 현재는 단건 조회라 영향이 작지만, 리스트 응답으로 확장될 경우 N+1 리스크가 있습니다(캐싱 또는 벌크 조회로 선대응 권장).
src/main/java/konkuk/thip/room/adapter/out/persistence/repository/category/CategoryJpaRepository.java (1)
14-18: JPQL 쿼리 최적화 고려현재 구현이 동작하지만, 다음과 같은 최적화를 고려해보시기 바랍니다:
- 쿼리가 자주 호출된다면
@QueryHints를 사용한 캐싱 고려CategoryJpaEntity와AliasForCategoryJpaEntity간의 관계가 1:1이라면 fetch join 사용 검토TODO 주석에 따라 리팩토링 시 이러한 성능 최적화도 함께 고려하시면 좋겠습니다.
src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java (1)
109-115: 예외 처리는 적절하나 리팩토링 필요
EntityNotFoundException사용과 에러 코드 설정이 적절합니다. TODO 주석에 따라 리팩토링 시 다음 사항을 고려하시기 바랍니다:
- 캐싱 메커니즘 도입 (카테고리 색상은 자주 변경되지 않으므로)
- 카테고리 관련 로직을 별도 서비스로 분리
카테고리 색상은 변경 빈도가 낮은 데이터이므로, 애플리케이션 레벨 캐싱(@Cacheable)이나 Redis 캐싱을 도입하면 성능 향상을 기대할 수 있습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
src/main/java/konkuk/thip/common/security/filter/JwtAuthenticationFilter.java(2 hunks)src/main/java/konkuk/thip/room/adapter/in/web/response/RoomGetMemberListResponse.java(1 hunks)src/main/java/konkuk/thip/room/adapter/in/web/response/RoomPlayingDetailViewResponse.java(1 hunks)src/main/java/konkuk/thip/room/adapter/in/web/response/RoomRecruitingDetailViewResponse.java(2 hunks)src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java(3 hunks)src/main/java/konkuk/thip/room/adapter/out/persistence/repository/category/CategoryJpaRepository.java(1 hunks)src/main/java/konkuk/thip/room/application/port/out/RoomQueryPort.java(1 hunks)src/main/java/konkuk/thip/room/application/service/RoomGetMemberListService.java(1 hunks)src/main/java/konkuk/thip/room/application/service/RoomShowPlayingDetailViewService.java(3 hunks)src/main/java/konkuk/thip/room/application/service/RoomShowRecruitingDetailViewService.java(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#113
File: src/main/java/konkuk/thip/recentSearch/adapter/out/persistence/RecentSearchCommandPersistenceAdapter.java:38-44
Timestamp: 2025-07-30T14:05:04.945Z
Learning: seongjunnoh는 코드 최적화 제안에 대해 구체적인 기술적 근거와 효율성 차이를 이해하고 싶어하며, 성능 개선 방식에 대한 상세한 설명을 선호한다.
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#93
File: src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java:49-114
Timestamp: 2025-07-28T16:44:31.224Z
Learning: seongjunnoh는 코드 중복 문제에 대한 리팩토링 제안을 적극적으로 수용하고 함수형 인터페이스를 활용한 해결책을 선호한다.
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#195
File: src/main/java/konkuk/thip/feed/application/mapper/FeedQueryMapper.java:0-0
Timestamp: 2025-08-13T05:22:32.287Z
Learning: seongjunnoh는 데이터 무결성과 중복 방지에 대한 고민이 깊으며, LinkedHashSet을 활용한 중복 제거와 순서 보장을 동시에 달성하는 솔루션을 선호한다.
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#112
File: src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepositoryImpl.java:272-272
Timestamp: 2025-07-30T10:44:34.115Z
Learning: seongjunnoh는 피드 커서 페이지네이션에서 LocalDateTime 단일 커서 방식을 선호하며, 복합 키 기반 커서보다 구현 단순성과 성능을 우선시한다.
🧬 Code Graph Analysis (2)
src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java (1)
src/main/java/konkuk/thip/common/exception/EntityNotFoundException.java (1)
EntityNotFoundException(5-10)
src/main/java/konkuk/thip/room/application/service/RoomShowRecruitingDetailViewService.java (1)
src/main/java/konkuk/thip/common/util/DateUtil.java (1)
DateUtil(12-62)
🔇 Additional comments (6)
src/main/java/konkuk/thip/room/adapter/in/web/response/RoomPlayingDetailViewResponse.java (1)
17-17: categoryColor 필드 추가 LGTM — API 확장 변경은 역호환성 안전레코드 컴포넌트 추가가 빌더 사용과 함께 자연스럽게 반영됩니다. JSON 직렬화도 필드명 기반 매핑이므로 클라이언트는 무시 가능해 역호환성 문제 없습니다.
src/main/java/konkuk/thip/room/adapter/in/web/response/RoomGetMemberListResponse.java (1)
18-18: aliasColor 필드 추가 LGTM중첩 레코드에 @builder가 적용되어 있어 매핑 코드도 자연스럽게 확장됩니다. 클라이언트는 새 필드를 무시 가능하므로 역호환성도 안전합니다.
src/main/java/konkuk/thip/room/application/service/RoomGetMemberListService.java (1)
55-55: DTO 매핑에 aliasColor 추가 LGTM이미 imageUrl/value도 동일 경로에서 가져오고 있어 NPE 리스크는 기존과 동일 수준입니다. 배치 조회로 N+1도 회피되어 있습니다.
src/main/java/konkuk/thip/room/adapter/in/web/response/RoomRecruitingDetailViewResponse.java (1)
7-7: 빌더 패턴 적용과 새 필드 추가가 적절합니다
@Builder어노테이션 추가와categoryColor필드 추가가 잘 구현되었습니다. 빌더 패턴을 통해 응답 객체 생성이 더 명확해졌고, 카테고리 색상 정보를 제공하는 기능이 추가되었습니다.Also applies to: 19-19
src/main/java/konkuk/thip/room/application/service/RoomShowPlayingDetailViewService.java (1)
28-31: 생성자 파라미터 순서가 일관성 있게 구성되었습니다
RoomQueryPort가RoomCommandPort바로 다음에 위치하여 Room 관련 포트들이 함께 그룹화되었습니다. 이는 코드 가독성 향상에 도움이 됩니다.src/main/java/konkuk/thip/room/application/service/RoomShowRecruitingDetailViewService.java (1)
56-78: 빌더 패턴 전환이 적절하게 구현되었습니다기존 생성자 방식에서 빌더 패턴으로의 전환이 잘 이루어졌으며, 필드 명명이 더 명확해졌습니다.
| if (authorization != null && authorization.startsWith(JWT_PREFIX.getValue())) { | ||
| return authorization.split(" ")[1]; | ||
| } |
There was a problem hiding this comment.
Authorization 헤더 파싱 취약 — split 인덱싱으로 AIOOB 가능
"Bearer" 다음에 공백/토큰이 없거나 공백이 여러 개인 경우 ArrayIndexOutOfBoundsException 가능성이 있습니다. prefix 길이 기반으로 안전하게 파싱하세요.
적용 제안:
- return authorization.split(" ")[1];
+ return authorization.substring(JWT_PREFIX.getValue().length()).trim();📝 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.
| if (authorization != null && authorization.startsWith(JWT_PREFIX.getValue())) { | |
| return authorization.split(" ")[1]; | |
| } | |
| if (authorization != null && authorization.startsWith(JWT_PREFIX.getValue())) { | |
| return authorization.substring(JWT_PREFIX.getValue().length()).trim(); | |
| } |
🤖 Prompt for AI Agents
In src/main/java/konkuk/thip/common/security/filter/JwtAuthenticationFilter.java
around lines 74-76, the current authorization header parsing uses
authorization.split(" ")[1] which can throw ArrayIndexOutOfBoundsException when
the header has no token or extra spaces; instead compute the token by taking the
substring after the known prefix length (e.g.
authorization.substring(JWT_PREFIX.getValue().length())), trim the result, and
validate it is non-empty before returning (otherwise return null or handle as
unauthenticated); ensure you keep the startsWith check and avoid indexing into
split arrays.
| // 2. Cookie에서 JWT 추출 (웹) | ||
| if (request.getCookies() != null) { | ||
| for (Cookie cookie : request.getCookies()) { | ||
| if (JWT_HEADER_KEY.getValue().equals(cookie.getName())) { | ||
| return cookie.getValue(); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
쿠키에서 JWT 조회 시 키 상수 혼용 가능성 — 전용 쿠키 키 사용 검토 및 두 케이스 지원
현재 쿠키 이름 비교에 JWT_HEADER_KEY(통상 Authorization 헤더 키)를 재사용하고 있습니다. 일반적으로 쿠키 키는 헤더 키와 분리(JWT_COOKIE_KEY 등)하는 것이 명확합니다. 또한 쿠키 값에 "Bearer " 프리픽스가 포함될 가능성까지 대비해 제거 로직을 넣어두는 편이 안전합니다.
최소 보완(프리픽스 제거) 제안:
- if (JWT_HEADER_KEY.getValue().equals(cookie.getName())) {
- return cookie.getValue();
- }
+ if (JWT_HEADER_KEY.getValue().equals(cookie.getName())) {
+ String value = cookie.getValue();
+ return value.startsWith(JWT_PREFIX.getValue())
+ ? value.substring(JWT_PREFIX.getValue().length()).trim()
+ : value;
+ }추가 권장:
- 전용 쿠키 키 상수(JWT_COOKIE_KEY 등) 도입 후 해당 키 우선 조회, 레거시 호환을 위해 한시적으로 HEADER_KEY 이름도 병행 지원.
- SameSite, Secure, HttpOnly 설정은 토큰 발급/설정 시점에서 반드시 보장.
레포 내 전용 쿠키 키 상수 존재 여부와 사용 위치 확인 스크립트:
🏁 Script executed:
#!/bin/bash
# JWT 쿠키 관련 상수 및 사용처 탐색
rg -n "JWT_.*COOKIE" -S
rg -n "AuthParameters" -A 5 -B 3
# Authorization 헤더/쿠키 사용 패턴 확인
rg -n "JWT_HEADER_KEY"
# 쿠키 생성/추가 위치 탐색
rg -n 'new Cookie\(' -A 2
rg -n 'addCookie\(' -A 2Length of output: 10136
전용 JWT 쿠키 키 분리, Bearer 프리픽스 제거 및 보안 속성 추가 필요
현재 Authorization 헤더 키(JWT_HEADER_KEY)를 쿠키 이름으로도 재사용 중이며, 쿠키 값에 대한 Bearer 프리픽스 제거 로직과 HttpOnly/Secure/SameSite 설정이 빠져 있습니다. 아래 항목을 반영해 주세요.
• AuthParameters.java
– JWT_COOKIE_KEY 상수 추가
• JwtAuthenticationFilter.java
– 쿠키 조회 시 JWT_COOKIE_KEY 우선 조회, 레거시 호환을 위해 JWT_HEADER_KEY도 지원
– 쿠키 값에 JWT_PREFIX(“Bearer ”) 제거 로직 추가
• CustomSuccessHandler.java
– 쿠키 생성 시 JWT_COOKIE_KEY 사용
– HttpOnly, Secure, Path 설정 보장
– SameSite 설정 추가 (필요 시 Set-Cookie 헤더 직접 조작)
예시 변경안:
src/main/java/konkuk/thip/common/security/constant/AuthParameters.java
public enum AuthParameters {
JWT_HEADER_KEY("Authorization"),
JWT_PREFIX("Bearer "),
+ JWT_COOKIE_KEY("access_token"), // 원하는 쿠키 이름으로 변경
KAKAO("kakao"),
GOOGLE("google"),
KAKAO_PROVIDER_ID_KEY("id");
// …
}src/main/java/konkuk/thip/common/security/filter/JwtAuthenticationFilter.java
- if (JWT_HEADER_KEY.getValue().equals(cookie.getName())) {
- String value = cookie.getValue();
- return value.startsWith(JWT_PREFIX.getValue())
- ? value.substring(JWT_PREFIX.getValue().length()).trim()
- : value;
- }
+ if (JWT_COOKIE_KEY.getValue().equals(cookie.getName())
+ || JWT_HEADER_KEY.getValue().equals(cookie.getName())) {
+ String value = cookie.getValue();
+ return value.startsWith(JWT_PREFIX.getValue())
+ ? value.substring(JWT_PREFIX.getValue().length()).trim()
+ : value;
+ }src/main/java/konkuk/thip/common/security/oauth2/CustomSuccessHandler.java
- Cookie cookie = new Cookie(JWT_HEADER_KEY.getValue(), token);
+ Cookie cookie = new Cookie(JWT_COOKIE_KEY.getValue(), token);
+ cookie.setHttpOnly(true);
+ cookie.setSecure(true);
+ cookie.setPath("/");
+ // SameSite 설정이 필요할 경우 아래와 같이 직접 헤더를 조작
+ // response.setHeader("Set-Cookie",
+ // String.format("%s=%s; Path=/; Secure; HttpOnly; SameSite=Strict", cookie.getName(), cookie.getValue()));
response.addCookie(cookie);📝 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.
| // 2. Cookie에서 JWT 추출 (웹) | |
| if (request.getCookies() != null) { | |
| for (Cookie cookie : request.getCookies()) { | |
| if (JWT_HEADER_KEY.getValue().equals(cookie.getName())) { | |
| return cookie.getValue(); | |
| } | |
| } | |
| } | |
| // 2. Cookie에서 JWT 추출 (웹) | |
| if (request.getCookies() != null) { | |
| for (Cookie cookie : request.getCookies()) { | |
| - if (JWT_HEADER_KEY.getValue().equals(cookie.getName())) { | |
| - return cookie.getValue(); | |
| - } | |
| + if (JWT_COOKIE_KEY.getValue().equals(cookie.getName()) | |
| + || JWT_HEADER_KEY.getValue().equals(cookie.getName())) { | |
| + String value = cookie.getValue(); | |
| + return value.startsWith(JWT_PREFIX.getValue()) | |
| + ? value.substring(JWT_PREFIX.getValue().length()).trim() | |
| + : value; | |
| + } | |
| } | |
| } |
🤖 Prompt for AI Agents
In src/main/java/konkuk/thip/common/security/filter/JwtAuthenticationFilter.java
around lines 78-85, the code reuses JWT_HEADER_KEY as the cookie name and
doesn't strip a Bearer prefix or prefer a dedicated cookie key; add a new
constant JWT_COOKIE_KEY in AuthParameters, update the filter to first look for a
cookie named JWT_COOKIE_KEY (fall back to JWT_HEADER_KEY for legacy), strip the
JWT_PREFIX ("Bearer ") from the cookie value if present, and return the cleaned
token; also update CustomSuccessHandler to set the cookie using JWT_COOKIE_KEY
and ensure HttpOnly, Secure, Path are set and SameSite is applied (use direct
Set-Cookie header manipulation if your cookie API lacks SameSite support).
| .currentPage(roomParticipants.getCurrentPageOfUser(userId)) | ||
| .userPercentage(roomParticipants.getUserPercentageOfUser(userId)) | ||
| .currentVotes(topParticipationVotes) | ||
| .categoryColor(roomQueryPort.findAliasColorOfCategory(room.getCategory())) // TODO : 리펙토링 대상 |
There was a problem hiding this comment.
🛠️ Refactor suggestion
카테고리 색상 조회 위치 재검토 필요
현재 buildResponse 메서드 내에서 roomQueryPort.findAliasColorOfCategory()를 호출하고 있습니다. 이는 순수한 응답 빌딩 로직에 외부 포트 호출이 섞여 있어 단일 책임 원칙에 위배됩니다.
다음과 같이 서비스 메서드에서 미리 조회하는 것을 권장합니다:
@Override
@Transactional(readOnly = true)
public RoomPlayingDetailViewResponse getPlayingRoomDetailView(Long userId, Long roomId) {
// 1. Room 조회, Book 조회, Category와 연관된 Alias 조회
Room room = roomCommandPort.getByIdOrThrow(roomId);
Book book = bookCommandPort.findById(room.getBookId());
+ String categoryColor = roomQueryPort.findAliasColorOfCategory(room.getCategory());
// 2. Room과 연관된 UserRoom 조회, RoomParticipants 일급 컬렉션 생성
// TODO. Room 도메인에 memberCount 값 추가된 후 리펙토링
List<RoomParticipant> findByRoomId = roomParticipantCommandPort.findAllByRoomId(roomId);
RoomParticipants roomParticipants = RoomParticipants.from(findByRoomId);
// 3. 투표 참여율이 가장 높은 투표 조회
List<RoomPlayingDetailViewResponse.CurrentVote> topParticipationVotes = voteQueryPort.findTopParticipationVotesByRoom(room, TOP_PARTICIPATION_VOTES_COUNT);
// 4. response 구성
- return buildResponse(userId, room, book, roomParticipants, topParticipationVotes);
+ return buildResponse(userId, room, book, roomParticipants, topParticipationVotes, categoryColor);
}
-private RoomPlayingDetailViewResponse buildResponse(Long userId, Room room, Book book, RoomParticipants roomParticipants, List<RoomPlayingDetailViewResponse.CurrentVote> topParticipationVotes) {
+private RoomPlayingDetailViewResponse buildResponse(Long userId, Room room, Book book, RoomParticipants roomParticipants, List<RoomPlayingDetailViewResponse.CurrentVote> topParticipationVotes, String categoryColor) {
return RoomPlayingDetailViewResponse.builder()
// ... 기존 필드들 ...
- .categoryColor(roomQueryPort.findAliasColorOfCategory(room.getCategory())) // TODO : 리펙토링 대상
+ .categoryColor(categoryColor)
.build();
}📝 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.
| .categoryColor(roomQueryPort.findAliasColorOfCategory(room.getCategory())) // TODO : 리펙토링 대상 | |
| @Override | |
| @Transactional(readOnly = true) | |
| public RoomPlayingDetailViewResponse getPlayingRoomDetailView(Long userId, Long roomId) { | |
| // 1. Room 조회, Book 조회, Category와 연관된 Alias 조회 | |
| Room room = roomCommandPort.getByIdOrThrow(roomId); | |
| Book book = bookCommandPort.findById(room.getBookId()); | |
| + String categoryColor = roomQueryPort.findAliasColorOfCategory(room.getCategory()); | |
| // 2. Room과 연관된 UserRoom 조회, RoomParticipants 일급 컬렉션 생성 | |
| List<RoomParticipant> findByRoomId = roomParticipantCommandPort.findAllByRoomId(roomId); | |
| RoomParticipants roomParticipants = RoomParticipants.from(findByRoomId); | |
| // 3. 투표 참여율이 가장 높은 투표 조회 | |
| List<RoomPlayingDetailViewResponse.CurrentVote> topParticipationVotes = | |
| voteQueryPort.findTopParticipationVotesByRoom(room, TOP_PARTICIPATION_VOTES_COUNT); | |
| // 4. response 구성 | |
| - return buildResponse(userId, room, book, roomParticipants, topParticipationVotes); | |
| + return buildResponse(userId, room, book, roomParticipants, topParticipationVotes, categoryColor); | |
| } | |
| -private RoomPlayingDetailViewResponse buildResponse( | |
| - Long userId, | |
| - Room room, | |
| - Book book, | |
| - RoomParticipants roomParticipants, | |
| - List<RoomPlayingDetailViewResponse.CurrentVote> topParticipationVotes | |
| -) { | |
| +private RoomPlayingDetailViewResponse buildResponse( | |
| + Long userId, | |
| + Room room, | |
| + Book book, | |
| + RoomParticipants roomParticipants, | |
| + List<RoomPlayingDetailViewResponse.CurrentVote> topParticipationVotes, | |
| + String categoryColor | |
| +) { | |
| return RoomPlayingDetailViewResponse.builder() | |
| // ... 기존 필드들 ... | |
| - .categoryColor(roomQueryPort.findAliasColorOfCategory(room.getCategory())) // TODO : 리펙토링 대상 | |
| + .categoryColor(categoryColor) | |
| .build(); | |
| } |
🤖 Prompt for AI Agents
In
src/main/java/konkuk/thip/room/application/service/RoomShowPlayingDetailViewService.java
around line 71, the buildResponse method currently calls
roomQueryPort.findAliasColorOfCategory(...) which mixes an external port call
into response-building; move that lookup into the service method before calling
buildResponse: call roomQueryPort.findAliasColorOfCategory(room.getCategory())
once in the service, pass the resulting categoryColor as an additional argument
into buildResponse (or into the DTO constructor), and remove the port call from
buildResponse so the builder only composes data it is given; update any method
signatures and call sites accordingly.
| .progressEndDate(DateUtil.formatDate(room.getEndDate())) | ||
| .recruitEndDate(DateUtil.formatAfterTime(room.getStartDate())) | ||
| .category(room.getCategory().getValue()) | ||
| .categoryColor(roomQueryPort.findAliasColorOfCategory(room.getCategory())) // TODO : 리펙토링 대상 |
There was a problem hiding this comment.
🛠️ Refactor suggestion
카테고리 색상 조회 위치 개선 필요
RoomShowPlayingDetailViewService와 동일한 문제가 있습니다. buildResponse 메서드는 순수한 응답 빌딩 로직만 담당해야 합니다.
서비스 메서드에서 미리 조회하도록 수정하세요:
@Override
@Transactional(readOnly = true)
public RoomRecruitingDetailViewResponse getRecruitingRoomDetailView(Long userId, Long roomId) {
// 1. Room 조회, Book 조회
Room room = roomCommandPort.getByIdOrThrow(roomId);
Book book = bookCommandPort.findById(room.getBookId());
+ String categoryColor = roomQueryPort.findAliasColorOfCategory(room.getCategory());
// 2. Room과 연관된 UserRoom 조회, RoomParticipants 일급 컬렉션 생성
List<RoomParticipant> findByRoomId = roomParticipantCommandPort.findAllByRoomId(roomId);
RoomParticipants roomParticipants = RoomParticipants.from(findByRoomId);
// 3. 다른 모임방 추천
List<RoomRecruitingDetailViewResponse.RecommendRoom> recommendRooms = roomQueryPort.findOtherRecruitingRoomsByCategoryOrderByStartDateAsc(room, RECOMMEND_ROOM_COUNT);
// 4. response 구성
- return buildResponse(userId, room, book, roomParticipants, recommendRooms);
+ return buildResponse(userId, room, book, roomParticipants, recommendRooms, categoryColor);
}
private RoomRecruitingDetailViewResponse buildResponse(
Long userId,
Room room,
Book book,
RoomParticipants participants,
- List<RoomRecruitingDetailViewResponse.RecommendRoom> recommendRooms
+ List<RoomRecruitingDetailViewResponse.RecommendRoom> recommendRooms,
+ String categoryColor
) {
return RoomRecruitingDetailViewResponse.builder()
// ... 기존 필드들 ...
- .categoryColor(roomQueryPort.findAliasColorOfCategory(room.getCategory())) // TODO : 리펙토링 대상
+ .categoryColor(categoryColor)
// ... 나머지 필드들 ...
.build();
}📝 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.
| .categoryColor(roomQueryPort.findAliasColorOfCategory(room.getCategory())) // TODO : 리펙토링 대상 | |
| @Override | |
| @Transactional(readOnly = true) | |
| public RoomRecruitingDetailViewResponse getRecruitingRoomDetailView(Long userId, Long roomId) { | |
| // 1. Room 조회, Book 조회 | |
| Room room = roomCommandPort.getByIdOrThrow(roomId); | |
| Book book = bookCommandPort.findById(room.getBookId()); | |
| String categoryColor = roomQueryPort.findAliasColorOfCategory(room.getCategory()); | |
| // 2. Room과 연관된 UserRoom 조회, RoomParticipants 일급 컬렉션 생성 | |
| List<RoomParticipant> findByRoomId = roomParticipantCommandPort.findAllByRoomId(roomId); | |
| RoomParticipants roomParticipants = RoomParticipants.from(findByRoomId); | |
| // 3. 다른 모임방 추천 | |
| List<RoomRecruitingDetailViewResponse.RecommendRoom> recommendRooms = | |
| roomQueryPort.findOtherRecruitingRoomsByCategoryOrderByStartDateAsc(room, RECOMMEND_ROOM_COUNT); | |
| // 4. response 구성 | |
| return buildResponse(userId, room, book, roomParticipants, recommendRooms, categoryColor); | |
| } | |
| private RoomRecruitingDetailViewResponse buildResponse( | |
| Long userId, | |
| Room room, | |
| Book book, | |
| RoomParticipants participants, | |
| List<RoomRecruitingDetailViewResponse.RecommendRoom> recommendRooms, | |
| String categoryColor | |
| ) { | |
| return RoomRecruitingDetailViewResponse.builder() | |
| // ... 기존 필드들 ... | |
| .categoryColor(categoryColor) | |
| // ... 나머지 필드들 ... | |
| .build(); | |
| } |
🤖 Prompt for AI Agents
In
src/main/java/konkuk/thip/room/application/service/RoomShowRecruitingDetailViewService.java
around line 67, the buildResponse currently calls
roomQueryPort.findAliasColorOfCategory(...) which mixes data fetching into
presentation building; move the category color lookup into the service method
before calling buildResponse, store the result in a local variable, and pass
that color into buildResponse (or into the DTO/builder) so buildResponse remains
pure presentation logic; also apply the same change pattern to
RoomShowPlayingDetailViewService to keep consistency.
#️⃣ 연관된 이슈
📝 작업 내용
response에 alias color, category color 추가된 hotfix pr을 운영서버로 배포합니다
📸 스크린샷
💬 리뷰 요구사항
📌 PR 진행 시 이러한 점들을 참고해 주세요
Summary by CodeRabbit