Skip to content

[hotfix] alias color 빠진 api 1개 수정 + category color 값을 반환해야하는 요구사항에 따라 코드 수정#214

Merged
seongjunnoh merged 4 commits intodevelopfrom
hotfix/#210-alias-color-and-category-color-add
Aug 13, 2025
Merged

[hotfix] alias color 빠진 api 1개 수정 + category color 값을 반환해야하는 요구사항에 따라 코드 수정#214
seongjunnoh merged 4 commits intodevelopfrom
hotfix/#210-alias-color-and-category-color-add

Conversation

@seongjunnoh
Copy link
Collaborator

@seongjunnoh seongjunnoh commented Aug 13, 2025

#️⃣ 연관된 이슈

closes #210

📝 작업 내용

  • response 에 alias color 를 빼먹은 api 1개에 alias color 값 추가
  • 모집중/진행중인 방 상세보기 api의 response 에 category의 color 값을 추가해야하는 요구사항이 발견되어, response 수정

@hd0rable @buzz0331 현재 Alias, Category 는 도메인이 아니라, 각각 User, Room에 속하는 Value 로 분류된 상황인데, 모집중/진행중인 방 상세보기 api의 response 에 category에 해당하는 color 값을 반환해야하는 요구사항이 생김으로써

  1. Room 도메인 내부의 Category를 영속성 adapter 로 던지기
  2. CategoryJpaRepository 내부에서 Category.value 로 이와 매핑되는 CategoryJpaEntity 를 찾아서
  3. 이와 연관되는 AliasJpaEntity 의 color 값을 반환

하도록 구현하였습니다.

현재 도메인 레벨에서는 [Alias, Category 의 연관관계를 고려 X, 그리고 각각을 엔티티가 아니라 Value로 분류] 하지만,
JPA 레벨에서는 [Alias, Category를 각각 엔티티로 분류, 서로 연관관계 존재] 하는 상황이라서 일단 임시 방편으로 요구사항을 만족하기 위해 위 방식으로 수정하였습니다

추후에 JPA 엔티티 및 DB 테이블 구조를 수정하여 Alias, Category를 DB 테이블에서 탈락시킨다고 해도, category의 color 값을 반환해야하는 요구사항으로 인해

  • Category enum의 내부에 color 값 추가 or
  • Alias 와 Category의 연관관계에 대한 enum 클래스를 정의 or
  • 또다른???

위와 같은 방법을 고려해야 할 것 같습니다!! 일단 hotfix이니 바로 머지하고 노션에 위 내용 추가해놓겠습니다!

📸 스크린샷

💬 리뷰 요구사항

📌 PR 진행 시 이러한 점들을 참고해 주세요

* P1 : 꼭 반영해 주세요 (Request Changes) - 이슈가 발생하거나 취약점이 발견되는 케이스 등
* P2 : 반영을 적극적으로 고려해 주시면 좋을 것 같아요 (Comment)
* P3 : 이런 방법도 있을 것 같아요~ 등의 사소한 의견입니다 (Chore)

@coderabbitai
Copy link

coderabbitai bot commented Aug 13, 2025

Walkthrough

응답 DTO에 aliasColor/categoryColor 필드를 추가하고, 서비스 계층에서 해당 값을 채우도록 매핑을 확장했다. 카테고리의 별칭 색상을 조회하기 위해 포트/어댑터/레포지토리에 쿼리 메서드를 추가했다. 한 DTO는 빌더(@builder)로 전환되었고, 관련 서비스는 빌더 사용으로 변경되었다.

Changes

