Skip to content

[chore] 운영서버로 배포 25/08/13#215

Merged
seongjunnoh merged 7 commits intomainfrom
develop
Aug 13, 2025
Merged

[chore] 운영서버로 배포 25/08/13#215
seongjunnoh merged 7 commits intomainfrom
develop

Conversation

@seongjunnoh
Copy link
Collaborator

@seongjunnoh seongjunnoh commented Aug 13, 2025

#️⃣ 연관된 이슈

closes #이슈번호

📝 작업 내용

response에 alias color, category color 추가된 hotfix pr을 운영서버로 배포합니다

📸 스크린샷

💬 리뷰 요구사항

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

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

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

Summary by CodeRabbit

  • New Features
    • 멤버 목록 응답에 별칭 색상(aliasColor) 추가로 프로필 표시가 풍부해졌습니다.
    • 진행/모집 방 상세에 카테고리 색상(categoryColor) 제공으로 화면 가독성과 구분성이 개선되었습니다.
    • 인증 안정성 향상: Authorization 헤더가 없을 때도 쿠키에 저장된 JWT를 인식해 로그인 상태 유지가 더 견고해졌습니다.

@coderabbitai
Copy link

coderabbitai bot commented Aug 13, 2025

Walkthrough

JWT 인증 필터에 쿠키 기반 토큰 조회가 추가되었고, 방 관련 응답 DTO들에 aliasColor/categoryColor 필드가 확장되었습니다. 카테고리 색상 조회를 위해 Port/Adapter/Repository 계층에 메서드가 추가되었으며, 관련 서비스들이 신규 필드를 매핑하도록 수정되었습니다. 일부 DTO는 빌더 방식으로 전환되었습니다.

Changes

Cohort / File(s) Summary
Security: JWT token extraction
src/main/java/konkuk/thip/common/security/filter/JwtAuthenticationFilter.java
Authorization 헤더의 Bearer 토큰 조회 후 실패 시 쿠키에서 JWT_HEADER_KEY 이름의 쿠키 값으로 토큰 조회 로직 추가. jakarta.servlet.http.Cookie import 추가. 토큰 미존재 시 null 반환 경로 유지.
Room response DTOs: color 필드 확장
.../room/adapter/in/web/response/RoomGetMemberListResponse.java, .../room/adapter/in/web/response/RoomPlayingDetailViewResponse.java, .../room/adapter/in/web/response/RoomRecruitingDetailViewResponse.java
MemberSearchResult에 aliasColor:String 추가(생성자/접근자/빌더 반영). PlayingDetailView에 categoryColor:String 레코드 컴포넌트 추가. RecruitingDetailView는 레코드에 @Builder 추가 및 categoryColor:String 컴포넌트 추가; 빌더 기반 생성으로 전환.
Persistence/Port: category 색상 조회 추가
.../room/adapter/out/persistence/RoomQueryPersistenceAdapter.java, .../room/adapter/out/persistence/repository/category/CategoryJpaRepository.java, .../room/application/port/out/RoomQueryPort.java
RoomQueryPort#findAliasColorOfCategory(Category) 신규. Adapter에 CategoryJpaRepository 의존성 추가 및 위 메서드 구현(카테고리 value로 alias color 조회, 없으면 EntityNotFoundException(ErrorCode.CATEGORY_NOT_FOUND) 던짐). Repository에 JPQL findAliasColorByValue(...) 추가.
Services: 신규 필드 매핑/의존성 추가
.../room/application/service/RoomGetMemberListService.java, .../room/application/service/RoomShowPlayingDetailViewService.java, .../room/application/service/RoomShowRecruitingDetailViewService.java
회원 목록 응답에 aliasColor 매핑 추가. Playing/Recruiting 상세 조회 서비스에 RoomQueryPort 의존성 추가하고 응답에 categoryColor 채움. Recruiting 상세는 빌더 사용으로 매핑 전환 및 필드명 정리.

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: 토큰 설정 후 체인 진행(또는 토큰 없음 처리)
Loading
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)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

🧹 chore, 🚀 deploy

Suggested reviewers

  • hd0rable

Poem

귀끝에 붉은 픽셀 한 점, 색을 주웠지
방엔 별칭의 색, 카테고리의 빛이 스며들고
쿠키 속 토큰은 살짝 달콤하네 🍪
빌더로 층층이 쌓아 올린 응답의 탑
깡총, 오늘도 컬러풀한 PR 위에서 춤춘다 🐇

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch develop

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 2a19181.

@seongjunnoh seongjunnoh merged commit 773569b into main Aug 13, 2025
5 of 6 checks passed
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: 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 쿼리 최적화 고려

현재 구현이 동작하지만, 다음과 같은 최적화를 고려해보시기 바랍니다:

  1. 쿼리가 자주 호출된다면 @QueryHints를 사용한 캐싱 고려
  2. CategoryJpaEntityAliasForCategoryJpaEntity 간의 관계가 1:1이라면 fetch join 사용 검토

TODO 주석에 따라 리팩토링 시 이러한 성능 최적화도 함께 고려하시면 좋겠습니다.

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

109-115: 예외 처리는 적절하나 리팩토링 필요

EntityNotFoundException 사용과 에러 코드 설정이 적절합니다. TODO 주석에 따라 리팩토링 시 다음 사항을 고려하시기 바랍니다:

  1. 캐싱 메커니즘 도입 (카테고리 색상은 자주 변경되지 않으므로)
  2. 카테고리 관련 로직을 별도 서비스로 분리

카테고리 색상은 변경 빈도가 낮은 데이터이므로, 애플리케이션 레벨 캐싱(@Cacheable)이나 Redis 캐싱을 도입하면 성능 향상을 기대할 수 있습니다.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between cac0a12 and 2a19181.

📒 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: 생성자 파라미터 순서가 일관성 있게 구성되었습니다

RoomQueryPortRoomCommandPort 바로 다음에 위치하여 Room 관련 포트들이 함께 그룹화되었습니다. 이는 코드 가독성 향상에 도움이 됩니다.

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

56-78: 빌더 패턴 전환이 적절하게 구현되었습니다

기존 생성자 방식에서 빌더 패턴으로의 전환이 잘 이루어졌으며, 필드 명명이 더 명확해졌습니다.

Comment on lines 74 to 76
if (authorization != null && authorization.startsWith(JWT_PREFIX.getValue())) {
return authorization.split(" ")[1];
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

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.

Suggested change
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.

Comment on lines +78 to +85
// 2. Cookie에서 JWT 추출 (웹)
if (request.getCookies() != null) {
for (Cookie cookie : request.getCookies()) {
if (JWT_HEADER_KEY.getValue().equals(cookie.getName())) {
return cookie.getValue();
}
}
}
Copy link

Choose a reason for hiding this comment

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

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

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

Suggested change
// 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 : 리펙토링 대상
Copy link

Choose a reason for hiding this comment

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

🛠️ 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.

Suggested change
.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 : 리펙토링 대상
Copy link

Choose a reason for hiding this comment

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

🛠️ 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.

Suggested change
.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.

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.

2 participants