fix: 학번 유니크 제약조건 제거 - #356
Conversation
📝 WalkthroughWalkthrough유니크 학번 제약을 DB 마이그레이션으로 제거하고, 리포지토리 반환타입·서비스 검증·동호회 멤버 추가 흐름을 다중 사용자 처리로 변경했습니다. API 문서 및 응답 코드에서 중복 학번 관련 항목을 삭제/대체했습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant UserService
participant ClubService
participant UserRepository
participant Database
Client->>UserService: 회원가입 요청 (univId, studentNumber, ...)
UserService->>UserRepository: findAllByUniversityIdAndStudentNumber(univId, studentNumber)
UserRepository->>Database: SELECT ... WHERE university_id=? AND student_number=? AND deleted_flag=0
Database-->>UserRepository: 사용자 리스트 반환
UserRepository-->>UserService: 사용자 리스트
UserService->>Database: INSERT 사용자 (중복 검사 없음)
Database-->>UserService: 생성 결과
UserService-->>Client: 가입 성공 응답
Client->>ClubService: 동호회 멤버 추가 요청 (univId, studentNumber, name)
ClubService->>UserRepository: findAllByUniversityIdAndStudentNumber(univId, studentNumber)
UserRepository->>Database: SELECT ...
Database-->>UserRepository: 후보 리스트 반환
UserRepository-->>ClubService: 후보 리스트
ClubService->>ClubService: 후보 리스트 필터링 by name
alt 이름으로 단일 매칭
ClubService->>Database: 멤버 직접 추가 (matched user)
Database-->>ClubService: 추가 성공
else 다중 매칭
ClubService-->>Client: AMBIGUOUS_USER_MATCH 에러 반환
else 매칭 없음
ClubService->>ClubService: addPreMemberInternal 처리 (프리멤버)
end
ClubService-->>Client: 멤버 추가 결과
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 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: 2
🤖 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/resources/db/migration/V49__remove_unique_constraint_on_user_student_number.sql`:
- Around line 1-2: This migration drops the unique index
uq_users_university_id_student_number_active on users which makes the change
effectively irreversible if duplicates appear; before dropping it, add a
duplicate-detection step (query for rows grouped by university_id,
student_number, active_flag having count>1) and abort the migration (or clean
up/merge duplicates) if any are found, or alternatively document explicitly in
the migration/operational runbook that V49 is destructive and include the
required manual duplicate-cleanup procedure and rollback impossibility;
reference the ALTER TABLE users DROP INDEX
uq_users_university_id_student_number_active operation and ensure the migration
fails loudly rather than proceeding when duplicates exist.
- Around line 1-2: The migration removes the unique constraint so lookups by
(universityId, studentNumber) may return multiple users; update
UserRepository.findByUniversityIdAndStudentNumber(...) to return a collection
(e.g., List<User>) or a result type that can represent multiple matches, then
update ClubMemberManagementService.addDirectMember(...) (and its caller flow) to
handle multiple results by either requiring an additional disambiguating
identifier, validating uniqueness and failing fast with a clear error if
multiple active users exist, or selecting the correct user deterministically
only after extra checks; also add unit/integration tests for the multi-match
case and deploy the code change before running the migration.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: bf0da731-d96e-442f-82a0-30dc1ec7103a
📒 Files selected for processing (4)
src/main/java/gg/agit/konect/domain/user/model/User.javasrc/main/java/gg/agit/konect/domain/user/repository/UserRepository.javasrc/main/java/gg/agit/konect/domain/user/service/UserService.javasrc/main/resources/db/migration/V49__remove_unique_constraint_on_user_student_number.sql
💤 Files with no reviewable changes (3)
- src/main/java/gg/agit/konect/domain/user/model/User.java
- src/main/java/gg/agit/konect/domain/user/service/UserService.java
- src/main/java/gg/agit/konect/domain/user/repository/UserRepository.java
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
src/main/resources/db/migration/**/*.sql
⚙️ CodeRabbit configuration file
src/main/resources/db/migration/**/*.sql: Flyway 마이그레이션 리뷰 규칙:
- 버전 파일명 규칙(V{number}__{description}.sql) 위반 여부를 우선 확인한다.
- 이미 배포된 마이그레이션 수정/재번호 부여 위험이 있으면 반드시 차단 코멘트를 남긴다.
- 파괴적 변경(drop, rename 등)은 롤백 가능성과 운영 영향 관점에서 검토한다.
Files:
src/main/resources/db/migration/V49__remove_unique_constraint_on_user_student_number.sql
**/*
⚙️ CodeRabbit configuration file
**/*: 공통 리뷰 톤 가이드:
- 모든 코멘트는 첫 줄에
[LEVEL: ...]태그를 포함한다.- 과장된 표현 없이 사실 기반으로 작성한다.
- 한 코멘트에는 하나의 이슈만 다룬다.
- 코드 예시가 필요하면 최소 수정 예시를 제시한다.
- 가독성/단순화/확장성 이슈를 발견하면 우선순위를 높여 코멘트한다.
Files:
src/main/resources/db/migration/V49__remove_unique_constraint_on_user_student_number.sql
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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/gg/agit/konect/domain/club/service/ClubMemberManagementService.java`:
- Around line 94-103: The current logic uses
userRepository.findAllByUniversityIdAndStudentNumber(...) and then
candidates.stream().filter(...).findFirst() to pick a matchedUser and pass it to
addDirectMember(...), which can incorrectly choose one of multiple
identical-name candidates; change this so you count/filter name-equals results:
if exactly one match exists call addDirectMember(club, user, clubPosition), but
if zero or more than one matches fall back to addPreMemberInternal(...) (or
throw a clear ambiguity error) to avoid non-deterministic selection; update the
code paths that reference matchedUser, addDirectMember, and addPreMemberInternal
accordingly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 3ac0e237-8209-4191-a90d-a625501ad50f
📒 Files selected for processing (4)
src/main/java/gg/agit/konect/domain/club/service/ClubMemberManagementService.javasrc/main/java/gg/agit/konect/domain/user/controller/UserApi.javasrc/main/java/gg/agit/konect/domain/user/repository/UserRepository.javasrc/main/java/gg/agit/konect/global/code/ApiResponseCode.java
💤 Files with no reviewable changes (2)
- src/main/java/gg/agit/konect/global/code/ApiResponseCode.java
- src/main/java/gg/agit/konect/domain/user/controller/UserApi.java
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
src/main/java/**/*.java
⚙️ CodeRabbit configuration file
src/main/java/**/*.java: 아래 원칙으로 리뷰 코멘트를 작성한다.
- 코멘트는 반드시 한국어로 작성한다.
- 반드시 수정이 필요한 항목만 코멘트로 남기고, 단순 취향 차이는 지적하지 않는다.
- 각 코멘트 첫 줄에 심각도를
[LEVEL: high|medium|low]형식으로 반드시 표기한다.- 심각도 기준: high=운영 장애 가능, medium=품질 저하, low=개선 권고.
- 각 코멘트는 "문제 -> 영향 -> 제안" 순서로 3문장 이내로 간결하게 작성한다.
- 가능하면 재현 조건 및 실패 시나리오도 포함한다.
- 제안은 현재 코드베이스(Spring Boot + JPA + Flyway) 패턴과 일치해야 한다.
- 보안, 트랜잭션 경계, 예외 처리, N+1, 성능 회귀 가능성을 우선 점검한다.
- 가독성: 변수/메서드 이름이 의도를 바로 드러내는지, 중첩과 메서드 길이가 과도하지 않은지 점검한다.
- 단순화: 불필요한 추상화, 중복 로직, 과한 방어 코드가 있으면 더 단순한 대안을 제시한다.
- 확장성: 새 요구사항 추가 시 변경 범위가 최소화되는 구조인지(하드코딩 분기/값 여부 포함) 점검한다.
Files:
src/main/java/gg/agit/konect/domain/user/repository/UserRepository.javasrc/main/java/gg/agit/konect/domain/club/service/ClubMemberManagementService.java
**/*
⚙️ CodeRabbit configuration file
**/*: 공통 리뷰 톤 가이드:
- 모든 코멘트는 첫 줄에
[LEVEL: ...]태그를 포함한다.- 과장된 표현 없이 사실 기반으로 작성한다.
- 한 코멘트에는 하나의 이슈만 다룬다.
- 코드 예시가 필요하면 최소 수정 예시를 제시한다.
- 가독성/단순화/확장성 이슈를 발견하면 우선순위를 높여 코멘트한다.
Files:
src/main/java/gg/agit/konect/domain/user/repository/UserRepository.javasrc/main/java/gg/agit/konect/domain/club/service/ClubMemberManagementService.java
🔍 개요
유저의 휴먼 에러로 학번을 오기입하는 문제가 발생함
그로 인해 누군가는 이미 사용중인 학번이라 가입을 못한다는 문의가 제기됨
정책을 완화하여 학번을 중복가능하도록 하고자 함
🚀 주요 변경 내용
users테이블에(university_id, student_number, active_flag)유니크 제약조건을 제거했습니다.그에 따라 학번 중복 검증 로직도 같이 제거했습니다.
이름, 학번으로 동아리 멤버를 등록하는 기능에 동일 학번+이름을 지니는 유저가 2명 이상일 시 등록을 차단합니다.
💬 참고 사항
✅ Checklist (완료 조건)