Skip to content

Conversation

@minjee2758
Copy link
Collaborator

@minjee2758 minjee2758 commented Jul 1, 2025

작업 내용

  • UserSerivce에 통합되어있던 admin 기능(admin권한부여)를 클래스로 분리
    • 향후 admin 기능의 확장성을 고려해 분리했습니다
    • AdminException도 추가
  • UserDomainServiceTest 추가

변경 사항

  • AdminService 추가
  • AdminException & AdminExceptionCode 추가
  • UserDomainService 테스트 코드 추가

참고 사항

테스트커버리지 참고 이미지
image


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

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

Summary by CodeRabbit

  • 신규 기능

    • 관리자 권한 부여 기능이 별도의 엔드포인트(/api/admin/users/{userId}/grant-admin)로 분리되어 제공됩니다. 이제 관리자는 다른 사용자에게 관리자 권한을 부여할 수 있습니다.
    • 관리자 권한 부여 관련 예외 처리 전용 클래스와 코드가 도입되어, 권한 부여 시 발생 가능한 오류 상황에 대한 명확한 안내가 추가되었습니다.
  • 버그 수정

    • 관리자 권한 부여 시 발생할 수 있는 예외(자기 자신에게 권한 부여, 이미 관리자임)에 대한 안내 메시지가 개선되었습니다.
  • 테스트

    • 사용자 도메인 서비스의 주요 기능에 대한 단위 테스트가 추가되었습니다.

@minjee2758 minjee2758 self-assigned this Jul 1, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 1, 2025

"""

Walkthrough

관리자 권한 부여 기능이 기존 UserService와 UserController에서 분리되어, 별도의 AdminService와 AdminController로 이동되었습니다. 이 과정에서 관리자 권한 예외 처리를 위한 AdminException 및 AdminExceptionCode가 신설되었고, 관련된 테스트 코드(UserDomainServiceTest)도 추가되었습니다.

Changes

파일/경로 요약 변경 내용 요약
.../usermanagement/user/service/AdminService.java
.../usermanagement/AdminController.java
AdminService와 AdminController 신규 생성, 관리자 권한 부여 기능 및 엔드포인트 분리
.../usermanagement/user/service/UserService.java
.../usermanagement/UserController.java
grantAdminRole 메서드 및 관련 엔드포인트 삭제
.../user/exception/AdminException.java
.../user/exception/code/AdminExceptionCode.java
AdminException 및 AdminExceptionCode 신규 추가, 관리자 권한 부여 예외 전용
.../user/exception/code/UserExceptionCode.java 기존 관리자 관련 예외 코드(GRANT_ADMIN_SELF, ALREADY_ADMIN_USER) 삭제
.../user/service/UserDomainService.java UserGithubInfo 관련 import 정리(기능/로직 변경 없음)
.../user/UserDomainServiceTest.java UserDomainService 단위 테스트 신규 추가

Sequence Diagram(s)

sequenceDiagram
    participant Admin as AdminController
    participant Service as AdminService
    participant Domain as UserDomainService

    Admin->>Service: grantAdminRole(authUser, userId)
    Service->>Service: 본인 부여 시 예외 검사
    Service->>Domain: findUserById(userId)
    Domain-->>Service: User 객체 반환
    Service->>Service: 이미 관리자 여부 검사
    Service->>Domain: 권한 변경(ADMIN)
    Service-->>Admin: GrantAdminRoleResponse 반환
Loading

Suggested labels

enhancement, Test

Suggested reviewers

  • Kimminu7
  • pokerbearkr
  • NCookies

Poem

🐰
새로운 서비스, 관리자의 길
권한 부여는 이제 따로 빌
예외도 새로, 코드도 깔끔
테스트까지 꼼꼼히 담금
토끼는 박수 짝짝짝!
코드가 더 튼튼해진 오늘 밤
🥕✨
"""


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ae0273a and 7f13243.

📒 Files selected for processing (1)
  • src/test/java/org/ezcode/codetest/domain/user/UserDomainServiceTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/test/java/org/ezcode/codetest/domain/user/UserDomainServiceTest.java
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
✨ Finishing Touches
  • 📝 Generate Docstrings

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

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 (3)
src/main/java/org/ezcode/codetest/domain/user/exception/AdminException.java (1)

