Skip to content

feat: 어드민에서 출신 대학을 관리하는 기능 추가#725

Merged
whqtker merged 10 commits into
developfrom
feat/632-manage-home-univ-admin
Jun 3, 2026
Merged

feat: 어드민에서 출신 대학을 관리하는 기능 추가#725
whqtker merged 10 commits into
developfrom
feat/632-manage-home-univ-admin

Conversation

@whqtker
Copy link
Copy Markdown
Member

@whqtker whqtker commented May 29, 2026

관련 이슈

작업 내용

어드민에서 출신(협정) 대학을 추가하는 CRUD를 추가합니다.

특이 사항

리뷰 요구사항 (선택)

@whqtker whqtker self-assigned this May 29, 2026
@whqtker whqtker added the 기능 label May 29, 2026
@whqtker whqtker requested review from Gyuhyeok99 and wibaek as code owners May 29, 2026 11:22
@whqtker whqtker added the 최종 리뷰 최소 1명 필수 label May 29, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: bc9053ca-2f1f-4aa5-b0e5-27b97058270b

📥 Commits

Reviewing files that changed from the base of the PR and between ebd6094 and c786189.

📒 Files selected for processing (4)
  • src/main/java/com/example/solidconnection/admin/university/dto/AdminHomeUniversityResponse.java
  • src/main/java/com/example/solidconnection/admin/university/service/AdminHomeUniversityService.java
  • src/test/java/com/example/solidconnection/admin/university/service/AdminHomeUniversityServiceTest.java
  • src/test/java/com/example/solidconnection/university/fixture/HomeUniversityFixture.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/main/java/com/example/solidconnection/admin/university/dto/AdminHomeUniversityResponse.java
  • src/test/java/com/example/solidconnection/admin/university/service/AdminHomeUniversityServiceTest.java
  • src/main/java/com/example/solidconnection/admin/university/service/AdminHomeUniversityService.java

Walkthrough

  1. 요청/응답 DTO 및 에러 코드 추가: AdminHomeUniversityCreateRequest, AdminHomeUniversityUpdateRequest, AdminHomeUniversityResponse 레코드와 HOME_UNIVERSITY_* ErrorCode 항목들을 정의했습니다.
  2. 도메인·리포지토리 변경: HomeUniversity에 update(name)를 추가하고 UnivApplyInfoRepository와 SiteUserRepository에 existsByHomeUniversityId 쿼리를 추가했습니다.
  3. 서비스 구현: AdminHomeUniversityService에서 전체/단건 조회, 생성(중복검증), 수정(중복검증), 삭제(참조검증) 로직과 캐시 무효화 애노테이션을 구현했습니다.
  4. 컨트롤러 노출: AdminHomeUniversityController가 /admin/home-universities로 CRUD 엔드포인트를 노출하고 @Valid 검증을 적용합니다.
  5. 테스트 추가: AdminHomeUniversityServiceTest에 생성/조회/수정/삭제의 정상 및 예외 시나리오를 검증하는 중첩 테스트들을 추가했습니다.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • wibaek
  • Hexeong
  • lsy1307
  • JAEHEE25
  • sukangpunch
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive PR의 변경사항이 이슈 #632의 출신 대학 CRUD 기능 요구사항을 모두 충족합니다. 단, 로고 이미지 처리는 미구현 상태입니다. 이슈 #632에서 명시한 로고 이미지(선택) 기능이 구현되었는지 확인이 필요합니다.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 출신 대학 관리 기능 추가라는 PR의 주요 변경사항을 명확하게 요약하고 있습니다.
Description check ✅ Passed PR 설명이 필수 섹션(관련 이슈, 작업 내용)을 포함하고 있으나 특이 사항과 리뷰 요구사항은 미작성 상태입니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 출신 대학 관리 CRUD 기능과 관련된 범위 내의 변경으로 보입니다.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/632-manage-home-univ-admin

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.