Cohort / File(s) Summary
Response DTO 확장
src/main/java/.../response/RoomGetMemberListResponse.java, src/main/java/.../response/RoomPlayingDetailViewResponse.java, src/main/java/.../response/RoomRecruitingDetailViewResponse.java
MemberSearchResult에 aliasColor(String) 추가, Playing/Recruiting 상세 응답에 categoryColor(String) 추가, Recruiting DTO에 @builder 도입
서비스 매핑 수정
src/main/java/.../service/RoomGetMemberListService.java, src/main/java/.../service/RoomShowPlayingDetailViewService.java, src/main/java/.../service/RoomShowRecruitingDetailViewService.java
사용자 별칭 색상과 카테고리 색상 매핑 추가, Recruiting 상세는 빌더 기반 생성으로 변경
포트/어댑터/레포지토리 추가
src/main/java/.../port/out/RoomQueryPort.java, src/main/java/.../persistence/RoomQueryPersistenceAdapter.java, src/main/java/.../repository/category/CategoryJpaRepository.java
RoomQueryPort에 findAliasColorOfCategory 추가, 어댑터 구현 추가, CategoryJpaRepository에 findAliasColorByValue 및 findByValue 추가

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant RoomShowPlayingDetailViewService as Service(Playing)
  participant RoomQueryPort as RoomQueryPort
  participant RoomQueryPersistenceAdapter as Adapter
  participant CategoryJpaRepository as CategoryRepo

  Client->>Service(Playing): getPlayingRoomDetailView(roomId, userId)
  Service(Playing)->>RoomQueryPort: findAliasColorOfCategory(room.category)
  RoomQueryPort->>Adapter: findAliasColorOfCategory(category)
  Adapter->>CategoryRepo: findAliasColorByValue(category.value)
  CategoryRepo-->>Adapter: aliasColor
  Adapter-->>RoomQueryPort: aliasColor
  RoomQueryPort-->>Service(Playing): aliasColor
  Service(Playing)-->>Client: RoomPlayingDetailViewResponse(..., categoryColor)
