Skip to content

Conversation

@chat26666
Copy link
Collaborator

@chat26666 chat26666 commented Jun 24, 2025


작업 내용

  • api 경로가 좀 더 rest 하게 변경되었습니다.
  • 그 외 일부 쓰지 않는 메서드들 정리했고, 게임 어드민 기능은 ROLE ADMIN 만 가능하게끔 제한조치하였습니다.

코드 리뷰 전 확인 체크리스트

  • 불필요한 콘솔 로그, 주석 제거
  • 커밋 메시지 컨벤션 준수 (type : )
  • 기능 정상 동작 확인

Summary by CodeRabbit

  • 신규 기능

    • 채팅방 소유자 외에 관리자도 채팅방 삭제 등 주요 작업을 수행할 수 있도록 권한 범위가 확장되었습니다.
    • 게임 관리 기능 전체에 관리자 권한이 적용되어, 관리자는 모든 게임 관리 작업을 수행할 수 있습니다.
    • 문제 해결 이벤트 발생 시 게임 캐릭터 레벨업 처리를 위한 이벤트 발행 및 처리 기능이 추가되었습니다.
  • 버그 수정

    • 채팅 및 채팅방 관련 REST API, WebSocket, 프론트엔드 경로가 일관되게 단수(room)에서 복수(rooms)로 통일되어 경로 혼동 문제가 해결되었습니다.
  • 리팩터링/스타일

    • 패키지 선언 및 import 구문이 일관성 있게 정정되었습니다.
    • 이벤트 관련 클래스들이 적절한 패키지로 이동되어 구조가 개선되었습니다.
    • 불필요한 메서드가 제거되어 코드가 간결해졌습니다.
  • 테스트

    • 변경된 권한 체크 로직에 맞춰 테스트 코드가 수정되었습니다.

@coderabbitai
Copy link

coderabbitai bot commented Jun 24, 2025

## Walkthrough

채팅 관련 API, 컨트롤러, 인터셉터, 테스트 등에서 URL 경로의 단수 "room"을 복수 "rooms"로 통일하였으며, 채팅방 소유자 확인 로직을 소유자 또는 관리자 권한 확인으로 확장하였습니다. 또한, 관리 기능 클래스에 ADMIN 권한 어노테이션을 추가하고, 불필요한 findAll 메서드를 제거하였습니다. 게임 레벨업 관련 이벤트 및 리스너, 이벤트 퍼블리셔가 새로 추가되고, 이벤트 관련 패키지 구조가 일부 변경되었습니다.

## Changes