@whqtker whqtker changed the title Feat/632 manage home univ admin feat: 어드민에서 출신 대학을 관리하는 기능 추가 May 29, 2026
Copy link
Copy Markdown

@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.

🧹 Nitpick comments (4)
src/main/java/com/example/solidconnection/admin/university/service/AdminHomeUniversityService.java (1)

82-96: ⚡ Quick win

중복 검증 로직을 하나로 합치면 더 깔끔해질 것 같아요.

validateNameNotExistsvalidateNameNotDuplicated는 사실상 같은 일을 하고 있고, excludeIdnull로 넘긴 validateNameNotDuplicated(name, null)validateNameNotExists(name)과 동일하게 동작합니다(existing.getId().equals(null)은 항상 false이므로 생성 시에도 의도대로 예외가 발생합니다). 하나로 통합하면 의미 중복을 줄이고 유지보수가 쉬워집니다.

♻️ 검증 메서드 통합 제안
-    private void validateNameNotExists(String name) {
-        homeUniversityRepository.findByName(name)
-                .ifPresent(existing -> {
-                    throw new CustomException(HOME_UNIVERSITY_ALREADY_EXISTS);
-                });
-    }
-
-    private void validateNameNotDuplicated(String name, Long excludeId) {
+    private void validateNameNotDuplicated(String name, Long excludeId) {
         homeUniversityRepository.findByName(name)
                 .ifPresent(existing -> {
                     if (!existing.getId().equals(excludeId)) {
                         throw new CustomException(HOME_UNIVERSITY_ALREADY_EXISTS);
                     }
                 });
     }

생성 시 호출부도 함께 변경합니다.

-        validateNameNotExists(request.name());
+        validateNameNotDuplicated(request.name(), null);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/example/solidconnection/admin/university/service/AdminHomeUniversityService.java`
around lines 82 - 96, Combine the two validators into a single method (keep the
name validateNameNotDuplicated(String name, Long excludeId) or choose a clear
single name) that uses
homeUniversityRepository.findByName(name).ifPresent(existing -> { if (excludeId
== null || !existing.getId().equals(excludeId)) throw new
CustomException(HOME_UNIVERSITY_ALREADY_EXISTS); }); then replace all calls to
validateNameNotExists(name) with validateNameNotDuplicated(name, null) (or call
the new single method from both create and update flows) so duplicate-check
logic is centralized and correctly handles null excludeId.
src/main/java/com/example/solidconnection/admin/university/controller/AdminHomeUniversityController.java (3)

39-44: ⚡ Quick win

생성 성공 시 201 Created 상태 코드와 Location 헤더를 반환하는 것을 권장합니다.

현재 구현은 200 OK를 반환하지만, REST 모범 사례에 따르면 리소스 생성 시에는 201 Created 상태 코드를 사용하고 생성된 리소스의 URI를 Location 헤더에 포함해야 합니다. 이렇게 하면 API 사용자가 새로 생성된 리소스에 직접 접근할 수 있습니다.

♻️ 제안하는 개선 방안
+import org.springframework.http.HttpStatus;
+import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
+import java.net.URI;
+
 `@PostMapping`
 public ResponseEntity<AdminHomeUniversityResponse> createHomeUniversity(
         `@Valid` `@RequestBody` AdminHomeUniversityCreateRequest request
 ) {
-    return ResponseEntity.ok(adminHomeUniversityService.createHomeUniversity(request));
+    AdminHomeUniversityResponse response = adminHomeUniversityService.createHomeUniversity(request);
+    URI location = ServletUriComponentsBuilder
+            .fromCurrentRequest()
+            .path("/{id}")
+            .buildAndExpand(response.id())
+            .toUri();
+    return ResponseEntity.created(location).body(response);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/example/solidconnection/admin/university/controller/AdminHomeUniversityController.java`
around lines 39 - 44, The createHomeUniversity endpoint currently returns 200
OK; change it to return 201 Created with a Location header pointing to the new
resource URI. Update the createHomeUniversity controller method to call
adminHomeUniversityService.createHomeUniversity(request) to obtain the created
resource or its id, build the resource URI (e.g., using
ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(created.getId()).toUri()),
and return ResponseEntity.created(location).body(createdResponse) so the
response status is 201 and the Location header is set.

54-60: ⚡ Quick win

삭제 성공 시 204 No Content 상태 코드를 반환하는 것을 권장합니다.

현재 구현은 200 OK를 반환하지만, REST 모범 사례에 따르면 응답 본문이 없는 DELETE 요청은 204 No Content 상태 코드를 사용하는 것이 더 적절합니다.

♻️ 제안하는 개선 방안
 `@DeleteMapping`("/{home-university-id}")
 public ResponseEntity<Void> deleteHomeUniversity(
         `@PathVariable`("home-university-id") Long homeUniversityId
 ) {
     adminHomeUniversityService.deleteHomeUniversity(homeUniversityId);
-    return ResponseEntity.ok().build();
+    return ResponseEntity.noContent().build();
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/example/solidconnection/admin/university/controller/AdminHomeUniversityController.java`
around lines 54 - 60, Change the deleteHomeUniversity endpoint in
AdminHomeUniversityController to return 204 No Content instead of 200 OK: after
calling adminHomeUniversityService.deleteHomeUniversity(homeUniversityId) have
the method return ResponseEntity.noContent().build() (i.e., use
ResponseEntity.noContent() in the deleteHomeUniversity method).

20-23: 🏗️ Heavy lift

관리자 엔드포인트(/admin/)는 전역 보안 설정으로 이미 보호되고 있습니다.**

  1. src/main/java/com/example/solidconnection/admin/university/controller/AdminHomeUniversityController 의 라우트(/admin/home-universities)는 SecurityConfiguration에서 requestMatchers("/admin/**").hasRole(ADMIN.name())로 처리되어 관리자 역할 없이는 접근이 차단됩니다.
  2. 클래스/메서드 단에 @PreAuthorize를 추가하면 의도가 더 명확해지는 “방어적 가독성” 차원 개선으로 고려할 만합니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/example/solidconnection/admin/university/controller/AdminHomeUniversityController.java`
around lines 20 - 23, 현재 AdminHomeUniversityController 클래스(경로
"/admin/home-universities")는 SecurityConfiguration의
requestMatchers("/admin/**").hasRole(ADMIN.name())로 이미 보호되고 있으나 가독성·방어적 문서화를 위해
클래스나 핵심 메서드에 `@PreAuthorize`("hasRole('ADMIN')")를 추가하세요; 대상은
AdminHomeUniversityController 클래스 선언부 또는 개별 엔드포인트 메서드이며 SecurityConfiguration을
변경하지 말고 `@PreAuthorize` 어노테이션이 Spring Method Security가 활성화된 상태에서만 작동하도록 설정(예:
`@EnableMethodSecurity` 또는 `@EnableGlobalMethodSecurity`)되어 있는지 확인하세요.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@src/main/java/com/example/solidconnection/admin/university/controller/AdminHomeUniversityController.java`:
- Around line 39-44: The createHomeUniversity endpoint currently returns 200 OK;
change it to return 201 Created with a Location header pointing to the new
resource URI. Update the createHomeUniversity controller method to call
adminHomeUniversityService.createHomeUniversity(request) to obtain the created
resource or its id, build the resource URI (e.g., using
ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(created.getId()).toUri()),
and return ResponseEntity.created(location).body(createdResponse) so the
response status is 201 and the Location header is set.
- Around line 54-60: Change the deleteHomeUniversity endpoint in
AdminHomeUniversityController to return 204 No Content instead of 200 OK: after
calling adminHomeUniversityService.deleteHomeUniversity(homeUniversityId) have
the method return ResponseEntity.noContent().build() (i.e., use
ResponseEntity.noContent() in the deleteHomeUniversity method).
- Around line 20-23: 현재 AdminHomeUniversityController 클래스(경로
"/admin/home-universities")는 SecurityConfiguration의
requestMatchers("/admin/**").hasRole(ADMIN.name())로 이미 보호되고 있으나 가독성·방어적 문서화를 위해
클래스나 핵심 메서드에 `@PreAuthorize`("hasRole('ADMIN')")를 추가하세요; 대상은
AdminHomeUniversityController 클래스 선언부 또는 개별 엔드포인트 메서드이며 SecurityConfiguration을
변경하지 말고 `@PreAuthorize` 어노테이션이 Spring Method Security가 활성화된 상태에서만 작동하도록 설정(예:
`@EnableMethodSecurity` 또는 `@EnableGlobalMethodSecurity`)되어 있는지 확인하세요.

In
`@src/main/java/com/example/solidconnection/admin/university/service/AdminHomeUniversityService.java`:
- Around line 82-96: Combine the two validators into a single method (keep the
name validateNameNotDuplicated(String name, Long excludeId) or choose a clear
single name) that uses
homeUniversityRepository.findByName(name).ifPresent(existing -> { if (excludeId
== null || !existing.getId().equals(excludeId)) throw new
CustomException(HOME_UNIVERSITY_ALREADY_EXISTS); }); then replace all calls to
validateNameNotExists(name) with validateNameNotDuplicated(name, null) (or call
the new single method from both create and update flows) so duplicate-check
logic is centralized and correctly handles null excludeId.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7445e042-7163-4850-91b6-0a93255e5c60

📥 Commits

Reviewing files that changed from the base of the PR and between 67aad12 and ebd6094.

📒 Files selected for processing (10)
  • src/main/java/com/example/solidconnection/admin/university/controller/AdminHomeUniversityController.java
  • src/main/java/com/example/solidconnection/admin/university/dto/AdminHomeUniversityCreateRequest.java
  • src/main/java/com/example/solidconnection/admin/university/dto/AdminHomeUniversityResponse.java
  • src/main/java/com/example/solidconnection/admin/university/dto/AdminHomeUniversityUpdateRequest.java
  • src/main/java/com/example/solidconnection/admin/university/service/AdminHomeUniversityService.java
  • src/main/java/com/example/solidconnection/common/exception/ErrorCode.java
  • src/main/java/com/example/solidconnection/siteuser/repository/SiteUserRepository.java
  • src/main/java/com/example/solidconnection/university/domain/HomeUniversity.java
  • src/main/java/com/example/solidconnection/university/repository/UnivApplyInfoRepository.java
  • src/test/java/com/example/solidconnection/admin/university/service/AdminHomeUniversityServiceTest.java

Copy link
Copy Markdown
Contributor

@Gyuhyeok99 Gyuhyeok99 left a comment

Choose a reason for hiding this comment

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

오랜만에 솔커 코드 보니 마음이 편안해지네요.. 너무 잘읽힙니다

import com.example.solidconnection.university.domain.HomeUniversity;

public record AdminHomeUniversityResponse(
Long id,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

이런 건 null이될 수 없으니 long이 낫지 않나요? 머쓱하지만 오랜만에 pr봅니다..

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

놓친 부분이라 수정했습니다 !!

void 저장된_모든_협정대학을_반환한다() {
// given
HomeUniversity homeUniversity1 = homeUniversityFixture.인하대학교();
HomeUniversity homeUniversity2 = homeUniversityRepository.save(new HomeUniversity(null, "연세대학교"));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

오랜만에 코드봐서 제가 바뀐 컨벤션을 모르지만 얜 fixture 안쓴 이유가 혹시 있나요?

Comment on lines +82 to +87
private void validateNameNotExists(String name) {
homeUniversityRepository.findByName(name)
.ifPresent(existing -> {
throw new CustomException(HOME_UNIVERSITY_ALREADY_EXISTS);
});
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

이제 private 함수는 맨 밑으로 보내게 바뀌었나보군요!

@whqtker whqtker merged commit 1436d72 into develop Jun 3, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

기능 최종 리뷰 최소 1명 필수

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: 어드민에서 출신 대학을 관리하는 기능 추가

2 participants