3-3: 불필요한 import를 제거하세요.

ResponseCode를 import하고 있지만 사용하지 않습니다. 불필요한 import를 제거해 주세요.

-import org.ezcode.codetest.common.base.exception.ResponseCode;
 import org.ezcode.codetest.domain.user.exception.code.AdminExceptionCode;
src/test/java/org/ezcode/codetest/domain/user/UserDomainServiceTest.java (2)

46-61: 테스트 데이터 설정 방식을 개선하세요.

익명 내부 클래스를 사용하여 getId()와 getReviewToken() 메서드를 오버라이드하는 방식은 테스트 코드의 가독성을 떨어뜨립니다. 테스트용 빌더 패턴이나 팩토리 메서드를 사용하는 것이 더 명확합니다.

다음과 같이 개선할 수 있습니다:

-    private final User testUser = new User(
-        "[email protected]",
-        "hashedPassword",
-        "testUser",
-        "TestNick",
-        30,
-        Tier.NEWBIE,
-        UserRole.USER,
-        false,  // isDeleted
-        true,   // verified
-        "https://github.com/test",
-        false   // gitPushStatus
-    ) {
-        public Long getId() { return 1L; }
-        public int getReviewToken() { return 5; }
-    };
+    private User testUser;
+
+    @BeforeEach
+    void setUp() {
+        testUser = spy(new User(
+            "[email protected]",
+            "hashedPassword", 
+            "testUser",
+            "TestNick",
+            30,
+            Tier.NEWBIE,
+            UserRole.USER,
+            false,
+            true,
+            "https://github.com/test",
+            false
+        ));
+        when(testUser.getId()).thenReturn(1L);
+        when(testUser.getReviewToken()).thenReturn(5);
+    }

217-230: 주석 처리된 테스트 코드를 정리하세요.

토큰 리셋 테스트가 주석 처리되어 있습니다. 기능이 필요하다면 완성하거나, 불필요하다면 제거해야 합니다.

이 테스트가 필요한지 확인 후 다음 중 하나를 선택하세요:

  1. 기능이 구현되어 있다면 테스트를 완성
  2. 기능이 없거나 불필요하다면 주석 블록 전체 제거

완성이 필요하다면 구현을 도와드릴 수 있습니다.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f710d77 and b13d412.

📒 Files selected for processing (9)
  • src/main/java/org/ezcode/codetest/application/usermanagement/user/service/AdminService.java (1 hunks)
  • src/main/java/org/ezcode/codetest/application/usermanagement/user/service/UserService.java (0 hunks)
  • src/main/java/org/ezcode/codetest/domain/user/exception/AdminException.java (1 hunks)
  • src/main/java/org/ezcode/codetest/domain/user/exception/code/AdminExceptionCode.java (1 hunks)
  • src/main/java/org/ezcode/codetest/domain/user/exception/code/UserExceptionCode.java (1 hunks)
  • src/main/java/org/ezcode/codetest/domain/user/service/UserDomainService.java (0 hunks)
  • src/main/java/org/ezcode/codetest/presentation/usermanagement/AdminController.java (1 hunks)
  • src/main/java/org/ezcode/codetest/presentation/usermanagement/UserController.java (0 hunks)
  • src/test/java/org/ezcode/codetest/domain/user/UserDomainServiceTest.java (1 hunks)