| 파일/경로 요약                                                                                   | 변경 내용 요약                                                                                      |
|--------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------|
| .../application/chatting/service/ChattingUseCase.java<br>.../domain/chat/service/ChattingDomainService.java<br>.../test/java/org/ezcode/codetest/application/chatting/service/ChattingUseCaseTest.java<br>.../test/java/org/ezcode/codetest/domain/chat/service/ChattingDomainServiceTest.java | 채팅방 소유자 확인 메서드를 소유자 또는 관리자 확인으로 변경 및 테스트 코드 반영                    |
| .../application/game/management/GameAdminUseCase.java                                            | 클래스에 `@PreAuthorize("hasRole('ADMIN')")` 어노테이션 추가                                       |
| .../domain/chat/repository/ChatRepository.java<br>.../infrastructure/persistence/repository/chat/ChatRepositoryImpl.java | findAll() 메서드 제거                                                                              |
| .../presentation/chatting/chatting/config/ChatWebConfig.java<br>.../presentation/chatting/chatting/controller/ChatController.java<br>.../presentation/chatting/chatting/controller/ChatRoomController.java<br>.../presentation/chatting/chatting/interceptor/ChatLimitInterceptor.java<br>.../presentation/chatting/event/EventHandleController.java<br>.../presentation/chatting/view/ChatViewController.java | 패키지명 오타 수정 및 URL 경로를 단수 "room"에서 복수 "rooms"로 변경, 관련 어노테이션 수정          |
| .../resources/templates/chat-page.html                                                           | JS 내 WebSocket/REST API 경로를 "room"에서 "rooms"로 변경                                          |
| .../infrastructure/event/dto/GameLevelUpEvent.java                                               | 게임 레벨업 이벤트 데이터 레코드 추가                                                             |
| .../infrastructure/event/listener/GameLevelUpListener.java                                       | 게임 레벨업 이벤트 리스너 클래스 추가                                                              |
| .../infrastructure/event/publisher/ProblemEventPublisher.java                                    | 문제 풀이 이벤트를 게임 레벨업 이벤트로 변환하여 발행하는 퍼블리셔 추가                            |
| .../infrastructure/event/listener/ChatEventListener.java<br>.../infrastructure/event/listener/NotificationEventListener.java<br>.../infrastructure/event/listener/WebSocketEventListener.java<br>.../infrastructure/event/publisher/ChatEventPublisher.java<br>.../infrastructure/event/publisher/DiscordNotifier.java<br>.../infrastructure/event/publisher/NotificationEventPublisher.java<br>.../infrastructure/event/publisher/RedisJudgeQueueProducer.java<br>.../infrastructure/event/publisher/StompMessageService.java | 이벤트 관련 클래스들의 패키지 경로를 `service`에서 `publisher`로 변경                            |
| .../infrastructure/event/config/CustomHandShakeHandler.java                                      | WebSocket 연결 토큰 파라미터 처리 확장 및 예외 처리 추가                                          |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant ChatController
    participant ChattingUseCase
    participant ChattingDomainService

    User->>ChatController: 채팅방 삭제 요청 (roomId, user)
    ChatController->>ChattingUseCase: removeChatRoom(roomId, user)
    ChattingUseCase->>ChattingDomainService: checkChatRoomOwnerOrAdmin(room, user)
    ChattingDomainService-->>ChattingUseCase: 소유자 또는 관리자 권한 확인
    ChattingUseCase-->>ChatController: 삭제 처리 결과 반환
    ChatController-->>User: 응답 반환

Possibly related PRs

Suggested reviewers

  • pokerbearkr
  • Kimminu7

Poem

채팅방 길을 plural로,
관리 권한도 넓혀서,
ADMIN만이 할 수 있게,
findAll은 안녕이네!
게임 레벨업 소식도,
이벤트로 활짝 피어나,
토끼는 깡총깡총 뛰며, 코드 축하하네 🐇✨


<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

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.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=ezcode-my/backend&utm_content=97):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `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. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- 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 src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### 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](https://docs.coderabbit.ai/guides/configure-coderabbit) 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`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

@chat26666 chat26666 changed the title refactor : api 경로 변경 코드 정리 refactor : api 경로 변경 및 필요없는 코드 정리 Jun 24, 2025
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: 0

🔭 Outside diff range comments (1)
src/main/java/org/ezcode/codetest/presentation/chatting/chatting/interceptor/ChatLimitInterceptor.java (1)

33-41: AuthUser 캐스팅 안전성 확보 및 비인증 사용자 처리

익명 사용자(AnonymousAuthenticationToken)가 들어올 경우 AuthUser 로 단순 캐스팅하면 ClassCastException 이 발생할 수 있습니다.
타입 검증 후 처리하거나 401/403 응답을 명시적으로 내려주세요.

-AuthUser authUser = (AuthUser)authentication.getPrincipal();
+if (!(authentication.getPrincipal() instanceof AuthUser authUser)) {
+    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+    return false;
+}
🧹 Nitpick comments (3)
src/main/java/org/ezcode/codetest/presentation/chatting/chatting/interceptor/ChatLimitInterceptor.java (3)

1-1: 패키지 경로에 chatting.chatting 이중 표기 – 필요성 재검토 권장

chatting.chatting 처럼 동일한 디렉터리명이 두 번 반복되는 구조는 직관성이 떨어집니다.
org.ezcode.codetest.presentation.chatting.interceptor 정도로 단순화해도 모듈 경계가 명확하니, 경로를 한 단계 줄이는 방안을 고려해 주세요.


24-26: 상수 선언 관례 및 오토박싱 비용 최적화

