-
Notifications
You must be signed in to change notification settings - Fork 3
feat : 닉네임 한글로 랜덤 생성 #56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Caution Review failedThe pull request is closed. """ WalkthroughOAuth2 사용자 생성 시 별명을 자동으로 생성하고, 중복되지 않는 별명인지 검증하는 기능이 추가되었습니다. 이를 위해 별명 생성을 위한 형용사와 명사 enum이 도입되었고, 별명 존재 여부를 확인하는 메서드가 저장소 계층에 추가되었습니다. User 엔터티의 팩토리 메서드 시그니처도 변경되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant OAuth2UserService
participant UserDomainService
participant UserRepository
OAuth2UserService->>UserRepository: findByEmail(email)
alt User not found
OAuth2UserService->>UserDomainService: generateUniqueNickname()
UserDomainService->>UserRepository: existsByNickname(nickname) (최대 1천만회 반복)
UserDomainService-->>OAuth2UserService: unique nickname 반환
OAuth2UserService->>User: googleUser(email, username, nickname)
OAuth2UserService->>UserRepository: save(user)
else User exists
OAuth2UserService-->>OAuth2UserService: 기존 유저 반환
end
Possibly related PRs
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this 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 (8)
src/main/java/org/ezcode/codetest/domain/user/model/enums/Noun.java (1)
3-14: Enum 상수의 표기·타이포 확인 필요
- Java 코딩 컨벤션상 enum 상수는 대문자·언더스코어로 작성하는 것이 일반적입니다. 한글로 작성해도 컴파일은 되지만, 혼합 언어 사용 시 IDE 검색·정렬·리팩터링 지원이 떨어집니다. 팀 컨벤션을 한 번 더 확인해주세요.
- 7행
다람이는 일반적으로 ‘다람쥐’의 오타로 보입니다. 타이포인지 의도된 별칭인지 검토 바랍니다.- 다람이 + 다람쥐 // 또는 의도한 다른 동물명으로 수정src/main/java/org/ezcode/codetest/domain/user/model/enums/Adjective.java (1)
3-14: Enum 상수 네이밍 컨벤션 일관성
Noun과 동일하게 모든 상수가 한글 소문자로 구성되어 있습니다. 코드스타일 규칙(예: GOOGLE JAVA STYLE)에서는멋있는→멋있는과 같이 대문자·언더스코어로 표기(MEOT_IT_NEUN)하도록 권장합니다.
팀 내부 규칙이 없다면 추후 영문/숫자 혼합 프로젝트에서의 혼란을 줄이기 위해 컨벤션을 정의해 두시는 편이 좋습니다.src/main/java/org/ezcode/codetest/domain/user/repository/UserRepository.java (1)
18-21:existsByNickname추가 👍 — Nullable 방어만 검토메서드 자체는 필요한 기능을 깔끔히 추가했습니다. 다만 외부 호출자가
null을 전달할 여지가 있으면 NPE 대신IllegalArgumentException등으로 방어하거나, 파라미터에@NonNull/@NotBlank어노테이션을 붙여 명시해두면 좋겠습니다.src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/user/UserJpaRepository.java (1)
14-14: 닉네임 컬럼에 Unique Index 권장
existsByNickname빈번 호출 시 풀스캔을 피하려면 DB 레벨에서nickname컬럼에 UNIQUE + INDEX를 동시에 걸어두는 것이 좋습니다.
JPA 스키마 자동 생성 중이라면 Entity 쪽에@Column(unique = true)나@Index(columnList = "nickname")추가를 검토해주세요.src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/user/UserRepositoryImpl.java (1)
41-44: 읽기 전용 트랜잭션 플래그 추가 고려단순 존재 여부 조회는 쓰기 작업이 없으므로
@Transactional(readOnly = true)를 붙여주면 불필요한 flush 체크를 피할 수 있습니다. 다른 조회 메서드에도 동일 규칙 적용을 검토해주세요.
src/main/java/org/ezcode/codetest/domain/user/service/UserDomainService.java (3)
45-47: 불필요한 이중 세미콜론 제거
orElseThrow(...);;처럼 세미콜론이 두 번 들어가 있습니다. 컴파일에는 영향이 없지만 가독성을 떨어뜨립니다.- .orElseThrow(() -> new AuthException(AuthExceptionCode.USER_NOT_FOUND));; + .orElseThrow(() -> new AuthException(AuthExceptionCode.USER_NOT_FOUND));
74-82: 닉네임 중복 검사 루프 한계 및 동시성 이슈
- 최대 1,000만 회 루프는 최악의 경우 긴 지연을 유발할 수 있습니다.
- DB
UNIQUE제약만으로도 동시성 중복을 완전히 막을 수 없으므로, 생성 → INSERT 시 충돌이 나면 재시도하는 방식이 더 안전합니다.for (int i = 0; i < MAX_RETRY; i++) { String nickname = generateRandomNickname(); try { userRepository.createNickname(nickname); // 닉네임만 삽입 (unique key) return nickname; } catch (DuplicateKeyException ignored) { // 충돌 → 재시도 } } throw new IllegalStateException("닉네임 생성 실패");
84-89: 닉네임 구성 가독성 개선
adjective.name() + noun.name() + number로 연결하면 숫자가 1자리일 때...호랑이3처럼 가독성이 떨어집니다.
다음과 같이 구분자와 0-padding을 추가하면 사용자 경험이 좋아집니다.-return adjective.name() + noun.name() + number; +return String.format("%s%s%03d", adjective.name(), noun.name(), number);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/main/java/org/ezcode/codetest/domain/user/model/entity/User.java(1 hunks)src/main/java/org/ezcode/codetest/domain/user/model/enums/Adjective.java(1 hunks)src/main/java/org/ezcode/codetest/domain/user/model/enums/Noun.java(1 hunks)src/main/java/org/ezcode/codetest/domain/user/repository/UserRepository.java(1 hunks)src/main/java/org/ezcode/codetest/domain/user/service/CustomOAuth2UserService.java(2 hunks)src/main/java/org/ezcode/codetest/domain/user/service/UserDomainService.java(1 hunks)src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/user/UserJpaRepository.java(1 hunks)src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/user/UserRepositoryImpl.java(1 hunks)
| String nickname = userDomainService.generateUniqueNickname(); | ||
| User newUser = User.googleUser(oAuth2Response.getEmail(), username, nickname); | ||
| log.info("newUser: {} 새로운 유저", newUser); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
닉네임 생성 실패 시 예외 유형 매핑 필요
userDomainService.generateUniqueNickname() 내부에서 IllegalStateException이 발생할 수 있는데, 현재 메서드에서는 그대로 전파되어 OAuth2AuthenticationException으로 래핑되지 않습니다.
OAuth 흐름에서 발생하는 모든 예외를 OAuth2AuthenticationException으로 맞춰두면 필터 단계에서 일관되게 처리할 수 있으므로, 아래와 같이 예외 매핑을 권장합니다.
try {
+ String nickname = userDomainService.generateUniqueNickname();
+ User newUser = User.googleUser(oAuth2Response.getEmail(), username, nickname);
+ userRepository.createUser(newUser);
- String nickname = userDomainService.generateUniqueNickname();
- User newUser = User.googleUser(oAuth2Response.getEmail(), username, nickname);
- userRepository.createUser(newUser);
} catch (IllegalStateException e) {
log.error("중복 닉네임 생성 실패 : {}", e.getMessage());
throw new OAuth2AuthenticationException("닉네임 생성 실패입니다");
} catch (Exception e) {
...
}generateUniqueNickname 메서드 정의와 CustomOAuth2UserService 내 호출 부분을 확인하기 위해 아래 스크립트를 실행하겠습니다.
🏁 Script executed:
#!/bin/bash
set -e
echo "=== generateUniqueNickname 정의 위치 및 예외 선언 확인 ==="
rg -n "generateUniqueNickname" -C3 src
echo ""
echo "=== CustomOAuth2UserService 내 호출 위치 및 예외 처리 현황 ==="
rg -n "generateUniqueNickname" -C10 src/main/java/org/ezcode/codetest/domain/user/service/CustomOAuth2UserService.javaLength of output: 2724
generateUniqueNickname 메서드의 구현 전체와 IllegalStateException 발생 지점을 확인하기 위해 아래 스크립트를 실행하겠습니다.
🏁 Script executed:
#!/bin/bash
set -e
echo "=== generateUniqueNickname 전체 구현 확인 ==="
rg -n "public String generateUniqueNickname" -C20 src/main/java/org/ezcode/codetest/domain/user/service/UserDomainService.java
echo ""
echo "=== IllegalStateException throw 여부 확인 ==="
rg -n "throw new IllegalStateException" -C2 src/main/java/org/ezcode/codetest/domain/user/service/UserDomainService.javaLength of output: 1814
닉네임 생성 실패 예외 매핑 추가 필요
UserDomainService.generateUniqueNickname()는 1천만 번 시도 후에도 고유 닉네임을 찾지 못하면
IllegalStateException("중복된 닉네임 생성 불가")를 던집니다.
현재 CustomOAuth2UserService에서는 이 예외가 try 블록 바깥에 있어 필터 단계에서 일관된 OAuth2AuthenticationException 처리 경로를 타지 못합니다.
아래처럼 try 범위를 확장해 IllegalStateException을 별도로 잡아 OAuth2AuthenticationException으로 변환해 주세요.
- 대상 파일:
src/main/java/org/ezcode/codetest/domain/user/service/CustomOAuth2UserService.java (54~64행)
@@ if (findUser == null) {
- String nickname = userDomainService.generateUniqueNickname();
- User newUser = User.googleUser(oAuth2Response.getEmail(), username, nickname);
- log.info("newUser: {} 새로운 유저", newUser);
- try {
- userRepository.createUser(newUser);
- } catch (Exception e) {
- log.error("OAuth 사용자 생성 실패 : {}", e.getMessage());
- throw new OAuth2AuthenticationException("사용자 생성 실패입니다");
- }
+ try {
+ String nickname = userDomainService.generateUniqueNickname();
+ User newUser = User.googleUser(oAuth2Response.getEmail(), username, nickname);
+ log.info("newUser: {} 새로운 유저", newUser);
+ userRepository.createUser(newUser);
+ } catch (IllegalStateException e) {
+ log.error("중복 닉네임 생성 실패 : {}", e.getMessage());
+ throw new OAuth2AuthenticationException("닉네임 생성 실패입니다");
+ } catch (Exception e) {
+ log.error("OAuth 사용자 생성 실패 : {}", e.getMessage());
+ throw new OAuth2AuthenticationException("사용자 생성 실패입니다");
+ }위 변경을 통해 닉네임 생성 실패 시에도 OAuth2 필터 단계에서 일관된 예외 처리 흐름이 보장됩니다.
📝 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.
| String nickname = userDomainService.generateUniqueNickname(); | |
| User newUser = User.googleUser(oAuth2Response.getEmail(), username, nickname); | |
| log.info("newUser: {} 새로운 유저", newUser); | |
| if (findUser == null) { | |
| try { | |
| String nickname = userDomainService.generateUniqueNickname(); | |
| User newUser = User.googleUser(oAuth2Response.getEmail(), username, nickname); | |
| log.info("newUser: {} 새로운 유저", newUser); | |
| userRepository.createUser(newUser); | |
| } catch (IllegalStateException e) { | |
| log.error("중복 닉네임 생성 실패 : {}", e.getMessage()); | |
| throw new OAuth2AuthenticationException("닉네임 생성 실패입니다"); | |
| } catch (Exception e) { | |
| log.error("OAuth 사용자 생성 실패 : {}", e.getMessage()); | |
| throw new OAuth2AuthenticationException("사용자 생성 실패입니다"); | |
| } | |
| } |
🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/domain/user/service/CustomOAuth2UserService.java
around lines 54 to 64, the call to userDomainService.generateUniqueNickname()
can throw IllegalStateException which is not currently caught and wrapped as
OAuth2AuthenticationException. To fix this, expand the try block to include the
nickname generation call and catch IllegalStateException separately, then wrap
and rethrow it as an OAuth2AuthenticationException. This ensures consistent
exception handling in the OAuth2 filter layer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
합당한데?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pokerbearkr 말씀해주신 대로 예외 매핑을 적용하도록 하겠습니다. 아래 계획대로 CustomOAuth2UserService 에 try-catch 블록을 확장하여 IllegalStateException → OAuth2AuthenticationException 으로 변환하는 코드를 반영하겠습니다. 확인 후 진행해도 괜찮을지 알려주세요!
• CustomOAuth2UserService 의 findUser == null 분기 내 로직을 try-catch 블록으로 감싸고,
IllegalStateException 을 별도로 잡아 OAuth2AuthenticationException("닉네임 생성 실패입니다") 로 래핑
→ OAuth2 필터 단계에서 일관된 예외 처리 보장
</plan_code_changes>
⏳ Preparing changes...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A summary of the edits CodeRabbit can apply:
CustomOAuth2UserService.java will be updated so that nickname generation and user creation are executed inside a try-catch block which converts IllegalStateException to an OAuth2AuthenticationException, ensuring consistent OAuth error handling.
A plan of each step that CodeRabbit will take in order to execute the edits for each file (with inline rough draft snippets):
✏️ src/main/java/org/ezcode/codetest/domain/user/service/CustomOAuth2UserService.java
Delete the current block spanning lines 55-63 (the standalone nickname generation, new User creation, and single Exception catch).
Insert the following replacement starting at line 55:\njava\n try {\n String nickname = userDomainService.generateUniqueNickname();\n User newUser = User.googleUser(oAuth2Response.getEmail(), username, nickname);\n log.info(\"newUser: {} 새로운 유저\", newUser);\n userRepository.createUser(newUser);\n } catch (IllegalStateException e) {\n log.error(\"중복 닉네임 생성 실패 : {}\", e.getMessage());\n throw new OAuth2AuthenticationException(\"닉네임 생성 실패입니다\");\n } catch (Exception e) {\n log.error(\"OAuth 사용자 생성 실패 : {}\", e.getMessage());\n throw new OAuth2AuthenticationException(\"사용자 생성 실패입니다\");\n }\n
No additional imports are necessary because IllegalStateException is part of java.lang; ensure existing imports remain untouched.
Re-compile and run the OAuth flow (or unit tests that simulate nickname collision) to verify IllegalStateException is now translated into OAuth2AuthenticationException and handled uniformly by the filter layer.
- ✅ Create PR with these edits
- 📌 Create commit in current branch
- 📋 Get copyable edits
| public static User googleUser(String email, String username, String nickname){ | ||
| return User.builder() | ||
| .email(email) | ||
| .username(username) | ||
| .authType(AuthType.GOOGLE) | ||
| .nickname("user_" + UUID.randomUUID().toString().split("-")[0])//닉네임은 자동으로 생성해주고, 나중에 수정할 수 있도록 함 | ||
| .nickname(nickname)//닉네임은 자동으로 생성해주고, 나중에 수정할 수 있도록 함 | ||
| .tier(Tier.NEWBIE) | ||
| .role(UserRole.USER) | ||
| .isDeleted(false) | ||
| .password(UUID.randomUUID().toString()) | ||
| .build(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
랜덤 비밀번호 평문 저장은 보안 위험
OAuth 가입 시 password(UUID.randomUUID().toString())로 무작위 문자열을 그대로 저장하고 있습니다.
비밀번호를 사용하지 않는 계정이라면 NULL 처리하거나, 최소한 PasswordEncoder로 해싱한 값을 저장하여 평문 노출을 방지해주세요.
- .password(UUID.randomUUID().toString())
+ // OAuth 계정은 비밀번호 미사용 → NULL 처리
+ .password(null)또는,
- .password(UUID.randomUUID().toString())
+ .password(PasswordEncoderFactories.createDelegatingPasswordEncoder()
+ .encode(UUID.randomUUID().toString()))Also applies to: 107-118
🤖 Prompt for AI Agents
In src/main/java/org/ezcode/codetest/domain/user/model/entity/User.java around
lines 94 to 104 and 107 to 118, the code stores a random password as plain text
for OAuth users, which is a security risk. To fix this, either set the password
field to null if it is not used or encode the random password using
PasswordEncoder before saving it to avoid storing plain text passwords.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
알아서할게 토끼야
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Kimminu7 알겠습니다! 필요하시면 언제든지 말씀해 주세요.
작업 내용
변경 사항
트러블 슈팅
해결해야 할 문제
참고 사항
코드 리뷰 전 확인 체크리스트
type :)Summary by CodeRabbit
신규 기능
기타