💤 Files with no reviewable changes (3)
  • src/main/java/org/ezcode/codetest/domain/user/service/UserDomainService.java
  • src/main/java/org/ezcode/codetest/presentation/usermanagement/UserController.java
  • src/main/java/org/ezcode/codetest/application/usermanagement/user/service/UserService.java
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: thezz9
PR: ezcode-my/backend#114
File: src/main/java/org/ezcode/codetest/infrastructure/github/GitHubApiClient.java:159-165
Timestamp: 2025-06-28T02:03:38.654Z
Learning: User thezz9's service (ezcode) targets Korean users exclusively ("찐 한국인밖에 안 옴"), so Korean language hardcoding in commit messages and UI elements is intentional and appropriate for their use case.
src/main/java/org/ezcode/codetest/application/usermanagement/user/service/AdminService.java (2)
Learnt from: NCookies
PR: ezcode-my/backend#17
File: src/main/java/org/ezcode/codetest/presentation/problemmanagement/ProblemAdminController.java:25-25
Timestamp: 2025-06-02T06:57:37.929Z
Learning: 이 프로젝트에서는 아직 Spring Security가 적용되지 않아서 @PreAuthorize 어노테이션이 주석 처리되어 있음. Spring Security 도입 전까지는 권한 검증 어노테이션들이 비활성화 상태임.
Learnt from: chat26666
PR: ezcode-my/backend#67
File: src/main/java/org/ezcode/codetest/domain/game/service/CharacterEquipService.java:26-34
Timestamp: 2025-06-16T16:07:34.354Z
Learning: 이 프로젝트에서는 UseCase 레벨에서 트랜잭션 경계를 관리하므로, 도메인 서비스 클래스들(예: CharacterEquipService)에는 @Transactional 어노테이션이 필요하지 않습니다. 트랜잭션은 UseCase에서 열리므로 데이터 일관성이 보장됩니다.
src/main/java/org/ezcode/codetest/presentation/usermanagement/AdminController.java (1)
Learnt from: NCookies
PR: ezcode-my/backend#17
File: src/main/java/org/ezcode/codetest/presentation/problemmanagement/ProblemAdminController.java:25-25
Timestamp: 2025-06-02T06:57:37.929Z
Learning: 이 프로젝트에서는 아직 Spring Security가 적용되지 않아서 @PreAuthorize 어노테이션이 주석 처리되어 있음. Spring Security 도입 전까지는 권한 검증 어노테이션들이 비활성화 상태임.
src/test/java/org/ezcode/codetest/domain/user/UserDomainServiceTest.java (3)
Learnt from: minjee2758
PR: ezcode-my/backend#43
File: src/main/java/org/ezcode/codetest/domain/user/model/entity/User.java:77-89
Timestamp: 2025-06-10T02:13:33.890Z
Learning: 이 프로젝트에서는 입력 검증을 DTO 레벨에서 수행하고 있으며, User 엔티티의 팩토리 메서드에서는 별도의 입력 검증을 하지 않는다.
Learnt from: chat26666
PR: ezcode-my/backend#67
File: src/main/java/org/ezcode/codetest/domain/game/service/CharacterEquipService.java:26-34
Timestamp: 2025-06-16T16:07:34.354Z
Learning: 이 프로젝트에서는 UseCase 레벨에서 트랜잭션 경계를 관리하므로, 도메인 서비스 클래스들(예: CharacterEquipService)에는 @Transactional 어노테이션이 필요하지 않습니다. 트랜잭션은 UseCase에서 열리므로 데이터 일관성이 보장됩니다.
Learnt from: chat26666
PR: ezcode-my/backend#67
File: src/main/java/org/ezcode/codetest/domain/game/service/GameEncounterDomainService.java:131-134
Timestamp: 2025-06-17T15:06:54.036Z
Learning: GameEncounterDomainService의 getRandomEnemyCharacter 메소드에서 findRandomCharacter 결과가 빈 리스트일 경우에 대한 예외 처리는 불필요함. 시스템에 항상 테스트 계정이 존재하도록 설계되어 있어 빈 결과가 발생하지 않음.
🧬 Code Graph Analysis (1)
src/main/java/org/ezcode/codetest/domain/user/exception/code/AdminExceptionCode.java (1)
src/main/java/org/ezcode/codetest/domain/user/exception/AdminException.java (1)
  • Getter (9-20)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (9)
src/main/java/org/ezcode/codetest/domain/user/exception/code/UserExceptionCode.java (1)

18-19: 관리자 관련 예외 코드 분리 작업이 적절합니다.

관리자 기능을 별도 도메인으로 분리하여 AdminExceptionCode로 이동한 것은 좋은 설계 결정입니다. 도메인 분리 원칙을 잘 따르고 있습니다.

src/main/java/org/ezcode/codetest/application/usermanagement/user/service/AdminService.java (2)

20-20: 트랜잭션 관리 전략을 확인해 주세요.