MAX_CHAT_COUNT_PER_10SEC 는 상수이므로 primitive long 이 더 적합하며, staticfinal 위치를 관례적으로 바꿔 가독성을 높일 수 있습니다.

-private final static Long MAX_CHAT_COUNT_PER_10SEC = 11L;
+private static final long MAX_CHAT_COUNT_PER_10SEC = 11L;

59-74: extractRoomId 예외 메시지 불투명

NumberFormatException 에 원본 메시지만 전달하면 어떤 PathVariable 이 잘못됐는지 로그 외에는 알기 어렵습니다.
구체적인 메시지와 함께 400 Bad Request 로 응답하도록 개선을 권장합니다.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b42839e and 573bab2.

📒 Files selected for processing (14)
  • src/main/java/org/ezcode/codetest/application/chatting/service/ChattingUseCase.java (1 hunks)
  • src/main/java/org/ezcode/codetest/application/game/management/GameAdminUseCase.java (1 hunks)
  • src/main/java/org/ezcode/codetest/domain/chat/repository/ChatRepository.java (0 hunks)
  • src/main/java/org/ezcode/codetest/domain/chat/service/ChattingDomainService.java (2 hunks)
  • src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/chat/ChatRepositoryImpl.java (0 hunks)
  • src/main/java/org/ezcode/codetest/presentation/chatting/chatting/config/ChatWebConfig.java (2 hunks)
  • src/main/java/org/ezcode/codetest/presentation/chatting/chatting/controller/ChatController.java (2 hunks)
  • src/main/java/org/ezcode/codetest/presentation/chatting/chatting/controller/ChatRoomController.java (2 hunks)
  • src/main/java/org/ezcode/codetest/presentation/chatting/chatting/interceptor/ChatLimitInterceptor.java (1 hunks)
  • src/main/java/org/ezcode/codetest/presentation/chatting/event/EventHandleController.java (3 hunks)
  • src/main/java/org/ezcode/codetest/presentation/chatting/view/ChatViewController.java (1 hunks)
  • src/main/resources/templates/chat-page.html (3 hunks)
  • src/test/java/org/ezcode/codetest/application/chatting/service/ChattingUseCaseTest.java (1 hunks)
  • src/test/java/org/ezcode/codetest/domain/chat/service/ChattingDomainServiceTest.java (4 hunks)
💤 Files with no reviewable changes (2)
  • src/main/java/org/ezcode/codetest/domain/chat/repository/ChatRepository.java
  • src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/chat/ChatRepositoryImpl.java
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (19)
src/main/java/org/ezcode/codetest/presentation/chatting/view/ChatViewController.java (1)

1-1: 패키지 경로가 변경되었습니다 – 레거시 참조 검사 필요
chattingmanagement.viewchatting.view 로 이동하면서 다른 소스가 여전히 이전 패키지를 import 하고 있다면 컴파일이 실패합니다. 전체 코드베이스에서 레거시 경로 사용 여부를 한번 더 확인해주세요.

#!/bin/bash
# 변경 전 패키지 경로 사용 여부 확인
rg --line-number 'presentation\.chattingmanagement\.view' || echo "✅ 레거시 패키지 참조 없음"
src/main/java/org/ezcode/codetest/presentation/chatting/chatting/interceptor/ChatLimitInterceptor.java (1)

45-55: 차단 시 클라이언트 피드백 부재

현재 false 만 반환하면 Spring MVC 가 단순 200 OK 로 body 없이 응답할 수 있습니다.
적절한 HTTP 상태 코드(예: 429 Too Many Requests)와 메시지를 설정해 사용자-경험을 향상시켜 주세요.

src/main/java/org/ezcode/codetest/presentation/chatting/chatting/config/ChatWebConfig.java (2)

1-3: 패키지 구조 수정이 올바르게 적용되었습니다.

패키지 경로가 chattingmanagement.chatting에서 chatting.chatting으로 수정되어 디렉토리 구조와 일치하도록 개선되었습니다.


19-19: API 경로가 RESTful 규칙에 맞게 복수형으로 변경되었습니다.

