Skip to content

✨ Feat: 회원가입 기능 개선 (관심 종목 선택, 아이디 중복 체크 API 추가)#74

Merged
angoroa merged 3 commits intodevelopfrom
feat/signup-improve
Mar 11, 2026
Merged

✨ Feat: 회원가입 기능 개선 (관심 종목 선택, 아이디 중복 체크 API 추가)#74
angoroa merged 3 commits intodevelopfrom
feat/signup-improve

Conversation

@angoroa
Copy link
Member

@angoroa angoroa commented Mar 11, 2026

#️⃣ Issue Number

📝 요약(Summary)

회원가입 기능 개선을 위해 다음 사항을 반영했습니다.

  • 회원가입 시 관심 종목 선택 기능 추가
  • 아이디 중복 체크 API 추가 (GET /api/users/check-username)
  • username 필드의 이메일 형식 제약 제거

이를 통해 사용자가 이메일 형식이 아닌 일반 아이디로 회원가입할 수 있도록 개선하고,
회원가입 전 아이디 중복 여부를 확인할 수 있도록 기능을 추가했습니다.

🛠️ PR 유형

어떤 변경 사항이 있나요?

  • 새로운 기능 추가
  • 버그 수정
  • CSS 등 사용자 UI 디자인 변경
  • 코드에 영향을 주지 않는 변경사항
  • 코드 리팩토링
  • 주석 추가 및 수정
  • 문서 수정
  • 테스트 추가, 테스트 리팩토링
  • 빌드 부분 혹은 패키지 매니저 수정
  • 파일 혹은 폴더명 수정
  • 파일 혹은 폴더 삭제

📸스크린샷 (선택)

없음

💬 공유사항 to 리뷰어

  • 아이디 중복 체크 API를 통해 회원가입 전에 username 사용 가능 여부를 확인할 수 있습니다.
  • username 필드의 이메일 형식 제한을 제거하여 일반 아이디 기반 회원가입이 가능하도록 수정했습니다.
  • 회원가입 요청 시 관심 종목을 함께 전달하도록 기능을 추가했습니다.

✅ PR Checklist

PR이 다음 요구 사항을 충족하는지 확인하세요.

  • 커밋 메시지 컨벤션에 맞게 작성했습니다.
  • 변경 사항에 대한 테스트를 했습니다.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added username duplicate check endpoint for real-time validation during sign-up
    • Added interest sports selection during user registration
  • Documentation

    • Updated API documentation to reflect username field as user ID rather than email format

안훈기 added 3 commits March 11, 2026 17:30
@coderabbitai
Copy link

coderabbitai bot commented Mar 11, 2026

개요

사용자 회원가입 기능을 개선하는 변경사항으로, 아이디 중복 확인 엔드포인트를 추가하고, 회원가입 요청에 관심 종목 필드를 도입하며, 이메일 기반 아이디에서 일반 아이디로 전환합니다.

변경사항

통합 / 파일 요약
Controller 계층
src/main/java/.../user/controller/UserController.java
GET /api/users/check-username 엔드포인트 추가로 아이디 중복 확인 기능 구현. 회원가입 작업 설명을 "이메일과 비밀번호로 회원가입"에서 "아이디와 비밀번호로 회원가입"으로 변경.
DTO (요청/응답)
src/main/java/.../dto/request/SignUpRequest.java, src/main/java/.../dto/response/SignUpResponse.java
SignUpRequest에 관심 종목 필드(interestSports: List<SportType>) 추가. username 필드에서 이메일 형식 검증 제거 및 설명 업데이트. SignUpResponse의 username 필드 Swagger 문서 수정(예: "user@example.com" → "sportize_user").
Entity 계층
src/main/java/.../user/entity/User.java
interestType 필드에 JPA @ElementCollection 매핑 추가. 전용 조인 테이블(user_interest_types) 생성 및 지연 로딩(LAZY) 설정. @Builder.Default로 빈 ArrayList 초기화.
Service 계층
src/main/java/.../user/service/UserService.java, src/main/java/.../user/service/UserServiceImpl.java
UserService 인터페이스에 checkUsernameDuplicate(String username) 메서드 추가. UserServiceImpl에서 구현하여 repository를 통한 아이디 존재 여부 확인. 회원가입 시 interestSports가 null인 경우 빈 ArrayList로 기본값 설정.

예상 코드 리뷰 난이도

🎯 3 (보통) | ⏱️ ~20분

추천 검토자

  • imjuyongp

🐰 아이디 검증 기능이 피어나고,
관심 종목들을 모아 담고,
이메일 형식은 물러나며,
데이터베이스는 신나게 춤춘다네!
회원가입 개선, 우리의 자랑이라! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 변경 사항의 주요 내용을 명확하게 요약하고 있으며, 관심 종목 선택과 아이디 중복 체크 API 추가라는 두 가지 핵심 기능을 제시합니다.
Linked Issues check ✅ Passed Pull request는 linked issue #73의 모든 코딩 요구사항을 만족합니다: 관심 종목 필드 추가(interestSports), 아이디 중복 체크 API 구현, 이메일 형식 제약 제거 및 아이디 기반으로 변경.
Out of Scope Changes check ✅ Passed 모든 코드 변경 사항이 linked issue #73의 요구사항 범위 내에 있으며, 정의된 목표와 관련 없는 변경은 없습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/signup-improve

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

Comment @coderabbitai help to get the list of available commands and usage tips.

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

🧹 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 필드에 대한 크기 제한이 없습니다. SportType enum이 현재 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

📥 Commits

Reviewing files that changed from the base of the PR and between 1f527ad and f6ea7ca.

📒 Files selected for processing (6)
  • src/main/java/com/be/sportizebe/domain/user/controller/UserController.java
  • src/main/java/com/be/sportizebe/domain/user/dto/request/SignUpRequest.java
  • src/main/java/com/be/sportizebe/domain/user/dto/response/SignUpResponse.java
  • src/main/java/com/be/sportizebe/domain/user/entity/User.java
  • src/main/java/com/be/sportizebe/domain/user/service/UserService.java
  • src/main/java/com/be/sportizebe/domain/user/service/UserServiceImpl.java

Comment on lines +32 to +39
@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));
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

보안 설정으로 인해 엔드포인트 접근 불가 - 수정 필요

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.

@angoroa angoroa merged commit a928094 into develop Mar 11, 2026
1 check passed
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.

✨ Feat: 회원가입 기능 개선 (아이디 중복 체크, 관심 종목 필드 추가)

1 participant