이 프로젝트에서는 UseCase 레벨에서 트랜잭션을 관리하는 것으로 알고 있는데, AdminService에서 @transactional을 사용하는 것이 적절한지 확인해 주세요.


21-32: 관리자 권한 부여 로직이 잘 구현되었습니다.

자기 자신에게 권한 부여를 방지하고, 이미 관리자인 사용자에 대한 중복 권한 부여를 방지하는 검증 로직이 적절하게 구현되어 있습니다.

src/main/java/org/ezcode/codetest/domain/user/exception/AdminException.java (1)

10-20: 예외 클래스 구조가 적절합니다.

AdminExceptionCode를 활용한 예외 클래스 구조가 잘 설계되어 있습니다.

src/main/java/org/ezcode/codetest/presentation/usermanagement/AdminController.java (2)

25-32: 실제 관리자 권한 검증이 필요합니다.

현재 코드에서는 실제로 요청자가 관리자 권한을 가지고 있는지 검증하지 않습니다. Spring Security 도입 전까지는 어플리케이션 레벨에서 권한 검증을 수행하거나, 향후 적절한 권한 검증 로직을 추가해야 합니다.

현재 인증된 사용자가 실제로 관리자 권한을 가지고 있는지 확인하는 로직을 추가하는 것이 좋습니다:

 @PostMapping("/users/{userId}/grant-admin")
 public ResponseEntity<GrantAdminRoleResponse> grantAdminRole(
     @AuthenticationPrincipal AuthUser authUser,
     @PathVariable Long userId
 ){
+    // 요청자의 관리자 권한 확인
+    if (!authUser.getRole().equals(UserRole.ADMIN)) {
+        throw new AdminException(AdminExceptionCode.INSUFFICIENT_AUTHORITY);
+    }
     return ResponseEntity.status(HttpStatus.OK).body(adminService.grantAdminRole(authUser, userId));
 }

18-23: 컨트롤러 구조가 잘 설계되었습니다.

REST API 설계와 OpenAPI 문서화가 적절하게 구현되어 있습니다.

src/test/java/org/ezcode/codetest/domain/user/UserDomainServiceTest.java (3)

64-79: 테스트 커버리지가 우수합니다.

각 도메인 서비스 메서드에 대해 정상 케이스와 예외 케이스를 모두 테스트하고 있어 높은 품질의 테스트 코드입니다. 특히 예외 처리와 Mock 검증이 적절히 구현되어 있습니다.

Also applies to: 94-106, 108-128, 147-160, 162-173, 184-187, 197-214


1-28: import 구문이 적절히 구성되어 있습니다.

필요한 모든 의존성이 적절히 import되어 있고, 사용하지 않는 import는 보이지 않습니다. 테스트에 필요한 Mockito와 JUnit 5 의존성이 올바르게 설정되어 있습니다.


191-194: 테스트 로직 일관성 검증 완료: 문제 없음

테스트에서 testUser.setReviewToken(5)getReviewToken() 반환값을 설정하고, 도메인 서비스의 decreaseReviewToken 메서드가 동일한 getReviewToken() 값을 기반으로 검증하기 때문에 로직이 완전히 일치합니다. 원래 제안하신 변경은 불필요하니 그대로 두셔도 됩니다.

Likely an incorrect or invalid review comment.

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/test/java/org/ezcode/codetest/domain/user/UserDomainServiceTest.java (1)

190-214: 이전 리뷰에서 지적된 테스트 데이터 일관성 문제가 여전히 존재합니다.

zeroTokenUser를 위한 또 다른 익명 내부 클래스를 생성하고 있어 코드 중복과 일관성 문제가 발생합니다. 테스트용 헬퍼 메서드를 사용하여 개선하세요.

다음과 같이 리팩토링하세요:

+    private User createUserWithReviewToken(int tokenCount) {
+        User user = spy(new User(
+            "[email protected]", "pwd", "user", "nick",
+            28, Tier.NEWBIE, UserRole.USER,
+            false, true, "https://github.com", false
+        ));
+        when(user.getReviewToken()).thenReturn(tokenCount);
+        return user;
+    }

     @Test
     void decreaseReviewToken_shouldThrowWhenNoTokens() {
-        User zeroTokenUser = new User(
-            "[email protected]", "pwd", "user", "nick",
-            28, Tier.NEWBIE, UserRole.USER,
-            false, true, "https://github.com", false
-        ) {
-            public int getReviewToken() {
-                return 0; // Directly return 0 tokens
-            }
-        };
+        User zeroTokenUser = createUserWithReviewToken(0);
🧹 Nitpick comments (1)
src/test/java/org/ezcode/codetest/domain/user/UserDomainServiceTest.java (1)

217-230: 주석 처리된 테스트 코드를 정리하세요.

미완성된 테스트 코드가 주석으로 남아있습니다. 구현할 계획이 있다면 TODO 형태로 남기거나, 불필요하다면 제거하는 것이 좋겠습니다.

다음 중 하나를 선택하여 정리하세요:

-    // 11. 토큰 리셋
-    // @Test
-    // void resetReviewTokensForUsers_shouldUpdateTokens() {
-    //     UsersByWeek users = new UsersByWeek(
-    //         List.of(new User("[email protected]","Aa12345**", "username",
-    //             "[email protected]", 100, Tier.CODER, UserRole.USER, false, true, "gitUrl.com", true)),
-    //         List.of(new User(2L, "[email protected]", "pwd", "User2", false, 0))
-    //     );
-    //
-    //     userDomainService.resetReviewTokensForUsers(users);
-    //
-    //     verify(userRepository).updateReviewTokens(users.fullWeek(), 40);
-    //     verify(userRepository).updateReviewTokens(users.partialWeek(), 20);
-    // }
+    // TODO: resetReviewTokensForUsers 메서드 테스트 구현 필요

또는 완전히 제거:

-    // 11. 토큰 리셋
-    // @Test
-    // void resetReviewTokensForUsers_shouldUpdateTokens() {
-    //     UsersByWeek users = new UsersByWeek(
-    //         List.of(new User("[email protected]","Aa12345**", "username",
-    //             "[email protected]", 100, Tier.CODER, UserRole.USER, false, true, "gitUrl.com", true)),
-    //         List.of(new User(2L, "[email protected]", "pwd", "User2", false, 0))
-    //     );
-    //
-    //     userDomainService.resetReviewTokensForUsers(users);
-    //
-    //     verify(userRepository).updateReviewTokens(users.fullWeek(), 40);
-    //     verify(userRepository).updateReviewTokens(users.partialWeek(), 20);
-    // }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b13d412 and ae0273a.

📒 Files selected for processing (2)
  • src/main/java/org/ezcode/codetest/domain/user/exception/code/AdminExceptionCode.java (1 hunks)
  • src/test/java/org/ezcode/codetest/domain/user/UserDomainServiceTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/org/ezcode/codetest/domain/user/exception/code/AdminExceptionCode.java
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: thezz9
PR: ezcode-my/backend#114
File: src/main/java/org/ezcode/codetest/infrastructure/github/GitHubApiClient.java:159-165
Timestamp: 2025-06-28T02:03:38.654Z
Learning: User thezz9's service (ezcode) targets Korean users exclusively ("찐 한국인밖에 안 옴"), so Korean language hardcoding in commit messages and UI elements is intentional and appropriate for their use case.
src/test/java/org/ezcode/codetest/domain/user/UserDomainServiceTest.java (6)
Learnt from: chat26666
PR: ezcode-my/backend#88
File: src/main/java/org/ezcode/codetest/domain/game/model/character/GameCharacterMatchTokenBucket.java:0-0
Timestamp: 2025-06-21T21:24:57.979Z
Learning: In the GameCharacterMatchTokenBucket class, the user prefers the current "full refill after interval" approach over gradual token refilling. When REFILL_INTERVAL (6 hours) passes, all tokens should be reset to maximum values rather than being refilled progressively.
Learnt from: thezz9
PR: ezcode-my/backend#75
File: src/main/java/org/ezcode/codetest/application/submission/service/SubmissionService.java:142-147
Timestamp: 2025-06-19T07:00:53.895Z
Learning: SubmissionService.getCodeReview() 메서드에서 토큰 차감을 리뷰 요청 전에 수행하는 이유: OpenAI 서버 장애보다 유저 토큰 부족 상황이 더 빈번하므로, 확률이 높은 실패 케이스를 먼저 체크하여 불필요한 처리를 방지함. OpenAI 서버 장애 시에는 OpenAIClient에서 트랜잭션 롤백으로 토큰 복원이 처리됨.
Learnt from: minjee2758
PR: ezcode-my/backend#43
File: src/main/java/org/ezcode/codetest/domain/user/model/entity/User.java:77-89
Timestamp: 2025-06-10T02:13:33.890Z
Learning: 이 프로젝트에서는 입력 검증을 DTO 레벨에서 수행하고 있으며, User 엔티티의 팩토리 메서드에서는 별도의 입력 검증을 하지 않는다.
Learnt from: chat26666
PR: ezcode-my/backend#67
File: src/main/java/org/ezcode/codetest/domain/game/service/CharacterEquipService.java:26-34
Timestamp: 2025-06-16T16:07:34.354Z
Learning: 이 프로젝트에서는 UseCase 레벨에서 트랜잭션 경계를 관리하므로, 도메인 서비스 클래스들(예: CharacterEquipService)에는 @Transactional 어노테이션이 필요하지 않습니다. 트랜잭션은 UseCase에서 열리므로 데이터 일관성이 보장됩니다.
Learnt from: chat26666
PR: ezcode-my/backend#67
File: src/main/java/org/ezcode/codetest/domain/game/service/GameEncounterDomainService.java:131-134
Timestamp: 2025-06-17T15:06:54.036Z
Learning: GameEncounterDomainService의 getRandomEnemyCharacter 메소드에서 findRandomCharacter 결과가 빈 리스트일 경우에 대한 예외 처리는 불필요함. 시스템에 항상 테스트 계정이 존재하도록 설계되어 있어 빈 결과가 발생하지 않음.
Learnt from: minjee2758
PR: ezcode-my/backend#110
File: src/main/java/org/ezcode/codetest/domain/user/service/CustomOAuth2UserService.java:102-112
Timestamp: 2025-06-27T06:03:05.687Z
Learning: `CustomOAuth2UserService`의 `updateGithubUrl` 메서드는 새로운 유저 생성 시나 기존 유저가 새로운 AuthType을 추가할 때만 호출되므로, `UserGithubInfo` 중복 생성 가능성이 없다. 별도의 중복 체크 로직이 불필요하다.
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (11)
src/test/java/org/ezcode/codetest/domain/user/UserDomainServiceTest.java (11)

1-44: 테스트 클래스 구조가 잘 설계되었습니다.

Mockito 기반의 단위 테스트 구조가 올바르게 설정되어 있고, 의존성 주입도 적절히 구성되었습니다.


66-80: 이메일 중복 검사 테스트가 잘 작성되었습니다.

정상 케이스와 예외 케이스 모두 적절히 테스트하고 있으며, Mock을 올바르게 사용하고 있습니다.


82-93: Repository 호출 검증 테스트가 명확합니다.

도메인 서비스가 올바른 Repository 메서드를 호출하는지 확인하는 테스트가 잘 작성되었습니다.


95-107: 사용자 조회 테스트가 완성도 높게 작성되었습니다.

존재하는 사용자와 존재하지 않는 사용자 케이스를 모두 다루고 있어 좋습니다.


109-129: 비밀번호 검증 테스트가 포괄적입니다.

올바른 비밀번호와 틀린 비밀번호 케이스를 모두 테스트하고, 예외 코드까지 검증하고 있어 좋습니다.


131-137: 비밀번호 인코딩 테스트가 간단명료합니다.

Mock을 사용한 인코딩 테스트가 적절히 작성되었습니다.


139-146: 인증 타입 조회 테스트가 올바릅니다.

Expected 값과 실제 반환값을 비교하는 테스트가 정확히 작성되었습니다.


148-161: 비밀번호 비교 테스트가 두 시나리오를 모두 다룹니다.

동일한 비밀번호와 다른 비밀번호 케이스를 모두 테스트하여 완성도가 높습니다.


163-174: 탈퇴 회원 검증 테스트가 적절합니다.

탈퇴한 사용자와 활성 사용자에 대한 검증 로직이 잘 테스트되었습니다.


176-188: 닉네임 생성 테스트가 경계값까지 고려합니다.

성공 케이스와 최대 시도 횟수 초과 시 실패 케이스를 모두 다루어 좋습니다.


233-237: 이메일로 사용자 조회 테스트가 간단명료합니다.

Repository 직접 호출을 테스트하는 간단한 테스트가 잘 작성되었습니다.

Comment on lines +46 to +63
private final User testUser = new User(
"[email protected]",
"hashedPassword",
"testUser",
"TestNick",
30,
Tier.NEWBIE,
UserRole.USER,
false, // isDeleted
true, // verified
"https://github.com/test",
false // gitPushStatus
) {
public Long getId() { return 1L; }
public int getReviewToken() { return 5; }
public int getZeroReviewToken() { return 0; }
};
private final UserAuthType testAuthType = new UserAuthType(testUser, AuthType.EMAIL);
Copy link

@coderabbitai coderabbitai bot Jul 1, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

테스트 데이터 생성 방식의 일관성을 개선하세요.

익명 내부 클래스를 사용하여 테스트 유저를 생성하고 있는데, 이는 199-208라인의 zeroTokenUser와 일관성이 맞지 않습니다. 헬퍼 메서드를 사용하여 통일된 방식으로 테스트 데이터를 생성하는 것이 좋겠습니다.

다음과 같이 헬퍼 메서드를 추가하여 일관성을 개선하세요:

+    private User createTestUserWithReviewToken(int tokenCount) {
+        User user = spy(new User(
+            "[email protected]", "hashedPassword", "testUser", "TestNick",
+            30, Tier.NEWBIE, UserRole.USER,
+            false, true, "https://github.com/test", false
+        ));
+        when(user.getId()).thenReturn(1L);
+        when(user.getReviewToken()).thenReturn(tokenCount);
+        return user;
+    }

-    private final User testUser = new User(
-        "[email protected]",
-        "hashedPassword",
-        "testUser",
-        "TestNick",
-        30,
-        Tier.NEWBIE,
-        UserRole.USER,
-        false,  // isDeleted
-        true,   // verified
-        "https://github.com/test",
-        false   // gitPushStatus
-    ) {
-        public Long getId() { return 1L; }
-        public int getReviewToken() { return 5; }
-        public int getZeroReviewToken() { return 0; }
-    };
+    private final User testUser = createTestUserWithReviewToken(5);
📝 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
private final User testUser = new User(
"[email protected]",
"hashedPassword",
"testUser",
"TestNick",
30,
Tier.NEWBIE,
UserRole.USER,
false, // isDeleted
true, // verified
"https://github.com/test",
false // gitPushStatus
) {
public Long getId() { return 1L; }
public int getReviewToken() { return 5; }
public int getZeroReviewToken() { return 0; }
};
private final UserAuthType testAuthType = new UserAuthType(testUser, AuthType.EMAIL);
// add this helper at the top of your test class
private User createTestUserWithReviewToken(int tokenCount) {
User user = spy(new User(
"[email protected]",
"hashedPassword",
"testUser",
"TestNick",
30,
Tier.NEWBIE,
UserRole.USER,
false, // isDeleted
true, // verified
"https://github.com/test",
false // gitPushStatus
));
when(user.getId()).thenReturn(1L);
when(user.getReviewToken()).thenReturn(tokenCount);
return user;
}
// replace the old anonymous‐subclass instantiation
private final User testUser = createTestUserWithReviewToken(5);
private final UserAuthType testAuthType = new UserAuthType(testUser, AuthType.EMAIL);
🤖 Prompt for AI Agents
In src/test/java/org/ezcode/codetest/domain/user/UserDomainServiceTest.java
around lines 46 to 63, the testUser is created using an anonymous inner class,
which is inconsistent with the zeroTokenUser creation at lines 199-208. Refactor
testUser creation by adding and using a helper method to instantiate User
objects uniformly, ensuring consistent test data creation across the class.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

구차나..

Copy link

Choose a reason for hiding this comment

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

@minjee2758 네, 알겠습니다! 현재 테스트 코드 스타일을 유지하시는 것으로 하겠습니다. 테스트가 잘 작동하고 있으니 괜찮습니다. 🙂


🧠 Learnings used
Learnt from: minjee2758
PR: ezcode-my/backend#43
File: src/main/java/org/ezcode/codetest/domain/user/model/entity/User.java:77-89
Timestamp: 2025-06-10T02:13:33.890Z
Learning: 이 프로젝트에서는 입력 검증을 DTO 레벨에서 수행하고 있으며, User 엔티티의 팩토리 메서드에서는 별도의 입력 검증을 하지 않는다.

Learnt from: chat26666
PR: ezcode-my/backend#67
File: src/main/java/org/ezcode/codetest/domain/game/service/CharacterEquipService.java:26-34
Timestamp: 2025-06-16T16:07:34.354Z
Learning: 이 프로젝트에서는 UseCase 레벨에서 트랜잭션 경계를 관리하므로, 도메인 서비스 클래스들(예: CharacterEquipService)에는 @Transactional 어노테이션이 필요하지 않습니다. 트랜잭션은 UseCase에서 열리므로 데이터 일관성이 보장됩니다.

Learnt from: NCookies
PR: ezcode-my/backend#17
File: src/main/java/org/ezcode/codetest/presentation/problemmanagement/ProblemAdminController.java:25-25
Timestamp: 2025-06-02T06:57:37.929Z
Learning: 이 프로젝트에서는 아직 Spring Security가 적용되지 않아서 @PreAuthorize 어노테이션이 주석 처리되어 있음. Spring Security 도입 전까지는 권한 검증 어노테이션들이 비활성화 상태임.

Learnt from: chat26666
PR: ezcode-my/backend#67
File: src/main/java/org/ezcode/codetest/domain/game/service/GameEncounterDomainService.java:131-134
Timestamp: 2025-06-17T15:06:54.036Z
Learning: GameEncounterDomainService의 getRandomEnemyCharacter 메소드에서 findRandomCharacter 결과가 빈 리스트일 경우에 대한 예외 처리는 불필요함. 시스템에 항상 테스트 계정이 존재하도록 설계되어 있어 빈 결과가 발생하지 않음.

Learnt from: thezz9
PR: ezcode-my/backend#30
File: src/main/java/org/ezcode/codetest/domain/problem/model/dto/SubmissionData.java:42-53
Timestamp: 2025-06-04T13:12:16.729Z
Learning: 사용자 thezz9는 개발 시 기능적 정확성을 먼저 달성한 후 세부 리팩터링을 나중에 하는 접근 방식을 선호한다. 테스트 단계에서는 하드코딩된 값도 허용한다.

Learnt from: thezz9
PR: ezcode-my/backend#30
File: src/main/java/org/ezcode/codetest/application/submission/service/SubmissionService.java:44-46
Timestamp: 2025-06-04T13:12:17.636Z
Learning: SubmissionService에서 "2 10" 입력값과 "12" 기대출력이 하드코딩되어 있는 것은 테스트 단계의 의도적인 구현이며, 추후 Problem 엔티티의 실제 테스트케이스로 대체 예정입니다.

Learnt from: chat26666
PR: ezcode-my/backend#64
File: src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/game/RandomEncounterRepositoryImpl.java:10-16
Timestamp: 2025-06-15T04:37:22.609Z
Learning: chat26666은 Repository 구현체를 만들 때 뼈대(skeleton)를 먼저 생성하고 나중에 메서드를 구현하는 개발 방식을 사용한다. 이런 경우 아직 미구현 상태인 것이 의도적인 것일 수 있다.

Learnt from: thezz9
PR: ezcode-my/backend#114
File: src/main/java/org/ezcode/codetest/infrastructure/github/GitHubApiClient.java:159-165
Timestamp: 2025-06-28T02:03:38.654Z
Learning: User thezz9's service (ezcode) targets Korean users exclusively ("찐 한국인밖에 안 옴"), so Korean language hardcoding in commit messages and UI elements is intentional and appropriate for their use case.

@minjee2758 minjee2758 closed this Jul 2, 2025
@minjee2758 minjee2758 reopened this Jul 2, 2025
@minjee2758 minjee2758 merged commit 7ddb651 into dev Jul 2, 2025
2 checks passed
@minjee2758 minjee2758 deleted the feature/admin branch July 2, 2025 01:36
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