인터셉터 패턴이 /api/room/*/chat에서 /api/rooms/*/chat으로 변경되어 일관된 복수형 명명 규칙을 따르고 있습니다.

src/main/java/org/ezcode/codetest/presentation/chatting/chatting/controller/ChatController.java (2)

1-1: 패키지 구조 수정이 일관되게 적용되었습니다.

다른 파일들과 동일하게 패키지 경로가 올바르게 수정되었습니다.


17-17: RequestMapping 경로가 RESTful 표준에 맞게 수정되었습니다.

경로가 /api/room/{roomId}/chat에서 /api/rooms/{roomId}/chat으로 변경되어 복수형 명명 규칙을 따르며, 인터셉터 설정과 일치합니다.

src/main/java/org/ezcode/codetest/application/game/management/GameAdminUseCase.java (2)

23-23: Spring Security 어노테이션 import가 추가되었습니다.

@PreAuthorize 어노테이션 사용을 위한 import가 올바르게 추가되었습니다.


31-31: 게임 관리 기능에 ADMIN 권한 제한이 올바르게 적용되었습니다.

클래스 레벨에 @PreAuthorize("hasRole('ADMIN')")를 적용하여 모든 메서드에 ADMIN 권한이 필요하도록 설정한 것은 보안 강화 측면에서 적절한 구현입니다.

src/test/java/org/ezcode/codetest/application/chatting/service/ChattingUseCaseTest.java (1)

170-170: 테스트가 새로운 권한 확인 로직에 맞게 올바르게 업데이트되었습니다.

isChatRoomOwner에서 checkChatRoomOwnerOrAdmin으로 변경되고, 매개변수도 사용자 ID에서 전체 User 객체로 변경되어 실제 구현과 일치합니다.

src/main/java/org/ezcode/codetest/application/chatting/service/ChattingUseCase.java (1)

59-59: 채팅방 권한 확인 로직이 관리자 권한을 포함하도록 확장되었습니다.

isChatRoomOwner에서 checkChatRoomOwnerOrAdmin으로 변경되어 소유자뿐만 아니라 관리자도 채팅방을 삭제할 수 있도록 권한이 확장되었습니다. 전체 User 객체를 전달하여 역할 기반 검증이 가능하도록 개선되었습니다.

src/main/java/org/ezcode/codetest/presentation/chatting/chatting/controller/ChatRoomController.java (2)

1-1: 패키지 선언 수정이 올바릅니다.

패키지 경로가 chattingmanagement.chatting에서 chatting.chatting으로 정정되어 일관성이 개선되었습니다.


24-24: RESTful API 규칙에 맞게 URL 경로가 개선되었습니다.

/api/chatrooms에서 /api/rooms로 변경하여 복수형 명사 사용으로 일관성을 확보했습니다.

src/main/java/org/ezcode/codetest/presentation/chatting/event/EventHandleController.java (2)

1-1: 패키지 선언 정정이 적절합니다.

패키지 경로가 올바르게 수정되어 프로젝트 구조의 일관성이 향상되었습니다.


28-28: WebSocket 메시지 매핑 경로가 일관성 있게 개선되었습니다.

/room/에서 /rooms/로 변경하여 RESTful 규칙에 맞게 복수형을 사용하고 있습니다.

Also applies to: 38-38

src/main/resources/templates/chat-page.html (1)

311-311: 프론트엔드 엔드포인트가 백엔드 변경사항과 일치하게 업데이트되었습니다.

WebSocket 및 REST API 경로가 모두 복수형 "rooms"를 사용하도록 일관성 있게 수정되었습니다.

Also applies to: 340-340, 355-355

src/main/java/org/ezcode/codetest/domain/chat/service/ChattingDomainService.java (2)

11-12: 필요한 임포트가 올바르게 추가되었습니다.

새로운 메서드 시그니처와 권한 확인 로직을 위한 UserUserRole 임포트가 적절히 추가되었습니다.


34-39: 권한 확인 로직이 향상되어 보안성이 개선되었습니다.

