-
Notifications
You must be signed in to change notification settings - Fork 8
feat: region 관련 관리 기능 추가 #561
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
feat: region 관련 관리 기능 추가 #561
Conversation
지역을 생성하는 기능을 구현했습니다: - AdminRegionCreateRequest: 지역 생성 요청 DTO - AdminRegionResponse: 지역 응답 DTO - AdminRegionService.createRegion(): 중복 검사를 포함한 지역 생성 로직 - AdminRegionController.createRegion(): HTTP POST 엔드포인트 중복 검사: - 지역 코드 중복 확인 - 한글명 중복 확인 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
지역 관리 기능을 완성했습니다: 구현 기능: - AdminRegionUpdateRequest: 지역 수정 요청 DTO - AdminRegionService.updateRegion(): 한글명 중복 검사를 포함한 지역 수정 - AdminRegionService.deleteRegion(): 지역 삭제 - AdminRegionService.getAllRegions(): 전체 지역 조회 - AdminRegionController: 수정/삭제/조회 HTTP 엔드포인트 테스트 코드 (AdminRegionServiceTest): - CREATE: 정상 생성, 코드 중복, 한글명 중복 테스트 - UPDATE: 정상 수정, NOT_FOUND, 중복 한글명, 동일 한글명 테스트 - DELETE: 정상 삭제, NOT_FOUND 테스트 - READ: 빈 목록, 전체 조회 테스트 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
지역 관리 기능에 필요한 에러코드를 추가했습니다: - REGION_NOT_FOUND: 존재하지 않는 지역 - REGION_ALREADY_EXISTS: 이미 존재하는 지역 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Walkthrough
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Repository UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (1)
🧰 Additional context used🧠 Learnings (3)📚 Learning: 2025-08-26T05:07:54.817ZApplied to files:
📚 Learning: 2025-07-29T17:26:08.811ZApplied to files:
📚 Learning: 2025-07-28T03:14:33.849ZApplied to files:
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
🔇 Additional comments (4)
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (1)
src/main/java/com/example/solidconnection/admin/location/region/service/AdminRegionService.java (1)
21-27: 전체 조회 로직이 적절하게 구현되었습니다.읽기 전용 트랜잭션과 스트림 기반 DTO 매핑이 깔끔합니다. 향후 지역 데이터가 많아질 경우 페이지네이션 추가를 고려할 수 있습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/main/java/com/example/solidconnection/admin/location/region/controller/AdminRegionController.java(1 hunks)src/main/java/com/example/solidconnection/admin/location/region/dto/AdminRegionCreateRequest.java(1 hunks)src/main/java/com/example/solidconnection/admin/location/region/dto/AdminRegionResponse.java(1 hunks)src/main/java/com/example/solidconnection/admin/location/region/dto/AdminRegionUpdateRequest.java(1 hunks)src/main/java/com/example/solidconnection/admin/location/region/service/AdminRegionService.java(1 hunks)src/main/java/com/example/solidconnection/common/exception/ErrorCode.java(1 hunks)src/main/java/com/example/solidconnection/location/region/repository/RegionRepository.java(1 hunks)src/test/java/com/example/solidconnection/admin/location/region/service/AdminRegionServiceTest.java(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/com/example/solidconnection/admin/location/region/service/AdminRegionService.java (1)
src/main/java/com/example/solidconnection/admin/location/region/controller/AdminRegionController.java (1)
RequiredArgsConstructor(21-58)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (2)
src/main/java/com/example/solidconnection/admin/location/region/controller/AdminRegionController.java (2)
28-57: REST 엔드포인트 구현이 모범 사례를 잘 따르고 있습니다.각 엔드포인트의 특징:
- GET /admin/regions - 전체 목록 조회, 200 OK 반환
- POST /admin/regions - 생성 요청에 @Valid 검증 적용, 201 CREATED 반환
- PUT /admin/regions/{code} - 업데이트 요청에 @Valid 검증 적용, 200 OK 반환
- DELETE /admin/regions/{code} - 삭제 완료 시 204 NO CONTENT 반환
HTTP 메서드 선택, 상태 코드, 그리고 요청 검증이 모두 적절합니다.
21-27: 컨트롤러 구조와 보안 설정이 모두 올바르게 구현되어 있습니다.검증 결과를 정리하면 다음과 같습니다:
Spring Security 설정 확인
SecurityConfiguration.java의 66번 라인에서.requestMatchers("/admin/**").hasRole(ADMIN.name())설정이 적용됨경로 매핑 확인
- 컨트롤러의
@RequestMapping("/admin/regions")가/admin/**패턴에 포함되어 ADMIN 역할만 접근 가능결론
- 인증/인가 설정이 제대로 구현되어 있으므로 관리자 전용 접근이 보장됨
의존성 주입, 경로 매핑, 보안 설정 모두 Spring 관례를 따르고 있으며 추가 수정이 필요하지 않습니다.
src/main/java/com/example/solidconnection/admin/location/region/dto/AdminRegionResponse.java
Show resolved
Hide resolved
| @Transactional | ||
| public AdminRegionResponse createRegion(AdminRegionCreateRequest request) { | ||
| regionRepository.findById(request.code()) | ||
| .ifPresent(region -> { | ||
| throw new CustomException(ErrorCode.REGION_ALREADY_EXISTS); | ||
| }); | ||
|
|
||
| regionRepository.findByKoreanName(request.koreanName()) | ||
| .ifPresent(region -> { | ||
| throw new CustomException(ErrorCode.REGION_ALREADY_EXISTS); | ||
| }); | ||
|
|
||
| Region region = new Region(request.code(), request.koreanName()); | ||
| Region savedRegion = regionRepository.save(region); | ||
|
|
||
| return AdminRegionResponse.from(savedRegion); | ||
| } |
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.
중복 체크 로직에 경쟁 조건(race condition) 위험이 있습니다.
현재 구조의 문제점:
- 31-34줄: code 중복 체크
- 36-39줄: koreanName 중복 체크
- 41-42줄: Region 생성 및 저장
위 체크와 저장 사이에 다른 트랜잭션이 동일한 code나 koreanName을 가진 Region을 생성할 수 있습니다. 이는 동시성 환경에서 중복 데이터가 저장될 수 있는 위험을 초래합니다.
권장 해결 방안:
- Region 엔티티의 code와 koreanName 필드에 데이터베이스 레벨 unique 제약 조건 추가
- DataIntegrityViolationException을 catch하여 REGION_ALREADY_EXISTS 에러로 변환
@Transactional
public AdminRegionResponse createRegion(AdminRegionCreateRequest request) {
- regionRepository.findById(request.code())
- .ifPresent(region -> {
- throw new CustomException(ErrorCode.REGION_ALREADY_EXISTS);
- });
-
- regionRepository.findByKoreanName(request.koreanName())
- .ifPresent(region -> {
- throw new CustomException(ErrorCode.REGION_ALREADY_EXISTS);
- });
-
- Region region = new Region(request.code(), request.koreanName());
- Region savedRegion = regionRepository.save(region);
-
- return AdminRegionResponse.from(savedRegion);
+ try {
+ Region region = new Region(request.code(), request.koreanName());
+ Region savedRegion = regionRepository.save(region);
+ return AdminRegionResponse.from(savedRegion);
+ } catch (DataIntegrityViolationException e) {
+ throw new CustomException(ErrorCode.REGION_ALREADY_EXISTS);
+ }
}이 방식은 데이터베이스의 ACID 속성을 활용하여 원자적으로 중복을 방지합니다.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In
src/main/java/com/example/solidconnection/admin/location/region/service/AdminRegionService.java
around lines 29 to 45, the current pre-checks for duplicate code and koreanName
create a race condition before saving; instead add database-level UNIQUE
constraints for Region.code and Region.koreanName (update the JPA entity
annotations or DB migration/DDL), remove or keep but do not rely on the
in-memory findBy checks, and wrap the save call in a try/catch that catches
DataIntegrityViolationException (or the specific Spring/JPA persistence
exception thrown on unique violation) and rethrow new
CustomException(ErrorCode.REGION_ALREADY_EXISTS) so concurrent inserts are
handled atomically by the DB; keep the method @Transactional as-is.
| regionRepository.findByKoreanName(request.koreanName()) | ||
| .ifPresent(existingRegion -> { | ||
| if (!existingRegion.getCode().equals(code)) { | ||
| throw new CustomException(ErrorCode.REGION_ALREADY_EXISTS); | ||
| } | ||
| }); |
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.
업데이트 시 중복 이름 체크도 경쟁 조건에 노출되어 있습니다.
createRegion과 동일한 문제로, 중복 체크와 저장 사이에 다른 트랜잭션이 동일한 koreanName을 사용할 수 있습니다. 데이터베이스 unique 제약 조건을 추가하고 예외 처리로 전환하는 것을 권장합니다.
🤖 Prompt for AI Agents
In
src/main/java/com/example/solidconnection/admin/location/region/service/AdminRegionService.java
around lines 52-57, the current in-memory check for duplicate koreanName during
update is racy; add a unique constraint on the korean_name column at the
DB/schema level and remove reliance on the pre-check as the sole guard, then
modify the service to catch the persistence constraint exception (e.g.,
DataIntegrityViolationException or ConstraintViolationException) thrown on save
and translate it into a CustomException(ErrorCode.REGION_ALREADY_EXISTS); ensure
the update/save is still performed inside the transactional context but rely on
DB uniqueness + exception handling rather than the non-atomic find-then-check
pattern.
src/main/java/com/example/solidconnection/admin/location/region/service/AdminRegionService.java
Outdated
Show resolved
Hide resolved
src/main/java/com/example/solidconnection/admin/location/region/service/AdminRegionService.java
Show resolved
Hide resolved
whqtker
left a comment
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.
컨벤션 관련한 부분만 코멘트 남겼습니다 ! 간단한 거만 손 보시면 머지해도 될 정도로 클로드가 잘 작성했네요 .. 특히 테스트 코드와 같이 단순한 작성은 클로드가 큰 도움이 될 거 같아요
| @Valid @RequestBody AdminRegionCreateRequest request | ||
| ) { | ||
| AdminRegionResponse response = adminRegionService.createRegion(request); | ||
| return ResponseEntity.status(HttpStatus.CREATED).body(response); |
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.
응답 코드를 지정하는 방향으로 작성해주었네요
여담으로 예전에 RESTful API 설계 원칙에 맞게 응답 코드를 지정하자고 얘기가 나왔던 것으로 기억하는데, 여유 생기면 한 번 진행해봐야겠네요
| regionRepository.findByKoreanName(request.koreanName()) | ||
| .ifPresent(region -> { | ||
| throw new CustomException(ErrorCode.REGION_ALREADY_EXISTS); | ||
| }); |
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.
저희는 orElseThrow 로 예외 던졌는데 이 부분도 조금 다르네요
예외 처리를 따로 private 메서드로 분리하지 않는 것도 그렇구요 ..!
| } | ||
|
|
||
| @Test | ||
| @DisplayName("저장된 모든 지역을 조회한다") |
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.
테스트 메서드에 @DisplayName 어노테이션도 저희 암묵적으론 사용하지 않고 있고요
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.
아직 손볼 곳들이 좀 많군요! 다른분들 확인하신 후에 고치려고 좀 납두긴 했습니다 ㅎㅎ.. 수정해놓겠습니다~
| class 전체_지역_조회 { | ||
|
|
||
| @Test | ||
| void 지역이_없으면_빈_목록을_반환한다() { |
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.
저희 서비스에서 테스트 코드에 '// given' 부분 내용이 존재하지 않다면 주석을 아예 빼버려도 되나요?
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.
다른 테스트 코드들 보니 안쓰고 있네요!
* fix: yml 들여쓰기 수정 (#555) * fix: yml 들여쓰기 수정 * fix: jdk 변경 * refactor: 멘토 및 채팅 관련 API 응답 수정 (#537) * refactor: 멘토의 멘토링 조회 응답에서 mentoringId가 아니라 roomId를 포함하도록 * refactor: 파트너가 멘토인 경우 partnerId는 mentorId로 - AS IS: 멘토/멘티 모두 partnerId가 siteUserId - TO BE: 멘티: siteUserId, 멘토: mentorId * refactor: 응답의 senderId가 mentorId/siteUserId가 되도록 * refactor: senderId에 해당하는 chatParticipant가 없을 경우 예외 처리하는 로직 추가 * refactor: 메서드명에 맞게 시그니처 변경 * refactor: getChatMessages 메서드에서 응답으로 siteUserId를 넘겨주도록 - AS IS: mentorId(mentor) / siteUserId(mentee) - TO BE: siteUserId(all) * refactor: 헬퍼 메서드로 메서드 복잡성을 분산한다 * refactor: getChatPartner 메서드의 응답으로 siteUserId를 넘겨주도록 - AS IS: mentorId(mentor) / siteUserId(mentee) - TO BE: siteUserId(all) * refactor: CD 성능 개선 (#552) * fix: deprecated된 base image를 eclipse-temurin:17-jdk로 변경 * refactor: scp 파일 전송하는 방식에서 GHCR로 push/pull하도록 변경 * fix: GHCR image 제거시 Org의 GITHUB_TOKEN 사용하도록 변경 * refactor : scp 파일 전송하는 방식에서 GHCR로 push/pull하도록 prod-cd.yml과 docker-compose.prod.yml 변경 * fix: prod 인스턴스 old image 이름 통일 * fix: prod-cd.yml StrictHostKeyChecking 옵션 문법 오류 수정 * fix: prod-cd.yml StrictHostKeyChecking 옵션 문법 오류 수정 * fix: dev-cd.yml Old images 정리 작업 중 이미지 이름 불일치 문제 해결 * chore: 마지막 줄 개행 추가 * chore: 마지막 줄 개행 추가 * feat: stage 인스턴스에 대한 최신 이미지 5개 유지 기능 및 old 이미지 제거 기능 추가 * chore: 중복된 환경변수 지정 제거 * chore: 중복된 pem키 생성 로직 제거 * fix: 잘못된 pem키 이름 수정 * refactor: 원격 호스트에서 pull할 경우, 최소 권한으로 실행하도록 Github App으로 임시토큰 발급하도록 수정 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 (#565) * fix: GitHub app token permission 문제 해결 (#566) * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 Contents 읽기 권한 추가 * fix: GitHub app token permission 문제 오류 해결 (#567) * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 Contents 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * fix: GitHub app token permission이 repo 레벨에서 부여되는 문제 해결 (#568) * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 Contents 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * fix: GitHub app token permission 권한 오류 해결 (#569) * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 Contents 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * test: fork repo의 작업 branch에서 해당 workflows가 실행되도록 임시 수정 * refactor: test용 설정 제거 * feat: claude.md 파일 추가 (#560) * fix : 동일 멘토 멘티 중복 신청 불가능하도록 수정 (#563) * fix : 동일 멘토 멘티 중복 신청 불가능하도록 수정 - UK 제약조건 추가 - flyway script 추가 - CustomException 추가 - Service 로직 수정 - Test code 추가 * fix : column명 오류 수정 - column명 camelCase -> snake_case로 변경 * fix : column명 오류 수정 - column명 name으로 명시 * fix: GitHub app token permission 권한 오류 해결 (#570) * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 Contents 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * test: fork repo의 작업 branch에서 해당 workflows가 실행되도록 임시 수정 * refactor: test용 설정 제거 * fix: docker login username 불일치 문제 * refactor: 최소권한 원칙 적용을 위한 Action Job 분리 * refactor: 필요없는 주석 제거 * fix: GHCR 정리 권한 PAT로 해결 (#573) * feat: 지원서가 APPROVED 인 유저의 멘토 생성 기능 추가 (#562) * feat: 지원서가 APPROVED 인 유저의 멘토 생성 기능 추가 * refactor: submitMentorApplication 메서드의 멘토 지원 유효 검증 부분을 메서드로 추출 * refactor: MentorMyPage 생성, 수정 부분의 channel 생성, 업데이트 부분 중복 제거 * test: Mentor 생성 관련 테스트 추가 * fix: 코드래빗 리뷰 적용 * refactor: 멘토 생성 시 channelRequest가 null 일 떄 예외 처리 * feat: MentorApplicationRequest 필드에 유효성 어노테이션 추가 * test: 채널 검색 시 siteUserId로 조회하는 문제 해결 * fix: 리뷰 수정사항 적용 * fix: 파일 끝에 개행 추가 * refactor: 멘토 생성 메서드에서 siteUser의 검증 제외 * refactor: dto 단에서 채널 리스트 null 검증 * feat: MentorApplication에 termId 추가 flyway 스크립트 추가 * fix: flyway 버전 충돌 해결 * feat: 어드민 멘토 승격 요청 페이징 조회 기능 추가 (#576) * feat: 어드민 멘토 지원서 페이징 조회 기능 추가 * feat: mentor/repository 패키지에 custom 패키지 추가 - custom 패키지에 페이징 조회를 책임지는 MentorApplicationFilterRepository 추가 - MentorApplicationSearchCondition 에서 넘긴 keyword 기반으로 닉네임, 권역, 나라, 학교명으로 필터링 검색 기능 추가 - MentorApplicationSearchCondition 에서 넘긴 mentorApplicationStatus 기반으로 승인, 거절, 진행중 으로 필터링 기능 추가 * test: 어드민 멘토 지원서 페이징 조회 테스트 추가 * feat: MentorApplication 엔티티에 approved_at 필드 추가 flyway 스크립트 작성 * fix: 파일 끝에 개행 추가 * refactor: 페이징 조회 시 count 쿼리에 불필요한 조인 막기 * fix: 코드래빗 리뷰 적용 * fix: flyway V39 스크립트 파일명 수정 * test: 테스트 코드 오류 수정, 검증 추가 * test: 기대하는 값이랑 다른 테스트 응답을 수정합니다 * feat: 어드민 멘토 승격 지원서 승인/거절 기능, 상태 별 지원서 개수 조회 기능 추가 (#577) * feat: 어드민 멘토 승격 지원서 승인/거절 기능 추가 * test: 어드민 멘토 지원서 승인/거절 테스트 추가 * feat: 멘토 지원서 상태별 개수 조회 기능 추가 * test: 멘토 지원서 상태별 개수 조회 테스트 추가 * fix: 대학이 선택되지 않은 멘토 지원서 승인 시 예외 발생하도록 수정 * refactor: 리뷰 내용 반영 * refactor: MENTOR_APPLICATION_ALREADY_CONFIRM -> MENTOR_APPLICATION_ALREADY_CONFIRMED 로 수정 * refactor: 멘토 지원서 거절 사유 관련하여 기획에 명시되지 않은 길이 제한 제거 * refactor: 리뷰 적용 * refactor: 변수명, 필드명 일관성 맞추기 * test: assertAll 적용 * feat: region 관련 관리 기능 추가 (#561) * feat: 지역 생성 기능 구현 (AdminRegion) 지역을 생성하는 기능을 구현했습니다: - AdminRegionCreateRequest: 지역 생성 요청 DTO - AdminRegionResponse: 지역 응답 DTO - AdminRegionService.createRegion(): 중복 검사를 포함한 지역 생성 로직 - AdminRegionController.createRegion(): HTTP POST 엔드포인트 중복 검사: - 지역 코드 중복 확인 - 한글명 중복 확인 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * feat: 지역 수정/삭제/조회 기능 구현 및 테스트 추가 (AdminRegion) 지역 관리 기능을 완성했습니다: 구현 기능: - AdminRegionUpdateRequest: 지역 수정 요청 DTO - AdminRegionService.updateRegion(): 한글명 중복 검사를 포함한 지역 수정 - AdminRegionService.deleteRegion(): 지역 삭제 - AdminRegionService.getAllRegions(): 전체 지역 조회 - AdminRegionController: 수정/삭제/조회 HTTP 엔드포인트 테스트 코드 (AdminRegionServiceTest): - CREATE: 정상 생성, 코드 중복, 한글명 중복 테스트 - UPDATE: 정상 수정, NOT_FOUND, 중복 한글명, 동일 한글명 테스트 - DELETE: 정상 삭제, NOT_FOUND 테스트 - READ: 빈 목록, 전체 조회 테스트 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * fix: 지역 관리 관련 에러코드 추가 (ErrorCode) 지역 관리 기능에 필요한 에러코드를 추가했습니다: - REGION_NOT_FOUND: 존재하지 않는 지역 - REGION_ALREADY_EXISTS: 이미 존재하는 지역 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * fix: jpa 오류 수정 * refactor: 코드리뷰 반영 --------- Co-authored-by: Claude <[email protected]> * fix: config.alloy 파일 경로 불일치 문제 해결 (#586) * fix: config.alloy 파일 경로 불일치 문제 해결 * refactor: docker-compose를 수정하는게 아닌 cd.yml의 경로를 수정하여 해결 * feat: 소셜 로그인 사용자는 비밀번호 변경을 할 수 없다. (#582) * feat: 소셜 로그인 사용자는 비밀번호 변경을 할 수 없도록 * test: 소셜 로그인 사용자 비밀번호 변경 관련 테스트 코드 작성 * chore: 컨벤션에 맞게 메서드명 변경 - ~~ 예외가 발생한다 * chore: 충돌 해결 * fix: Upgrade 헤더 유무에 따라 Connection 헤더의 값을 동적으로 설정하도록 (#581) * fix: Upgrade 헤더 유무에 따라 Connection 헤더의 값을 동적으로 설정하도록 - Upgrade 헤더가 존재하면(e.g. WebSocket) upgrade로 설정 - Upgrade 헤더가 존재하지 않으면 keep-alive로 설정 * chore: 서브모듈 업데이트 * feat: 멘토 지원서 대학교 매핑 기능, 대학 선택 상태 페이징 조건 추가 (#583) * feat: 멘토 지원서 검색 조건에 UniversitySelectType 추가 * feat: 어드민 멘토 지원서 페이징 조회 응답에 UniversitySelectType 추가 * test: 멘토 지원서 조회 테스트 추가 - test: UniversitySelectType 기반 페이징 조회 테스트 추가 * feat: 멘토 지원서에 대학 매핑 기능 추가 * test: 멘토 지원서 대학 매핑 테스트 추가 * refactor: 의미 없는 import 제거 * refactor: 리뷰 내용 반영 * refactor: 개행 및 공백 추가 * refactor: pathVariable 네이밍을 kebab-case 로 통일 * refactor: Service 레이어의 검증 로직을 도메인으로 이동 * refactor: PENDING 상태 및 OTHER 타입 검증을 도메인 메서드로 관리 * refactor: assignUniversity() 호출 전 검증 책임을 도메인 엔티티에 위임 * test : assertAll 로 검증 그룹화 * refactor: 스프링 부트 앱 외의 사이드 인프라 배포 과정을 분리 (#592) * refactor: dev 환경에서의 side-infra 배포 과정 분리 * refactor: prod 환경에서의 side-infra 배포 과정 분리 * refactor: docker-compose 가 실행되고 있지 않아도 스크립트가 실패하지 않게 변경 * fix: docker compose up 시에 사용할 환경변수 중 누락된 변수를 추가 * fix: S3 이름 불일치 문제 해결 (#594) * fix: s3 이름 불일치 문제 해결 * fix: s3와의 연동된 cloudfront URL로 수정 * refactor: 분리한 사이드 인프라에 대해서 필요없는 파일 정리 (#596) * test: flyway 스크립트를 검증하는 테스트 코드 작성 (#588) * test: flyway 스크립트를 검증하는 테스트 코드 작성 * fix: DirtiesContext 어노테이션을 통해 기존 컨텍스트를 폐기하도록 - 새로운 MySQL 환경에서 마이그레이션이 이루어지도록 수정 * fix: flyway 검증용의 별도의 MySQL 컨테이너를 사용하도록 * chore: 테스트 의도를 쉽게 이해할 수 있도록 주석 추가 * chore: 명시적으로 컨테이너를 시작하도록 - 또한 MySQLTestContainer 코드와 유사한 컨벤션을 가지도록 수정 * refactor: 게시글 조회 응답에 댓글 deprecated 여부 포함하도록 (#599) * feat: 유저의 멘토 지원서 신청 이력 조회 기능 추가 (#603) * feat: 유저의 멘토 지원 이력 조회 기능 추가 * refactor: 매개변수 타입 통일 * refactor: long 타입을 Long 으로 수정 * test: 멘토 지원서 이력 조회 테스트 추가 * test: MentorApplicationFixtureBuilder 에 rejectedReason 필드 및 빌더 메서드 추가 * refactor: 리뷰 사항 적용 * test: 멘토 지원서 이력 조회 에서 user와 university 재사용 * refactor: 긴 uri 를 짧게 수정 * refactor: 서브모듈 해시값 되돌리기 * refactor: 개행 지우기 * refactor: applicationOrder 자료형을 long 으로 수정 * fix: applicationOrder 를 int 자료형으로 처리하도록 복구 - 순서를 나타내고, 해당 값이 21억을 넘길 수 없다 판단하여 더 적합한 int 자료형으로 복구 * test: long type 을 기대하던 테스트 에러 해결 * fix: 탈퇴한 사용자가 물리적 삭제가 되지 않았던 문제를 해결한다 (#574) * refactor: FK에 ON DELETE CASCADE 옵션 추가 * refactor: 삭제 메서드로 사용자 연관 데이터를 삭제하도록 * feat: 어드민 유저 차단 기능 추가 (#604) * feat: 어드민 차단 기능 * test: 어드민 차단 기능 * feat: API 성능 로깅, 쿼리 별 메트릭 전송 추가 (#602) * feat: HTTP 요청/응답 로깅 필터 구현 - traceId 기반 요청 추적 - 요청/응답 로깅 - CustomExceptionHandler와 중복 로깅 방지 - Actuator 엔드포인트 로깅 제외 * feat: ExceptionHandler에 중복 로깅 방지 플래그 및 userId 로깅 추가 * feat: API 수행시간 로깅 인터셉터 추가 * feat: ApiPerf 인터셉터, Logging 필터 빈 등록 * refactor: logback 설정 변경 - info, warn, error, api_perf 로 로그 파일 분리해서 관리 * feat: 쿼리 별 수행시간 메트릭 모니터링 추가 * feat: 데이터소스 프록시 의존성 및 config 파일 추가 * feat: 데이터 소스 프록시가 metric을 찍을 수 있도록 listener 클래스 추가 * feat: 요청 시 method, uri 정보를 listener에서 활용하기 위해 RequestContext 및 관련 interceptor 추가 * refactor: 비효율적인 Time 빌더 생성 개선 - Time.builder 를 사용하면 매번 빌더를 생성하여 비효율적인 문제를 meterRegistry.timer 방식으로 해결 * feat: 로깅을 위해 HttpServeletRequest 속성에 userId 추가 * refactor: logback 설정 중 local은 console만 찍도록 수정 * refactor: FILE_PATTERN -> LOG_PATTERN 으로 수정 * test: TokenAuthenticationFilter에서 request에 userId 설정 검증 추가 - principal 조회 예외를 막기 위해 siteUserDetailsService given 추가 * refacotr: 코드 래빗 리뷰사항 반영 * test: 중복되는 테스트 제거 * refactor: 사용하지 않는 필드 제거 * refactor: 리뷰 내용 반영 * refactor: ApiPerformanceInterceptor에서 uri 정규화 관련 코드 제거 * refactor: ApiPerformanceInterceptor에서 if-return 문을 if-else 문으로 수정 * refactor: 추가한 interceptor 의 설정에 actuator 경로 무시하도록 셋팅 * refactor: 중복되는 의존성 제거 * refactor: 로깅 시 민감한 쿼리 파라미터 마스킹 - EXCLUDE_QUERIES 에 해당하는 쿼리 파라미터 KEY 값의 VALUE 를 masking 값으로 치환 * refactor: 예외 처리 후에도 Response 로그 찍도록 수정 * refactor: CustomExceptionHandler 원상복구 - Response 로그를 통해 user를 추적할 수 있으므로 로그에 userId 를 추가하지 않습니다 * refactor: 리뷰 사항 반영 * refactor: RequestContext 빌더 제거 * refactor: RequestContextInterceptor import 수정 * refactor: logback yml 파일에서 timestamp 서버 시간과 동일한 규격으로 수정 * refactor: ApiPerformanceInterceptor 에서 동일 내용 로그 중복으로 찍는 문제 수정 * fix: decode를 두 번 하는 문제 수정 * test: 로깅 관련 filter, interceptor 테스트 추가 * refactor: 코드래빗 리뷰사항 반영 * test: contains 로 비교하던 검증 로직을 isEqualTo 로 수정 * test: preHandle 테스트 에서 result 값을 항상 검증 * refactor: 단위테스트에 TestContainer 어노테이션 제거 * fix: conflict 해결 * fix: docker-compose 충돌 해결 (#610) * chore: release github action 임의 실행 추가 * refactor: 기본 추천 대학 후보 추가 (#161) * fix: config.alloy 경로 수정 * hotfix: 모의지원 현황 어드민 권한 제거 * hotfix: import 제거 * chore: 서브모듈 해시 업데이트 (#611)
관련 이슈
작업 내용
region 관련 curd기능을 추가했습니다.
특이 사항
놀랍게도 이 pr은 앞 pr에서 말씀드렸듯이 기능, 테스트, 커밋메시지까지 claude code가 해줬습니다! 이렇게 간단한 기능이라 한 번 시켜봤습니다 ㅎㅎ..
물론 아직 커밋 관련해서도 좀 부족한 거 같고 손볼 곳이 많을 거 같은데 다른 분들도 어떤 느낌인지 알면 좋을 거 같아 한 번 맡겨봤습니다!
앞으로 테스트 코드 관련해서는 확실히 스트레스를 덜 받으실 거 같습니다.
리뷰 요구사항 (선택)