Feat: 비밀번호 초기화 시 인증코드 전송 로직 분리#247#249
Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR separates email verification endpoints for user signup and password reset, introduces new generator classes for verification codes and nicknames, and updates corresponding tests.
- Updated email API endpoints and test cases to distinguish between signup and password reset verification flows.
- Introduced VerificationCodeGenerator and NicknameGenerator to replace legacy random generation logic.
- Updated service, acceptance tests, and API controllers to accommodate these changes.
Reviewed Changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| EmailCommandUseCaseTest.java | Updated test to call sendSignupVerificationEmail instead of sendVerificationEmail. |
| VerificationCodeGeneratorTest.java | Added tests validating the new six-digit verification code generation. |
| RandomGeneratorTest.java | Reused tests with minor adjustments for generatePositiveNumber logic. |
| NicknameGeneratorTest.java | Added tests to verify nickname generation using the new NicknameGenerator. |
| UserAcceptanceTest.java | Updated email verification steps to call the new signup endpoint. |
| EmailStep.java | Renamed methods to differentiate between signup and password reset email requests. |
| EmailAcceptanceTest.java | Refactored tests to cover both signup and password reset email verification scenarios. |
| UserCommandService.java | Changed nickname generation to use NicknameGenerator.generateNickname. |
| EmailCommandService.java | Separated signup and password reset email verification processing and added input validation. |
| EmailCommandUseCase.java | Updated interface with new method signatures for email verification. |
| EmailCommandApiV2.java | Added a new endpoint for password reset email verification with JWT validation. |
| VerificationCodeGenerator.java | Introduced a new generator class for verification codes using RandomGenerator. |
| RandomGenerator.java | Removed nickname generation logic; added generatePositiveNumber for controlled random numbers. |
| NicknameGenerator.java | Added a new generator class for nicknames based on a random index and a fixed prefix array. |
| } | ||
|
|
||
| private static String pickRandomNicknamePrefix() { | ||
| int index = RandomGenerator.generatePositiveNumber(NICKNAME_PREFIXES.length); |
There was a problem hiding this comment.
Using generatePositiveNumber to select an array index results in a range of [1, length-1] for bounds greater than 1, which skips the first prefix and may lead to an off-by-one error. Consider using a 0-indexed random generator to correctly cover the full array range.
zbqmgldjfh
left a comment
There was a problem hiding this comment.
2부분 정도 고민해볼만 한 부분 남겨두었습니다~~
| String nickname = ""; | ||
| do { | ||
| nickname = RandomGenerator.generateRandomNickname(6); | ||
| nickname = NicknameGenerator.generateNickname(); |
There was a problem hiding this comment.
지금의 방식은 계속 한번씩 생성하면서 확인하는 방식인데, 혹시 한번에 한 5개 정도를 생성하고, 존제하지 않는 값만 리턴받아 그중 하나를 사용하면 어떨가요?
n번의 쿼리가 발생할 수 있는 지점인것 같아, 조금 더 사이즈를 크게 한번에 물어봐도 될것 같아요.
(DB : A, B)
닉네임 랜덤 생성 -> (A, B, C, D, E) -> DB 에 subquery로 not exsist만 list로 반환하도록
DB가 (C, D, E) 반환 -> 이중 암거나 사용
There was a problem hiding this comment.
대충 다음같은 느낌으로 QueryDsl로 동적 쿼리 만들어 주면 될듯요!
@Query("SELECT n FROM Nickname n WHERE n.nickname NOT IN (SELECT u.nickname FROM User u WHERE u.nickname IN :nicknames)")
List<String> findAvailableNicknames(@Param("nicknames") List<String> nicknames);전체 코드는 대충 다음같은 느낌
private String createNickname() {
final int BATCH_SIZE = 10;
while (true) {
List<String> candidates = new ArrayList<>();
for (int i = 0; i < BATCH_SIZE; i++) {
candidates.add(NicknameGenerator.generateNickname());
}
// DB에 존재하지 않는 닉네임 목록 조회
List<String> availableNicknames = userQueryPort.findNonExistingNicknames(candidates);
// 하나라도 존재하지 않는 닉네임이 있다면 반환
if (!availableNicknames.isEmpty()) {
return availableNicknames.get(0);
}
// 없으면 다음 배치 시도
}
}There was a problem hiding this comment.
당연한 부분인데 확률이 낮다고 생각해서 너무 가볍게 생각했던거 같습니다!
말씀해주신대로 미리 일정 개수 정해두고 한번에 체크해보는게 더 좋을거 같습니다!
반영해서 수정해볼게요~~!!😀
| assertThat(nickname).isNotNull(); | ||
| assertThat(nickname).isNotEmpty(); | ||
|
|
||
| boolean isMatch = false; |
There was a problem hiding this comment.
정규 표현식 사용은 어떤가요?
// 접두사 목록을 정규식으로 결합
String regex = "^(Cool|Happy|Smart)\d{6}$";
assertThat(nickname).matches(regex);
There was a problem hiding this comment.
너무 좋은 방법인거같습니닷
수정해서 올려보겠습니다!
|
변경사항
추가 수정
관련 |
|
|
||
| static { | ||
| chroma = new ChromaDBContainer(DockerImageName.parse("chromadb/chroma:latest")) | ||
| .waitingFor(Wait.forHttp("/api/v2/heartbeat")) |
There was a problem hiding this comment.
chroma 1.0.0 버전업에 따른 testcontainers 수정
위 내용을 이제 봤는데 testcontainers 버전을 올렸으면 쉽게 해결됐을거같네유 하핫 🥲
* feat : 비밀번호 초기화 인증 코드 전송 API 분리 * feat : RandomGenerator 랜덤 양수 생성 메서드 추가 및 닉네임 생성 로직 제거 * feat : NicknameGenerator 추가 * feat : VerificationCodeGenerator 추가 * refactor : 회원가입 시 닉네임 생성 시 NicknameGenerator 사용하도록 변경 * test : 비밀번호 초기화 이메일 인증코드 전송 인수 테스트 추가 * test : 비밀번호 초기화 이메일 인증코드 전송 인수 테스트 추가 * test : Generator 클래스 테스트 추가 * fix : 닉네임 생성 시 닉네임 생성 안되는 이슈 해결 * test : 랜덤 양수 생성 테스트 제거 * feat : 존재하는 닉네임 조회 PersistenceAdapter 로직 추가 * refactor : 닉네임 생성 시 한번에 일정 개수 생성 후 DB 비교 로직 추가 * test : 정규식 사용하여 테스트 하도록 변경 * fix : 통합 테스트 시 ChromaDB 컨테이너 동작 확인 heartbeat API 변경 * feat : RootUserQueryRepository 추가 (cherry picked from commit ef61606)



구현
password-reset과signup으로 구분하여 회원가입 시와 비밀번호 초기화 시 사용하는 API를 분리했습니다.