✨ Feat: 회원가입 기능 개선 (관심 종목 선택, 아이디 중복 체크 API 추가)#74
Conversation
이메일 → 아이디 방식으로 변경됨에 따라 @Email 검증 어노테이션 및 관련 import 제거, Swagger 설명/예시 수정
개요사용자 회원가입 기능을 개선하는 변경사항으로, 아이디 중복 확인 엔드포인트를 추가하고, 회원가입 요청에 관심 종목 필드를 도입하며, 이메일 기반 아이디에서 일반 아이디로 전환합니다. 변경사항
예상 코드 리뷰 난이도🎯 3 (보통) | ⏱️ ~20분 추천 검토자
시
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
src/main/java/com/be/sportizebe/domain/user/dto/request/SignUpRequest.java (2)
12-14: username 필드에 길이 또는 패턴 검증 추가 고려이메일 형식 제약이 제거되었으므로,
username에 대한 길이 제한(예:@Size(min=4, max=20)) 또는 허용 문자 패턴(예:@Pattern(regexp="^[a-zA-Z0-9_]+$")) 검증을 추가하는 것이 좋습니다. 이를 통해 악의적이거나 부적절한 입력을 방지할 수 있습니다.🛡️ 검증 추가 제안
- `@Schema`(description = "사용자 아이디", example = "sportize_user") - `@NotBlank`(message = "아이디를 입력해주세요.") + `@Schema`(description = "사용자 아이디", example = "sportize_user") + `@NotBlank`(message = "아이디를 입력해주세요.") + `@Size`(min = 4, max = 20, message = "아이디는 4자 이상 20자 이하여야 합니다.") + `@Pattern`(regexp = "^[a-zA-Z0-9_]+$", message = "아이디는 영문, 숫자, 밑줄(_)만 사용할 수 있습니다.") String username,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/be/sportizebe/domain/user/dto/request/SignUpRequest.java` around lines 12 - 14, Add explicit length and character-pattern validation to the SignUpRequest.username field: annotate the existing String username in SignUpRequest with a size constraint (e.g. `@Size`(min=4, max=20)) and a pattern constraint (e.g. `@Pattern` with a regex like "^[a-zA-Z0-9_]+$") and provide clear validation messages so blank/too-short/too-long or disallowed-character inputs are rejected; keep the existing `@NotBlank` and update the `@Schema` example/description if needed to reflect the allowed format.
32-33: 관심 종목 목록 크기 제한 검토
interestSports필드에 대한 크기 제한이 없습니다.SportTypeenum이 현재 3개 값(SOCCER, BASKETBALL, BADMINTON)만 가지고 있으므로 큰 문제는 아니지만, 향후 확장성을 고려하여@Size(max = 10)등의 제한을 추가하면 좋습니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/be/sportizebe/domain/user/dto/request/SignUpRequest.java` around lines 32 - 33, The interestSports field in SignUpRequest lacks a size constraint; add a validation limit (e.g., `@Size`(max = 10)) to the List<SportType> interestSports declaration in the SignUpRequest DTO, import the corresponding validation annotation (javax.validation.constraints.Size) and ensure the field remains a List<SportType> so the validator enforces the maximum number of selected sports while keeping compatibility with the SportType enum.src/main/java/com/be/sportizebe/domain/user/controller/UserController.java (1)
30-30: 구현체 대신 인터페이스 주입 권장
UserServiceImpl대신UserService인터페이스를 주입하는 것이 DI 원칙에 부합합니다. 이는 테스트 용이성과 유연성을 높여줍니다.♻️ 인터페이스 주입으로 변경
- private final UserServiceImpl userService; + private final UserService userService;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/be/sportizebe/domain/user/controller/UserController.java` at line 30, The controller is injecting the concrete class UserServiceImpl via the field userService; change the field and constructor parameter types to the UserService interface (e.g., replace UserServiceImpl userService with UserService userService in UserController), update the import to the interface, and ensure any `@Autowired` or constructor injection remains intact so Spring will wire the implementation; adjust unit tests/mocks to reference UserService instead of UserServiceImpl.src/main/java/com/be/sportizebe/domain/user/service/UserServiceImpl.java (1)
125-128: 입력 검증 추가 고려
username파라미터가 null이거나 빈 문자열인 경우에 대한 검증이 없습니다. 불필요한 DB 쿼리를 방지하고 명확한 응답을 제공하기 위해 입력 검증을 추가하는 것이 좋습니다.🛡️ 입력 검증 추가 제안
`@Override` public boolean checkUsernameDuplicate(String username) { + if (username == null || username.isBlank()) { + return false; // 또는 IllegalArgumentException throw + } return userRepository.existsByUsername(username); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/be/sportizebe/domain/user/service/UserServiceImpl.java` around lines 125 - 128, Add input validation to checkUsernameDuplicate: if the incoming username is null or blank (e.g. username == null || username.trim().isEmpty() or using StringUtils.hasText), throw an IllegalArgumentException with a clear message instead of calling userRepository.existsByUsername; otherwise call userRepository.existsByUsername(username). This prevents unnecessary DB queries and gives a clear response for invalid input while keeping the method name checkUsernameDuplicate and usage of userRepository.existsByUsername intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/main/java/com/be/sportizebe/domain/user/controller/UserController.java`:
- Around line 32-39: The check-username GET endpoint is blocked by the current
SecurityConfig matcher ordering; update SecurityConfig so the public user
endpoints are explicitly permitted before the catch-all authenticated rule: add
a requestMatchers("/api/users/check-username").permitAll() (and ensure it
appears before requestMatchers("/api/users/**").authenticated()), keeping
existing requestMatchers("/api/users/signup").permitAll() and the HttpMethod.GET
"/api/**" permitAll rule positioned appropriately; verify the
UserController.checkUsernameDuplicate mapping remains GET
/api/users/check-username and test unauthenticated access.
---
Nitpick comments:
In `@src/main/java/com/be/sportizebe/domain/user/controller/UserController.java`:
- Line 30: The controller is injecting the concrete class UserServiceImpl via
the field userService; change the field and constructor parameter types to the
UserService interface (e.g., replace UserServiceImpl userService with
UserService userService in UserController), update the import to the interface,
and ensure any `@Autowired` or constructor injection remains intact so Spring will
wire the implementation; adjust unit tests/mocks to reference UserService
instead of UserServiceImpl.
In `@src/main/java/com/be/sportizebe/domain/user/dto/request/SignUpRequest.java`:
- Around line 12-14: Add explicit length and character-pattern validation to the
SignUpRequest.username field: annotate the existing String username in
SignUpRequest with a size constraint (e.g. `@Size`(min=4, max=20)) and a pattern
constraint (e.g. `@Pattern` with a regex like "^[a-zA-Z0-9_]+$") and provide clear
validation messages so blank/too-short/too-long or disallowed-character inputs
are rejected; keep the existing `@NotBlank` and update the `@Schema`
example/description if needed to reflect the allowed format.
- Around line 32-33: The interestSports field in SignUpRequest lacks a size
constraint; add a validation limit (e.g., `@Size`(max = 10)) to the
List<SportType> interestSports declaration in the SignUpRequest DTO, import the
corresponding validation annotation (javax.validation.constraints.Size) and
ensure the field remains a List<SportType> so the validator enforces the maximum
number of selected sports while keeping compatibility with the SportType enum.
In `@src/main/java/com/be/sportizebe/domain/user/service/UserServiceImpl.java`:
- Around line 125-128: Add input validation to checkUsernameDuplicate: if the
incoming username is null or blank (e.g. username == null ||
username.trim().isEmpty() or using StringUtils.hasText), throw an
IllegalArgumentException with a clear message instead of calling
userRepository.existsByUsername; otherwise call
userRepository.existsByUsername(username). This prevents unnecessary DB queries
and gives a clear response for invalid input while keeping the method name
checkUsernameDuplicate and usage of userRepository.existsByUsername intact.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 724495db-39a9-4665-bfd3-f4c0e0935206
📒 Files selected for processing (6)
src/main/java/com/be/sportizebe/domain/user/controller/UserController.javasrc/main/java/com/be/sportizebe/domain/user/dto/request/SignUpRequest.javasrc/main/java/com/be/sportizebe/domain/user/dto/response/SignUpResponse.javasrc/main/java/com/be/sportizebe/domain/user/entity/User.javasrc/main/java/com/be/sportizebe/domain/user/service/UserService.javasrc/main/java/com/be/sportizebe/domain/user/service/UserServiceImpl.java
| @GetMapping("/check-username") | ||
| @Operation(summary = "아이디 중복 체크", description = "사용 가능하면 false, 이미 사용 중이면 true 반환") | ||
| public ResponseEntity<BaseResponse<Boolean>> checkUsernameDuplicate( | ||
| @RequestParam String username | ||
| ) { | ||
| boolean isDuplicate = userService.checkUsernameDuplicate(username); | ||
| return ResponseEntity.ok(BaseResponse.success("아이디 중복 체크 성공", isDuplicate)); | ||
| } |
There was a problem hiding this comment.
보안 설정으로 인해 엔드포인트 접근 불가 - 수정 필요
SecurityConfig.java의 설정에서 .requestMatchers("/api/users/**").authenticated()가 .requestMatchers(HttpMethod.GET, "/api/**").permitAll() 보다 먼저 평가됩니다. 따라서 /api/users/check-username 엔드포인트는 인증되지 않은 사용자에게 401을 반환하여, 회원가입 전 아이디 중복 체크 목적을 달성할 수 없습니다.
SecurityConfig.java에서 해당 엔드포인트를 명시적으로 허용해야 합니다:
.requestMatchers("/api/users/check-username").permitAll() // 이 줄 추가
.requestMatchers("/api/users/signup").permitAll()
.requestMatchers("/api/users/**").authenticated()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/main/java/com/be/sportizebe/domain/user/controller/UserController.java`
around lines 32 - 39, The check-username GET endpoint is blocked by the current
SecurityConfig matcher ordering; update SecurityConfig so the public user
endpoints are explicitly permitted before the catch-all authenticated rule: add
a requestMatchers("/api/users/check-username").permitAll() (and ensure it
appears before requestMatchers("/api/users/**").authenticated()), keeping
existing requestMatchers("/api/users/signup").permitAll() and the HttpMethod.GET
"/api/**" permitAll rule positioned appropriately; verify the
UserController.checkUsernameDuplicate mapping remains GET
/api/users/check-username and test unauthenticated access.
#️⃣ Issue Number
📝 요약(Summary)
회원가입 기능 개선을 위해 다음 사항을 반영했습니다.
GET /api/users/check-username)이를 통해 사용자가 이메일 형식이 아닌 일반 아이디로 회원가입할 수 있도록 개선하고,
회원가입 전 아이디 중복 여부를 확인할 수 있도록 기능을 추가했습니다.
🛠️ PR 유형
어떤 변경 사항이 있나요?
📸스크린샷 (선택)
없음
💬 공유사항 to 리뷰어
✅ PR Checklist
PR이 다음 요구 사항을 충족하는지 확인하세요.
Summary by CodeRabbit
Release Notes
New Features
Documentation