메서드명이 checkChatRoomOwnerOrAdmin으로 변경되어 기능이 명확해졌고, 채팅방 소유자 또는 관리자 권한을 모두 허용하는 로직이 올바르게 구현되었습니다.

src/test/java/org/ezcode/codetest/domain/chat/service/ChattingDomainServiceTest.java (2)

44-44: 테스트를 위한 추가 사용자 객체가 적절히 설정되었습니다.

권한이 없는 사용자에 대한 테스트 케이스를 위해 wrongUser 객체가 올바르게 추가되었습니다.

Also applies to: 65-77


129-129: 테스트 메서드 호출이 서비스 변경사항에 맞게 업데이트되었습니다.

checkChatRoomOwnerOrAdmin 메서드를 사용하도록 테스트가 올바르게 수정되어 새로운 권한 확인 로직을 적절히 검증하고 있습니다.

Also applies to: 133-133, 199-199

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 (2)
src/main/java/org/ezcode/codetest/infrastructure/event/publisher/ProblemEventPublisher.java (1)

16-16: 메서드명 개선 제안

메서드명 publishProblemSolveEvent가 실제로 GameLevelUpEvent를 발행한다는 사실을 명확히 나타내지 못합니다.

메서드명을 다음과 같이 변경하는 것을 고려해보세요:

-public void publishProblemSolveEvent(UserProblemResult event) {
+public void publishGameLevelUpEvent(UserProblemResult event) {

또는 더 구체적으로:

-public void publishProblemSolveEvent(UserProblemResult event) {
+public void publishLevelUpEventFromProblemResult(UserProblemResult event) {
src/main/java/org/ezcode/codetest/infrastructure/event/listener/GameLevelUpListener.java (1)

20-22: 이벤트 데이터 검증 추가 고려

도메인 서비스를 호출하기 전에 이벤트 데이터의 유효성을 검증하는 것이 좋습니다.

다음과 같은 검증 로직 추가를 고려해보세요:

 public void handleGameCharacterLevelUp(GameLevelUpEvent event) {
+    if (event == null || event.userId() == null || event.problemCategory() == null) {
+        log.warn("유효하지 않은 GameLevelUpEvent: {}", event);
+        return;
+    }

     characterDomainService.gameCharacterLevelUp(event.userId(), event.isProblemSolved(), event.problemCategory());
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 573bab2 and 238e8cc.

📒 Files selected for processing (11)
  • src/main/java/org/ezcode/codetest/infrastructure/event/dto/GameLevelUpEvent.java (1 hunks)
  • src/main/java/org/ezcode/codetest/infrastructure/event/listener/ChatEventListener.java (1 hunks)
  • src/main/java/org/ezcode/codetest/infrastructure/event/listener/GameLevelUpListener.java (1 hunks)
  • src/main/java/org/ezcode/codetest/infrastructure/event/listener/NotificationEventListener.java (1 hunks)
  • src/main/java/org/ezcode/codetest/infrastructure/event/listener/WebSocketEventListener.java (1 hunks)
  • src/main/java/org/ezcode/codetest/infrastructure/event/publisher/ChatEventPublisher.java (1 hunks)
  • src/main/java/org/ezcode/codetest/infrastructure/event/publisher/DiscordNotifier.java (1 hunks)
  • src/main/java/org/ezcode/codetest/infrastructure/event/publisher/NotificationEventPublisher.java (1 hunks)
  • src/main/java/org/ezcode/codetest/infrastructure/event/publisher/ProblemEventPublisher.java (1 hunks)
  • src/main/java/org/ezcode/codetest/infrastructure/event/publisher/RedisJudgeQueueProducer.java (1 hunks)
  • src/main/java/org/ezcode/codetest/infrastructure/event/publisher/StompMessageService.java (1 hunks)
✅ Files skipped from review due to trivial changes (9)
  • src/main/java/org/ezcode/codetest/infrastructure/event/publisher/DiscordNotifier.java
  • src/main/java/org/ezcode/codetest/infrastructure/event/listener/WebSocketEventListener.java
  • src/main/java/org/ezcode/codetest/infrastructure/event/publisher/StompMessageService.java
  • src/main/java/org/ezcode/codetest/infrastructure/event/publisher/NotificationEventPublisher.java
  • src/main/java/org/ezcode/codetest/infrastructure/event/listener/ChatEventListener.java
  • src/main/java/org/ezcode/codetest/infrastructure/event/listener/NotificationEventListener.java
  • src/main/java/org/ezcode/codetest/infrastructure/event/publisher/ChatEventPublisher.java
  • src/main/java/org/ezcode/codetest/infrastructure/event/publisher/RedisJudgeQueueProducer.java
  • src/main/java/org/ezcode/codetest/infrastructure/event/dto/GameLevelUpEvent.java
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build

Comment on lines +16 to +23
public void publishProblemSolveEvent(UserProblemResult event) {

Long userId = event.getUser().getId();
boolean isCorrect = event.isCorrect();
String problemCategory = event.getProblem().getCategory().getDescription();

publisher.publishEvent(new GameLevelUpEvent(userId, isCorrect, problemCategory));
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

널 안전성 검증 추가 필요

현재 구현에서는 event, event.getUser(), event.getProblem(), event.getProblem().getCategory() 등의 null 체크가 누락되어 있어 NullPointerException이 발생할 수 있습니다.

다음과 같이 수정하여 null 안전성을 보장해주세요:

 public void publishProblemSolveEvent(UserProblemResult event) {
+    if (event == null || event.getUser() == null || event.getProblem() == null 
+        || event.getProblem().getCategory() == null) {
+        throw new IllegalArgumentException("UserProblemResult와 관련 객체들은 null일 수 없습니다");
+    }

     Long userId = event.getUser().getId();
     boolean isCorrect = event.isCorrect();
     String problemCategory = event.getProblem().getCategory().getDescription();

     publisher.publishEvent(new GameLevelUpEvent(userId, isCorrect, problemCategory));
 }
🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/infrastructure/event/publisher/ProblemEventPublisher.java
between lines 16 and 23, add null checks for event, event.getUser(),
event.getProblem(), and event.getProblem().getCategory() before accessing their
methods to prevent NullPointerException. Implement conditional checks that
return early or handle null cases safely to ensure null safety in the
publishProblemSolveEvent method.

Comment on lines 19 to 23
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleGameCharacterLevelUp(GameLevelUpEvent event) {

characterDomainService.gameCharacterLevelUp(event.userId(), event.isProblemSolved(), event.problemCategory());
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

에러 처리 및 로깅 추가 필요

현재 구현에서는 도메인 서비스 호출 시 발생할 수 있는 예외에 대한 처리가 없고, 로깅 어노테이션이 있음에도 불구하고 실제 로깅이 구현되지 않았습니다.

다음과 같이 에러 처리와 로깅을 추가해주세요:

 @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
 public void handleGameCharacterLevelUp(GameLevelUpEvent event) {
+    try {
+        log.info("게임 레벨업 이벤트 처리 시작 - userId: {}, isProblemSolved: {}, category: {}", 
+                 event.userId(), event.isProblemSolved(), event.problemCategory());
+        
         characterDomainService.gameCharacterLevelUp(event.userId(), event.isProblemSolved(), event.problemCategory());
+        
+        log.info("게임 레벨업 이벤트 처리 완료 - userId: {}", event.userId());
+    } catch (Exception e) {
+        log.error("게임 레벨업 이벤트 처리 중 오류 발생 - userId: {}, error: {}", 
+                  event.userId(), e.getMessage(), e);
+        // 필요에 따라 재시도 로직이나 알림 로직 추가 고려
+    }
 }
📝 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
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleGameCharacterLevelUp(GameLevelUpEvent event) {
characterDomainService.gameCharacterLevelUp(event.userId(), event.isProblemSolved(), event.problemCategory());
}
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleGameCharacterLevelUp(GameLevelUpEvent event) {
try {
log.info("게임 레벨업 이벤트 처리 시작 - userId: {}, isProblemSolved: {}, category: {}",
event.userId(), event.isProblemSolved(), event.problemCategory());
characterDomainService.gameCharacterLevelUp(event.userId(), event.isProblemSolved(), event.problemCategory());
log.info("게임 레벨업 이벤트 처리 완료 - userId: {}", event.userId());
} catch (Exception e) {
log.error("게임 레벨업 이벤트 처리 중 오류 발생 - userId: {}, error: {}",
event.userId(), e.getMessage(), e);
// 필요에 따라 재시도 로직이나 알림 로직 추가 고려
}
}
🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/infrastructure/event/listener/GameLevelUpListener.java
around lines 19 to 23, the method handleGameCharacterLevelUp lacks error
handling and does not perform any logging despite having logging annotations.
Wrap the call to characterDomainService.gameCharacterLevelUp in a try-catch
block to catch potential exceptions, log the error details using the logger, and
handle the exception appropriately to prevent it from propagating uncaught.

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

♻️ Duplicate comments (1)
src/main/java/org/ezcode/codetest/infrastructure/event/listener/GameLevelUpListener.java (1)

23-37: 로깅 개선으로 디버깅 효율성을 높일 수 있습니다.

이전 리뷰에서 언급된 에러 처리와 로깅이 잘 구현되어 있습니다. 다만 로그 메시지에 이벤트 컨텍스트 정보를 추가하면 디버깅과 모니터링에 더 유용할 것 같습니다.

다음과 같이 로그 메시지를 개선해보세요:

 @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
 @Transactional(propagation = Propagation.REQUIRES_NEW)
 public void handleGameCharacterLevelUp(GameLevelUpEvent event) {
+    log.debug("게임 레벨업 이벤트 처리 시작 - userId: {}, isProblemSolved: {}, category: {}", 
+              event.userId(), event.isProblemSolved(), event.problemCategory());
     
     try {
         characterDomainService.gameCharacterLevelUp(event.userId(), event.isProblemSolved(),
             event.problemCategory());
+        log.debug("게임 레벨업 이벤트 처리 완료 - userId: {}", event.userId());
     } catch (GameException ge) {
-        log.info("현재 해당 사용자는 게임 캐릭터를 생성한 상태가 아닙니다. {}", ge.getMessage());
+        log.info("현재 해당 사용자는 게임 캐릭터를 생성한 상태가 아닙니다. userId: {}, error: {}", 
+                 event.userId(), ge.getMessage());
         TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
     } catch (Exception e) {
-        log.warn("문제 풀이로 인한 레벨업 실패 Unknown Error 발생", e);
+        log.warn("문제 풀이로 인한 레벨업 실패 Unknown Error 발생 - userId: {}, category: {}", 
+                 event.userId(), event.problemCategory(), e);
         TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
     }
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 238e8cc and 5d61d04.

📒 Files selected for processing (4)
  • src/main/java/org/ezcode/codetest/infrastructure/event/config/CustomHandShakeHandler.java (1 hunks)
  • src/main/java/org/ezcode/codetest/infrastructure/event/listener/GameLevelUpListener.java (1 hunks)
  • src/main/java/org/ezcode/codetest/infrastructure/event/listener/WebSocketEventListener.java (3 hunks)
  • src/main/resources/templates/chat-page.html (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main/java/org/ezcode/codetest/infrastructure/event/listener/WebSocketEventListener.java
  • src/main/resources/templates/chat-page.html
🔇 Additional comments (3)
src/main/java/org/ezcode/codetest/infrastructure/event/listener/GameLevelUpListener.java (2)

1-14: 임포트 구조가 깔끔하게 정리되어 있습니다.

필요한 의존성들이 적절히 임포트되어 있고, 패키지 구조도 명확합니다.


16-21: 클래스 선언 및 의존성 주입이 적절합니다.

Spring의 표준 어노테이션들을 사용하여 컴포넌트 스캔, 로깅, 생성자 주입이 올바르게 구성되어 있습니다.

src/main/java/org/ezcode/codetest/infrastructure/event/config/CustomHandShakeHandler.java (1)

31-33: 쿼리 파라미터 null 검증 로직이 잘 추가되었습니다.

WebSocket 연결 시 쿼리 파라미터가 누락된 경우를 미리 검증하여 안정성을 향상시켰습니다.

Comment on lines +35 to 42
if (query.startsWith("token=")) {
tokenParam = query.substring(6);
} else if (query.startsWith("chat-token=")) {
tokenParam = query.substring(11);
attributes.put("isChattingWebsocket", true);
} else {
throw new IllegalArgumentException("허용되지 않은 토큰 파라미터: " + query);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

토큰 파라미터 처리 로직의 확장성과 유지보수성을 개선해주세요.

현재 구현에서 몇 가지 개선 사항이 필요합니다:

  • 매직 넘버(6, 11) 사용으로 인한 유지보수성 저하
  • 문자열 리터럴 중복
  • 새로운 토큰 타입 추가 시 확장성 부족

다음과 같이 리팩토링을 제안합니다:

+	private static final String TOKEN_PREFIX = "token=";
+	private static final String CHAT_TOKEN_PREFIX = "chat-token=";
+
 	@Override
 	protected Principal determineUser(
 		@NonNull ServerHttpRequest request,
 		@NonNull WebSocketHandler wsHandler,
 		@NonNull Map<String, Object> attributes
 	) {
 		URI uri = request.getURI();
 		String query = uri.getQuery();
 		String tokenParam = null;

 		if (query == null) {
 			throw new IllegalArgumentException("WebSocket 연결에 필요한 토큰이 없습니다.");
 		}

-		if (query.startsWith("token=")) {
-			tokenParam = query.substring(6);
-		} else if (query.startsWith("chat-token=")) {
-			tokenParam = query.substring(11);
+		if (query.startsWith(TOKEN_PREFIX)) {
+			tokenParam = query.substring(TOKEN_PREFIX.length());
+		} else if (query.startsWith(CHAT_TOKEN_PREFIX)) {
+			tokenParam = query.substring(CHAT_TOKEN_PREFIX.length());
 			attributes.put("isChattingWebsocket", true);
 		} else {
 			throw new IllegalArgumentException("허용되지 않은 토큰 파라미터: " + query);
 		}
📝 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 (query.startsWith("token=")) {
tokenParam = query.substring(6);
} else if (query.startsWith("chat-token=")) {
tokenParam = query.substring(11);
attributes.put("isChattingWebsocket", true);
} else {
throw new IllegalArgumentException("허용되지 않은 토큰 파라미터: " + query);
}
// In CustomHandShakeHandler.java, add at the top of the class:
private static final String TOKEN_PREFIX = "token=";
private static final String CHAT_TOKEN_PREFIX = "chat-token=";
@Override
protected Principal determineUser(
@NonNull ServerHttpRequest request,
@NonNull WebSocketHandler wsHandler,
@NonNull Map<String, Object> attributes
) {
URI uri = request.getURI();
String query = uri.getQuery();
String tokenParam = null;
if (query == null) {
throw new IllegalArgumentException("WebSocket 연결에 필요한 토큰이 없습니다.");
}
if (query.startsWith(TOKEN_PREFIX)) {
tokenParam = query.substring(TOKEN_PREFIX.length());
} else if (query.startsWith(CHAT_TOKEN_PREFIX)) {
tokenParam = query.substring(CHAT_TOKEN_PREFIX.length());
attributes.put("isChattingWebsocket", true);
} else {
throw new IllegalArgumentException("허용되지 않은 토큰 파라미터: " + query);
}
// … continue processing tokenParam …
}
🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/infrastructure/event/config/CustomHandShakeHandler.java
around lines 35 to 42, the token parameter handling uses hardcoded substring
indices and duplicated string literals, which reduces maintainability and
extensibility. Refactor by defining constants for token prefixes and their
lengths, and use these constants to extract token values. Consider using a map
or enum to associate token prefixes with their handling logic, so adding new
token types requires minimal code changes.

@chat26666 chat26666 merged commit f3db1e5 into dev Jun 24, 2025
2 checks passed
@chat26666 chat26666 deleted the refactor/chat branch June 24, 2025 11:09
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.

4 participants