Loading
sequenceDiagram
  participant Client
  participant RoomShowRecruitingDetailViewService as Service(Recruiting)
  participant RoomQueryPort as RoomQueryPort
  participant RoomQueryPersistenceAdapter as Adapter
  participant CategoryJpaRepository as CategoryRepo

  Client->>Service(Recruiting): getRecruitingRoomDetailView(roomId, userId)
  Service(Recruiting)->>RoomQueryPort: findAliasColorOfCategory(room.category)
  RoomQueryPort->>Adapter: findAliasColorOfCategory(category)
  Adapter->>CategoryRepo: findAliasColorByValue(category.value)
  CategoryRepo-->>Adapter: aliasColor
  Adapter-->>RoomQueryPort: aliasColor
  RoomQueryPort-->>Service(Recruiting): aliasColor
  Service(Recruiting)-->>Client: RoomRecruitingDetailViewResponse.builder().categoryColor(...).build()
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
aliasColor 누락된 부분 보완 (#210)
category color 도입 및 제공 (#210)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
findByValue 추가 (src/main/java/.../repository/category/CategoryJpaRepository.java) 카테고리 색상 조회와 직접적 연계가 명확하지 않으며 본 변경 범위 내 사용 여부가 불분명함. 관련 필요성 확인이 필요.

Possibly related PRs

Suggested labels

🔥 hotfix, 👻 성준

Suggested reviewers

  • hd0rable
  • buzz0331

Poem

당근 붓으로 색을 칠해, 카테고리엔 빛을 더해!
별칭에도 색이 들어, 토끼 마음 두근두근.
빌더로 집 짓듯 차곡차곡,
응답은 반짝 컬러풀—깡총!
오늘도 코드는 무지개처럼 쏟아진다. 🥕🌈

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch hotfix/#210-alias-color-and-category-color-add

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link

Test Results

383 tests   383 ✅  31s ⏱️
113 suites    0 💤
113 files      0 ❌

Results for commit a5ead8a.

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: 2

🧹 Nitpick comments (9)
src/main/java/konkuk/thip/room/adapter/in/web/response/RoomRecruitingDetailViewResponse.java (1)

19-19: categoryColor 추가 OK. API 문서에 색상 포맷 명세(@Schema) 주석 추가 제안

FE와의 계약을 명확히 하기 위해 색상 포맷(예: #RRGGBB)을 스키마에 명시해두는 것을 권장합니다.

아래와 같이 컴포넌트에 애너테이션을 부여하세요:

-        String categoryColor,
+        @Schema(description = "카테고리 별칭 색상 코드(예: #RRGGBB)")
+        String categoryColor,

추가로 파일 상단에 import가 필요합니다(선택 적용):

// 파일 상단 import 섹션에 추가
import io.swagger.v3.oas.annotations.media.Schema;
src/main/java/konkuk/thip/room/adapter/in/web/response/RoomPlayingDetailViewResponse.java (1)

17-17: categoryColor 필드 추가 적절. 중복 매핑 로직의 공통화와 API 문서 주석 제안

  • Recruiting/Playing 상세 모두에서 categoryColor를 채우는 로직이 생겼습니다. 서비스/매퍼 레벨에서 공통 함수로 추출하면 중복 제거와 유지보수성이 좋아집니다(예: Room -> categoryColor 매핑 유틸).
  • 스키마에 색상 포맷을 명시하는 주석을 추가하는 것을 권장합니다.

스키마 주석 예:

-        String categoryColor,
+        @Schema(description = "카테고리 별칭 색상 코드(예: #RRGGBB)")
+        String categoryColor,

필요 시 import:

import io.swagger.v3.oas.annotations.media.Schema;
src/main/java/konkuk/thip/room/adapter/in/web/response/RoomGetMemberListResponse.java (1)

18-19: aliasColor 필드 추가 적합. null 가능성과 문서화에 대한 간단한 가이드

  • User.alias가 비어있는 경우를 고려해 null이 반환될 수 있음을 FE에 명확히 하거나, 서버에서 기본값을 정해주는 정책 합의가 필요합니다.
  • API 스키마에 색상 포맷을 명시해 주세요.

스키마 주석 예:

-                String aliasColor,
+                @Schema(description = "사용자 별칭(닉네임 테마) 색상 코드(예: #RRGGBB)")
+                String aliasColor,

필요 시 import:

import io.swagger.v3.oas.annotations.media.Schema;
src/main/java/konkuk/thip/room/application/port/out/RoomQueryPort.java (1)

41-45: 포트 메서드 네이밍/소속/반환 타입 개선(후속 리팩토링 제안)

  • RoomQueryPort에 Category 관련 조회가 새로 추가되었는데, 개념적으로는 CategoryQueryPort가 더 적합합니다. hotfix 이후 포트 분리/이동을 고려해 주세요.
  • String보다는 ColorCode 같은 값 객체를 반환하는 편이 유효성(형식 검증, 표준화)과 변경 내성에 유리합니다.
  • 메서드명도 동작을 드러내도록 getCategoryAliasColorOrThrow(Category category) 등으로 구체화하면 의도가 명확해집니다.
  • 성능: 상세 보기 호출마다 별도 쿼리를 타는 구조라면, 카테고리 값->색상 매핑을 Caffeine 등으로 캐싱(TTL/사이즈 제한)하거나, 원본 Room 조회 시 조인으로 함께 가져오도록 쿼리를 확장하면 RTT를 줄일 수 있습니다.

원하시면 캐시 도입(Caffeine)을 위한 설정/코드 스니펫과, 포트/어댑터 계층 분리 계획안을 정리해 드리겠습니다.

src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java (1)

108-115: 메서드 계약/네이밍 및 캐싱 고려 — ‘find’가 예외를 던지는 계약과 어울리지 않습니다.

  • 현재 ‘findAliasColorOfCategory’가 값을 못 찾으면 예외를 던집니다. ‘find’ 대신 ‘get...OrThrow’로 바꾸거나 Optional을 반환하는 쪽이 계약상 더 명확합니다.
  • 동일 카테고리 값에 대한 반복 조회가 잦을 수 있으니, 간단한 캐싱을 붙이면 DB 부하와 레이턴시를 줄일 수 있습니다.

아래처럼 캐시를 붙이는 소규모 변경을 제안드립니다(캐싱 미활성화 시에도 무해합니다).

@@
-    @Override
-    public String findAliasColorOfCategory(Category category) {
-        return categoryJpaRepository.findAliasColorByValue(category.getValue()).orElseThrow(
-                () -> new EntityNotFoundException(ErrorCode.CATEGORY_NOT_FOUND)
-        );
-    }
+    @Override
+    @org.springframework.cache.annotation.Cacheable(cacheNames = "categoryAliasColorByValue", key = "#category.value")
+    public String findAliasColorOfCategory(Category category) {
+        return categoryJpaRepository.findAliasColorByValue(category.getValue())
+                .orElseThrow(() -> new EntityNotFoundException(ErrorCode.CATEGORY_NOT_FOUND));
+    }

추가로, 예외 코드가 "카테고리 자체 없음"과 "별칭 색상 매핑 없음"을 동일하게 다루고 있습니다. 분리된 에러 코드(e.g., CATEGORY_ALIAS_COLOR_NOT_FOUND)를 두면 운영 관찰성이 좋아집니다.

src/main/java/konkuk/thip/room/application/service/RoomShowPlayingDetailViewService.java (1)

71-71: 빌더 내 동기 쿼리 호출 분리 권장 — 가독성과 예외 처리 지점 명확화.
빌더 체인 안에서 쿼리 메서드를 직접 호출하면 예외 처리/로깅이 어려워집니다. 값을 미리 조회해 지역 변수로 전달하세요.

@@ public class RoomShowPlayingDetailViewService implements RoomShowPlayingDetailViewUseCase {
-        return RoomPlayingDetailViewResponse.builder()
+        final String categoryColor = roomQueryPort.findAliasColorOfCategory(room.getCategory()); // TODO : 리팩토링 대상
+        return RoomPlayingDetailViewResponse.builder()
@@
-                .categoryColor(roomQueryPort.findAliasColorOfCategory(room.getCategory()))      // TODO : 리펙토링 대상
+                .categoryColor(categoryColor)
                 .build();

참고: 색상 누락 상황에서 예외가 치명적이라면, 여기에서 안전한 기본값(예: "#000000")으로 폴백하는 정책도 검토해 주세요.

src/main/java/konkuk/thip/room/adapter/out/persistence/repository/category/CategoryJpaRepository.java (2)

12-12: 도메인 키 기반 탐색 메서드 추가 적절
Category.value는 조회의 주키로 자주 쓰일 가능성이 높습니다. 파생 쿼리 도입은 타당합니다. value 컬럼에 유니크 인덱스가 없다면 추가를 권장합니다.


15-18: JPQL 시그니처/네이밍 정교화 제안 + 인덱스 고려

  • 메서드명과 파라미터명을 더 구체적으로 맞추면 검색/사용 맥락이 분명해집니다.
  • where 절에서 c.value를 필터로 사용하므로 DB에 인덱스가 없으면 색상 조회에 불필요한 풀스캔이 발생할 수 있습니다.

다음과 같이 시그니처를 명확화하는 것을 고려해 주세요(연쇄 수정 필요).

-    @Query("select a.color " +
-            "from CategoryJpaEntity c join c.aliasForCategoryJpaEntity a " +
-            "where c.value = :categoryValue")
-    Optional<String> findAliasColorByValue(@Param("categoryValue") String categoryValue);
+    @Query("select a.color " +
+            "from CategoryJpaEntity c join c.aliasForCategoryJpaEntity a " +
+            "where c.value = :value")
+    Optional<String> findAliasColorByCategoryValue(@Param("value") String value);

운영 DB에서 Category.value 컬럼에 인덱스/유니크 제약이 없다면 추가를 권장합니다. 카디널리티가 높을수록 색상 조회의 P95/P99 레이턴시에 유의미한 개선이 있습니다.

src/main/java/konkuk/thip/room/application/service/RoomShowRecruitingDetailViewService.java (1)

65-65: 모집 마감 안내 포맷 재검토 — DateUtil.formatAfterTime의 음수/0인 경우 "??" 노출 위험
현재 구현은 시작일이 지났을 때 "??"가 반환됩니다. 실제 사용자 화면에는 "마감됨" 등의 안내가 적절합니다. 서비스 레벨에서 폴백하거나, DateUtil 자체를 개선하는 것이 좋아 보입니다.

원하시면 DateUtil에 "formatAfterTimeOrClosed" 형태의 안전한 API를 추가하는 수정안도 제안드릴 수 있습니다.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 19b06e0 and a5ead8a.

📒 Files selected for processing (9)
  • 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 (3)
src/main/java/konkuk/thip/room/adapter/in/web/response/RoomRecruitingDetailViewResponse.java (1)

7-7: 직접 생성자 호출 잔존 여부 확인 완료
직접 생성자 호출(new RoomRecruitingDetailViewResponse(…), new RoomPlayingDetailViewResponse(…))는 더 이상 존재하지 않으며, 모든 사용처가 @builder로 마이그레이션된 것을 확인했습니다.

src/main/java/konkuk/thip/room/application/service/RoomGetMemberListService.java (1)

55-55: NPE 방어 및 중복 접근 제거 제안

RoomGetMemberListService.java (약 55행 부근)에서 user.getAlias()에 여러 번 접근하고 있어, user 또는 alias가 null일 경우 NPE가 발생할 수 있습니다. 임시 변수로 뽑아 두고 null-safe 하게 매핑하거나, 도메인에서 alias가 항상 존재함을 명시적으로 보장해주세요.

– 위치

  • 파일: src/main/java/konkuk/thip/room/application/service/RoomGetMemberListService.java
  • 범위: roomParticipants.stream().map(…) 내부 빌더 호출 부분

– 최소 변경 예시

-    return RoomGetMemberListResponse.MemberSearchResult.builder()
-            .userId(userId)
-            .nickname(user.getNickname())
-            .imageUrl(user.getAlias().getImageUrl())
-            .aliasName(user.getAlias().getValue())
-            .aliasColor(user.getAlias().getColor())
-            .followerCount(user.getFollowerCount())
-            .build();
+    final var alias = user.getAlias();
+    return RoomGetMemberListResponse.MemberSearchResult.builder()
+            .userId(userId)
+            .nickname(user.getNickname())
+            .imageUrl(alias != null ? alias.getImageUrl() : null)
+            .aliasName(alias != null ? alias.getValue()    : null)
+            .aliasColor(alias != null ? alias.getColor()    : null)
+            .followerCount(user.getFollowerCount())
+            .build();

– 도메인 불변이 보장된다면 아래처럼 의도를 명시할 수도 있습니다.

Objects.requireNonNull(user,                    "user must not be null. userId=" + userId);
Objects.requireNonNull(user.getAlias(),         "alias must not be null. userId=" + userId);

alias가 null이 될 수 있는지 도메인 제약을 확인한 뒤 위 중 적절한 방어 로직 또는 requireNonNull을 적용해주세요.

src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java (1)

3-4: 예외 매핑 추가 적절 — NotFound를 명시적으로 표현한 점 좋습니다.
CATEGORY_NOT_FOUND로 명확히 매핑되어 있어 장애 시 원인 파악이 용이합니다.

public class RoomQueryPersistenceAdapter implements RoomQueryPort {

private final RoomJpaRepository roomJpaRepository;
private final CategoryJpaRepository categoryJpaRepository;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

CategoryJpaRepository 의존 추가는 타당하지만, 쿼리 경로 최적화를 고려해 주세요.
현재 서비스 레이어에서 카테고리 색상 조회가 개별 DB 왕복을 유발합니다. Room 관련 조회(projection/DTO)에 categoryColor를 조인해 한 번에 가져오도록 리포지토리 쿼리를 확장하면, 상세 화면 1회 호출당 추가 쿼리 1회 비용을 제거할 수 있습니다.

원하시면 RoomJpaRepository에 카테고리 색상 조인을 포함한 전용 프로젝션(예: RoomDetailProjection{..., categoryColor})을 추가하는 패치를 제안드릴게요.

🤖 Prompt for AI Agents
In
src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java
around line 30, adding CategoryJpaRepository is acceptable but causes per-room
DB roundtrips for category color; instead extend RoomJpaRepository to return a
projection/DTO that includes categoryColor (e.g., RoomDetailProjection { ...,
String categoryColor }), implement a repository query (JPQL/@Query or join
fetch) that joins Room -> Category and selects the category color into that
projection, update the adapter/service to use this new projection for room
detail queries and remove the per-room CategoryJpaRepository lookups so the
color is retrieved in a single DB call.

Comment on lines +56 to +78
return RoomRecruitingDetailViewResponse.builder()
.isHost(participants.isHostOfRoom(userId))
.isJoining(participants.isJoiningToRoom(userId))
.roomId(room.getId())
.roomName(room.getTitle())
.roomImageUrl(room.getCategory().getImageUrl())
.isPublic(room.isPublic())
.progressStartDate(DateUtil.formatDate(room.getStartDate()))
.progressEndDate(DateUtil.formatDate(room.getEndDate()))
.recruitEndDate(DateUtil.formatAfterTime(room.getStartDate()))
.category(room.getCategory().getValue())
.categoryColor(roomQueryPort.findAliasColorOfCategory(room.getCategory())) // TODO : 리펙토링 대상
.roomDescription(room.getDescription())
.memberCount(participants.calculateMemberCount())
.recruitCount(room.getRecruitCount())
.isbn(book.getIsbn())
.bookImageUrl(book.getImageUrl())
.bookTitle(book.getTitle())
.authorName(book.getAuthorName())
.bookDescription(book.getDescription())
.publisher(book.getPublisher())
.recommendRooms(recommendRooms)
.build();
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Builder 전 데이터 조회 분리 및 중복 제거 — 두 서비스에서 동일 패턴 반복

  • Playing/Recruiting 상세 모두에서 categoryColor 조회가 동일하게 반복됩니다. 지역 변수로 분리하고, 공통 유틸/컴포넌트로 추출하면 재사용성과 테스트 용이성이 좋아집니다.

간단한 로컬 정리 예시:

@@
-        return RoomRecruitingDetailViewResponse.builder()
+        final String categoryColor = roomQueryPort.findAliasColorOfCategory(room.getCategory()); // TODO : 리펙토링 대상
+        return RoomRecruitingDetailViewResponse.builder()
@@
-                .categoryColor(roomQueryPort.findAliasColorOfCategory(room.getCategory()))      // TODO : 리펙토링 대상
+                .categoryColor(categoryColor)
                 .roomDescription(room.getDescription())

더 나아가 CategoryColorProvider 컴포넌트를 도입해(인터페이스 + 기본 구현) 두 서비스에서 주입받아 사용하면, 추후 캐싱/폴백 정책을 한 곳에서 관리할 수 있습니다. 원하시면 해당 컴포넌트 초안까지 만들어 드리겠습니다.

📝 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.

Suggested change
return RoomRecruitingDetailViewResponse.builder()
.isHost(participants.isHostOfRoom(userId))
.isJoining(participants.isJoiningToRoom(userId))
.roomId(room.getId())
.roomName(room.getTitle())
.roomImageUrl(room.getCategory().getImageUrl())
.isPublic(room.isPublic())
.progressStartDate(DateUtil.formatDate(room.getStartDate()))
.progressEndDate(DateUtil.formatDate(room.getEndDate()))
.recruitEndDate(DateUtil.formatAfterTime(room.getStartDate()))
.category(room.getCategory().getValue())
.categoryColor(roomQueryPort.findAliasColorOfCategory(room.getCategory())) // TODO : 리펙토링 대상
.roomDescription(room.getDescription())
.memberCount(participants.calculateMemberCount())
.recruitCount(room.getRecruitCount())
.isbn(book.getIsbn())
.bookImageUrl(book.getImageUrl())
.bookTitle(book.getTitle())
.authorName(book.getAuthorName())
.bookDescription(book.getDescription())
.publisher(book.getPublisher())
.recommendRooms(recommendRooms)
.build();
// Extract categoryColor once to remove duplication and improve testability
final String categoryColor = roomQueryPort.findAliasColorOfCategory(room.getCategory()); // TODO : 리펙토링 대상
return RoomRecruitingDetailViewResponse.builder()
.isHost(participants.isHostOfRoom(userId))
.isJoining(participants.isJoiningToRoom(userId))
.roomId(room.getId())
.roomName(room.getTitle())
.roomImageUrl(room.getCategory().getImageUrl())
.isPublic(room.isPublic())
.progressStartDate(DateUtil.formatDate(room.getStartDate()))
.progressEndDate(DateUtil.formatDate(room.getEndDate()))
.recruitEndDate(DateUtil.formatAfterTime(room.getStartDate()))
.category(room.getCategory().getValue())
.categoryColor(categoryColor) // TODO : 리펙토링 대상
.roomDescription(room.getDescription())
.memberCount(participants.calculateMemberCount())
.recruitCount(room.getRecruitCount())
.isbn(book.getIsbn())
.bookImageUrl(book.getImageUrl())
.bookTitle(book.getTitle())
.authorName(book.getAuthorName())
.bookDescription(book.getDescription())
.publisher(book.getPublisher())
.recommendRooms(recommendRooms)
.build();
🤖 Prompt for AI Agents
In
src/main/java/konkuk/thip/room/application/service/RoomShowRecruitingDetailViewService.java
around lines 56 to 78, the categoryColor is being looked up inline in the
builder causing duplicated lookup logic across services; extract the category
color lookup into a local variable (e.g., String categoryColor =
roomQueryPort.findAliasColorOfCategory(room.getCategory())) and use that
variable in the builder, and then refactor by introducing a
CategoryColorProvider interface with a default implementation (or a simple
utility) that encapsulates roomQueryPort.findAliasColorOfCategory(...) so this
service and the similar Playing/Recruiting detail service can accept the
provider via constructor injection and call
provider.getCategoryColor(room.getCategory()), centralizing the logic for easier
reuse, testing, caching and future fallback handling.

@seongjunnoh seongjunnoh merged commit 2a19181 into develop Aug 13, 2025
4 checks passed
@seongjunnoh seongjunnoh deleted the hotfix/#210-alias-color-and-category-color-add branch August 13, 2025 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[THIP2025-257] [hotfix] aliasColor 빠진 곳 수정 + category color 의 등장

1 participant