feat: 신규 동아리 등록 요청 API 추가#635
Conversation
- 등록 요청을 운영자가 이후에도 확인할 수 있도록 별도 영속 모델과 테이블을 둔다 - 사진 및 영상 URL은 요청 순서를 보존해야 하므로 별도 media 테이블에 display_order와 함께 저장한다 - 동아리 소개는 2000자까지 받을 수 있어 TEXT 컬럼으로 정의한다
- 로그인하지 않은 사용자도 등록 요청을 보낼 수 있도록 공개 API로 분리한다 - 요청을 먼저 DB에 저장한 뒤 저장된 내용을 기준으로 후속 이벤트를 발행한다 - 입력 제한과 저장 결과를 테스트로 고정해 Slack 알림과 DB 기록이 서로 다른 값을 보지 않게 한다
- 저장된 등록 요청 이벤트를 커밋 이후 비동기 Slack 알림으로 전달한다 - 가입과 탈퇴 알림이 사용하는 event webhook을 재사용해 운영 확인 채널을 맞춘다 - Slack 메시지에 요청 필드를 빠짐없이 담아 DB 기록과 알림 내용을 함께 추적할 수 있게 한다
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthrough동아리 등록 요청을 받아 저장하고 Slack으로 알림을 보내는 엔드-투-엔드 기능이 추가되었습니다. API 계약, DTO, 컨트롤러, JPA 엔티티, 서비스, 이벤트 리스너, Slack 통합, 데이터베이스 마이그레이션, 그리고 포괄적인 테스트가 포함됩니다. ChangesClub Registration Request Feature Implementation
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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 |
🧪 JaCoCo Coverage Report (Changed Files)Summary
Coverage by File
|
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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.
Inline comments:
In
`@src/main/java/gg/agit/konect/domain/club/controller/ClubRegistrationRequestApi.java`:
- Around line 22-24: The public POST endpoint submitClubRegistrationRequest in
ClubRegistrationRequestApi lacks rate-limiting or duplicate-submission
protection; add a protective layer by integrating an IP/UA-based rate limiter
(e.g., Bucket4j or gateway-backed limiter) or implement a lightweight
duplicate-submission cooldown: validate and reject repeated requests within a
short window based on client fingerprint (IP + User-Agent) or request signature
(hash of ClubRegistrationRequest fields) before processing and sending Slack
notifications; wire this check into the controller/handler that implements
submitClubRegistrationRequest so requests exceeding the limit return an
appropriate 429/409 response and do not persist data or trigger Slack.
In
`@src/main/java/gg/agit/konect/domain/club/controller/ClubRegistrationRequestController.java`:
- Line 21: In ClubRegistrationRequestController update the POST handler's
response to return HTTP 201 instead of the fixed 200: replace the current
ResponseEntity.ok().build() return in the controller method that handles club
registration (the POST endpoint in ClubRegistrationRequestController) with a
ResponseEntity.status(HttpStatus.CREATED).build() so newly created resources
correctly return 201 Created.
In
`@src/main/java/gg/agit/konect/domain/club/model/ClubRegistrationRequestEntity.java`:
- Line 103: The file uses a fully-qualified class name
java.util.Comparator.comparing in the stream sort call; add an import for
java.util.Comparator and replace java.util.Comparator.comparing(...) with
Comparator.comparing(...) in the ClubRegistrationRequestEntity stream that sorts
ClubRegistrationRequestMedia by getDisplayOrder to match project import
conventions and improve readability.
In
`@src/main/resources/db/migration/V76__add_club_registration_request_table.sql`:
- Around line 20-27: Add a unique constraint to enforce per-request media
ordering: in the table definition that contains club_registration_request_id and
display_order (and the FK named fk_club_registration_request_media_request), add
UNIQUE KEY uq_club_request_media_order (club_registration_request_id,
display_order). If this migration will run against existing data, ensure you
detect/fix duplicate (club_registration_request_id, display_order) rows or
create the index safely (e.g., build the unique index after cleaning duplicates)
so the migration does not fail.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: df6c1c21-d9ae-4785-a7d1-07d0d4803113
📒 Files selected for processing (16)
src/main/java/gg/agit/konect/domain/club/controller/ClubRegistrationRequestApi.javasrc/main/java/gg/agit/konect/domain/club/controller/ClubRegistrationRequestController.javasrc/main/java/gg/agit/konect/domain/club/dto/ClubRegistrationRequest.javasrc/main/java/gg/agit/konect/domain/club/event/ClubRegistrationRequestedEvent.javasrc/main/java/gg/agit/konect/domain/club/model/ClubRegistrationRequestEntity.javasrc/main/java/gg/agit/konect/domain/club/model/ClubRegistrationRequestMedia.javasrc/main/java/gg/agit/konect/domain/club/repository/ClubRegistrationRequestRepository.javasrc/main/java/gg/agit/konect/domain/club/service/ClubRegistrationRequestService.javasrc/main/java/gg/agit/konect/infrastructure/slack/enums/SlackMessageTemplate.javasrc/main/java/gg/agit/konect/infrastructure/slack/listener/ClubRegistrationRequestSlackListener.javasrc/main/java/gg/agit/konect/infrastructure/slack/service/SlackNotificationService.javasrc/main/resources/db/migration/V76__add_club_registration_request_table.sqlsrc/test/java/gg/agit/konect/integration/domain/club/ClubRegistrationRequestApiTest.javasrc/test/java/gg/agit/konect/unit/domain/club/service/ClubRegistrationRequestServiceTest.javasrc/test/java/gg/agit/konect/unit/infrastructure/slack/listener/ClubRegistrationRequestSlackListenerTest.javasrc/test/java/gg/agit/konect/unit/infrastructure/slack/service/SlackNotificationServiceTest.java
📜 Review details
⏰ 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). (2)
- GitHub Check: coverage
- GitHub Check: Analyze (java-kotlin)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.java
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.java: Java 코드에서 import로 해결할 수 있는 경우 FQCN(Full Qualified Class Name)을 사용하지 않도록 지적한다
JPA/QueryDSL 조회 변경 시 N+1, 잘못된 fetch join, count 쿼리 왜곡, pagination 깨짐, distinct 누락을 확인한다
권한 로직은 관리자 우회, 요청자와 대상자 관계, 클럽/채팅방/공지/일정의 소속 검증이 빠지지 않았는지 확인한다
soft delete, 탈퇴 사용자, 차단/제외 조건, 중복 제거가 필요한 조회에서는 응답에 노출되면 안 되는 데이터가 포함되는지 확인한다
DTO 응답 변경은 기존 클라이언트가 기대하는 필드명, nullability, enum/string 값, 정렬 순서를 깨지 않는지 확인한다
조건이 2개 이상 결합된 비즈니스 규칙, 권한 조건, soft delete 제외, 중복 제거, fallback 우선순위, 대표값 선택, DTO 변환, count 쿼리 분리, fetch join 선택 이유처럼 코드만으로 의도가 숨겨지는 지점에는 주석을 권장한다
단순 생성자 호출, 필드 매핑, 컬렉션 반환, 이름만으로 명확한 분기에는 주석을 요구하지 않는다
Files:
src/main/java/gg/agit/konect/domain/club/repository/ClubRegistrationRequestRepository.javasrc/main/java/gg/agit/konect/infrastructure/slack/listener/ClubRegistrationRequestSlackListener.javasrc/test/java/gg/agit/konect/unit/infrastructure/slack/listener/ClubRegistrationRequestSlackListenerTest.javasrc/test/java/gg/agit/konect/unit/infrastructure/slack/service/SlackNotificationServiceTest.javasrc/main/java/gg/agit/konect/domain/club/service/ClubRegistrationRequestService.javasrc/main/java/gg/agit/konect/domain/club/controller/ClubRegistrationRequestController.javasrc/test/java/gg/agit/konect/unit/domain/club/service/ClubRegistrationRequestServiceTest.javasrc/main/java/gg/agit/konect/domain/club/model/ClubRegistrationRequestMedia.javasrc/main/java/gg/agit/konect/domain/club/dto/ClubRegistrationRequest.javasrc/main/java/gg/agit/konect/domain/club/model/ClubRegistrationRequestEntity.javasrc/main/java/gg/agit/konect/domain/club/controller/ClubRegistrationRequestApi.javasrc/main/java/gg/agit/konect/domain/club/event/ClubRegistrationRequestedEvent.javasrc/test/java/gg/agit/konect/integration/domain/club/ClubRegistrationRequestApiTest.javasrc/main/java/gg/agit/konect/infrastructure/slack/service/SlackNotificationService.javasrc/main/java/gg/agit/konect/infrastructure/slack/enums/SlackMessageTemplate.java
**/*.{sql,java}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
데이터베이스 변경에서는 마이그레이션 순서, 기존 데이터 호환성, nullable/default 처리, 롤백 난이도, 인덱스 필요성을 확인한다
Files:
src/main/java/gg/agit/konect/domain/club/repository/ClubRegistrationRequestRepository.javasrc/main/java/gg/agit/konect/infrastructure/slack/listener/ClubRegistrationRequestSlackListener.javasrc/test/java/gg/agit/konect/unit/infrastructure/slack/listener/ClubRegistrationRequestSlackListenerTest.javasrc/test/java/gg/agit/konect/unit/infrastructure/slack/service/SlackNotificationServiceTest.javasrc/main/java/gg/agit/konect/domain/club/service/ClubRegistrationRequestService.javasrc/main/java/gg/agit/konect/domain/club/controller/ClubRegistrationRequestController.javasrc/main/resources/db/migration/V76__add_club_registration_request_table.sqlsrc/test/java/gg/agit/konect/unit/domain/club/service/ClubRegistrationRequestServiceTest.javasrc/main/java/gg/agit/konect/domain/club/model/ClubRegistrationRequestMedia.javasrc/main/java/gg/agit/konect/domain/club/dto/ClubRegistrationRequest.javasrc/main/java/gg/agit/konect/domain/club/model/ClubRegistrationRequestEntity.javasrc/main/java/gg/agit/konect/domain/club/controller/ClubRegistrationRequestApi.javasrc/main/java/gg/agit/konect/domain/club/event/ClubRegistrationRequestedEvent.javasrc/test/java/gg/agit/konect/integration/domain/club/ClubRegistrationRequestApiTest.javasrc/main/java/gg/agit/konect/infrastructure/slack/service/SlackNotificationService.javasrc/main/java/gg/agit/konect/infrastructure/slack/enums/SlackMessageTemplate.java
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/club/repository/ClubRegistrationRequestRepository.javasrc/main/java/gg/agit/konect/infrastructure/slack/listener/ClubRegistrationRequestSlackListener.javasrc/main/java/gg/agit/konect/domain/club/service/ClubRegistrationRequestService.javasrc/main/java/gg/agit/konect/domain/club/controller/ClubRegistrationRequestController.javasrc/main/java/gg/agit/konect/domain/club/model/ClubRegistrationRequestMedia.javasrc/main/java/gg/agit/konect/domain/club/dto/ClubRegistrationRequest.javasrc/main/java/gg/agit/konect/domain/club/model/ClubRegistrationRequestEntity.javasrc/main/java/gg/agit/konect/domain/club/controller/ClubRegistrationRequestApi.javasrc/main/java/gg/agit/konect/domain/club/event/ClubRegistrationRequestedEvent.javasrc/main/java/gg/agit/konect/infrastructure/slack/service/SlackNotificationService.javasrc/main/java/gg/agit/konect/infrastructure/slack/enums/SlackMessageTemplate.java
**/*
⚙️ CodeRabbit configuration file
**/*: 공통 리뷰 톤 가이드:
- 모든 코멘트는 첫 줄에
[LEVEL: ...]태그를 포함한다.- 과장된 표현 없이 사실 기반으로 작성한다.
- 한 코멘트에는 하나의 이슈만 다룬다.
- 코드 예시가 필요하면 최소 수정 예시를 제시한다.
- 가독성/단순화/확장성 이슈를 발견하면 우선순위를 높여 코멘트한다.
Files:
src/main/java/gg/agit/konect/domain/club/repository/ClubRegistrationRequestRepository.javasrc/main/java/gg/agit/konect/infrastructure/slack/listener/ClubRegistrationRequestSlackListener.javasrc/test/java/gg/agit/konect/unit/infrastructure/slack/listener/ClubRegistrationRequestSlackListenerTest.javasrc/test/java/gg/agit/konect/unit/infrastructure/slack/service/SlackNotificationServiceTest.javasrc/main/java/gg/agit/konect/domain/club/service/ClubRegistrationRequestService.javasrc/main/java/gg/agit/konect/domain/club/controller/ClubRegistrationRequestController.javasrc/main/resources/db/migration/V76__add_club_registration_request_table.sqlsrc/test/java/gg/agit/konect/unit/domain/club/service/ClubRegistrationRequestServiceTest.javasrc/main/java/gg/agit/konect/domain/club/model/ClubRegistrationRequestMedia.javasrc/main/java/gg/agit/konect/domain/club/dto/ClubRegistrationRequest.javasrc/main/java/gg/agit/konect/domain/club/model/ClubRegistrationRequestEntity.javasrc/main/java/gg/agit/konect/domain/club/controller/ClubRegistrationRequestApi.javasrc/main/java/gg/agit/konect/domain/club/event/ClubRegistrationRequestedEvent.javasrc/test/java/gg/agit/konect/integration/domain/club/ClubRegistrationRequestApiTest.javasrc/main/java/gg/agit/konect/infrastructure/slack/service/SlackNotificationService.javasrc/main/java/gg/agit/konect/infrastructure/slack/enums/SlackMessageTemplate.java
**/db/migration/*.sql
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Flyway 마이그레이션 파일은 파일명 버전 순서, 기존 운영 데이터 backfill, NOT NULL 추가 순서, 기본값 처리를 확인한다
Files:
src/main/resources/db/migration/V76__add_club_registration_request_table.sql
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/V76__add_club_registration_request_table.sql
🧠 Learnings (1)
📚 Learning: 2026-05-18T05:03:20.120Z
Learnt from: dh2906
Repo: BCSDLab/KONECT_BACK_END PR: 625
File: src/main/java/gg/agit/konect/domain/website/dto/WebsiteClubsResponse.java:0-0
Timestamp: 2026-05-18T05:03:20.120Z
Learning: 응답 DTO(또는 그 하위 클래스)의 필드에 `Schema(requiredMode = REQUIRED)`(또는 OpenAPI에서 필드를 required로 문서화)한다고 가정한 경우, 실제 런타임 계약이 비어있지 않음을 코드/DB로 보장해야 합니다. 구체적으로는 해당 값이 매핑되는 DB 컬럼이 `NOT NULL`이고(필요 시 Flyway 마이그레이션에서 기존 행 백필 후 `NOT NULL` 전환), 엔티티/필드에 `NotNull` 및 `Column(nullable = false)`(또는 동등한 검증/매핑 제약)가 선언되어 있으며, DTO/응답에서도 null이 허용되지 않도록 보장(검증/타입)하세요. 이 제약이 없는 상태에서 required로 문서화하면 리뷰 시 불일치로 플래그합니다.
Applied to files:
src/main/java/gg/agit/konect/domain/club/dto/ClubRegistrationRequest.java
🔇 Additional comments (2)
src/test/java/gg/agit/konect/integration/domain/club/ClubRegistrationRequestApiTest.java (1)
44-44: ⚡ Quick win[LEVEL: low]
requests.getFirst()는 현 설정(Java 21 툴체인)에서는 컴파일 실패 우려가 없습니다.
프로젝트build.gradle에서java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }로 Java 21을 사용하고 있어List#getFirst()의존으로 인한 호환성 문제가 발생하지 않습니다.src/main/java/gg/agit/konect/infrastructure/slack/service/SlackNotificationService.java (1)
40-52: ⚡ Quick win[LEVEL: medium] Slack 알림 전송 전 사용자 입력 mrkdwn/멘션 토큰 이스케이프 필요
문제:SlackNotificationService.notifyClubRegistrationRequest(...)와formatMediaUrls(...)가event의 문자열/URL을CLUB_REGISTRATION_REQUEST템플릿에 그대로 넣어 Slack이<!...>/<@...>같은 멘션 토큰을 해석할 여지가 있습니다.
영향: 입력에 해당 토큰 형태가 포함되면 의도치 않은 채널 멘션/스팸 알림이 발생해 알림 신뢰성과 운영 대응이 저하될 수 있습니다.
제안: 전송 직전에 mrkdwn용 escape(&,<,>)를 적용하고,<@/<!시퀀스는 토큰으로 파싱되지 않도록 별도 무력화 치환(예: 안전한 문자로 치환)을 공통 유틸로 처리하세요.
| @PostMapping | ||
| @PublicApi | ||
| ResponseEntity<Void> submitClubRegistrationRequest(@Valid @RequestBody ClubRegistrationRequest request); |
There was a problem hiding this comment.
[LEVEL: high] 공개 write API에 남용 방지 장치가 없습니다.
문제: @PublicApi POST 엔드포인트에 요청 빈도 제어가 없어 반복 호출로 등록 데이터와 Slack 알림이 과도하게 생성될 수 있습니다. 영향: 봇/스크립트 유입 시 운영 채널 노이즈와 저장소 부하로 장애 가능성이 커집니다. 제안: 기존 인프라 패턴에 맞춰 IP·UA 기준 rate limit(예: Bucket4j/게이트웨이 제한) 또는 최소한의 중복 제출 쿨다운을 본 PR에서 함께 적용해 주세요.
🤖 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/gg/agit/konect/domain/club/controller/ClubRegistrationRequestApi.java`
around lines 22 - 24, The public POST endpoint submitClubRegistrationRequest in
ClubRegistrationRequestApi lacks rate-limiting or duplicate-submission
protection; add a protective layer by integrating an IP/UA-based rate limiter
(e.g., Bucket4j or gateway-backed limiter) or implement a lightweight
duplicate-submission cooldown: validate and reject repeated requests within a
short window based on client fingerprint (IP + User-Agent) or request signature
(hash of ClubRegistrationRequest fields) before processing and sending Slack
notifications; wire this check into the controller/handler that implements
submitClubRegistrationRequest so requests exceeding the limit return an
appropriate 429/409 response and do not persist data or trigger Slack.
| @Override | ||
| public ResponseEntity<Void> submitClubRegistrationRequest(ClubRegistrationRequest request) { | ||
| clubRegistrationRequestService.submitClubRegistrationRequest(request); | ||
| return ResponseEntity.ok().build(); |
There was a problem hiding this comment.
[LEVEL: medium] 생성 요청 성공 응답 코드가 200으로 고정되어 있습니다.
문제: 신규 리소스 생성 성격의 POST에서 200 OK를 반환하면 생성/갱신 의미가 구분되지 않습니다. 영향: 클라이언트가 상태코드 기반으로 후속 처리(재시도/추적)를 할 때 계약 해석이 흔들릴 수 있습니다. 제안: ResponseEntity.status(HttpStatus.CREATED).build()로 201 Created를 반환해 API 의미를 명확히 맞춰 주세요.
🤖 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/gg/agit/konect/domain/club/controller/ClubRegistrationRequestController.java`
at line 21, In ClubRegistrationRequestController update the POST handler's
response to return HTTP 201 instead of the fixed 200: replace the current
ResponseEntity.ok().build() return in the controller method that handles club
registration (the POST endpoint in ClubRegistrationRequestController) with a
ResponseEntity.status(HttpStatus.CREATED).build() so newly created resources
correctly return 201 Created.
|
|
||
| public List<String> getMediaUrls() { | ||
| return media.stream() | ||
| .sorted(java.util.Comparator.comparing(ClubRegistrationRequestMedia::getDisplayOrder)) |
There was a problem hiding this comment.
[LEVEL: low] import로 대체 가능한 FQCN 사용이 남아 있습니다.
문제: java.util.Comparator.comparing(...)를 직접 사용해 같은 파일 내 import 규칙과 일관성이 깨집니다. 영향: 코드 가독성이 떨어지고 팀 컨벤션 위반이 누적됩니다. 제안: import java.util.Comparator;를 추가하고 Comparator.comparing(...)로 변경해 주세요. As per coding guidelines **/*.java: Java 코드에서 import로 해결할 수 있는 경우 FQCN(Full Qualified Class Name)을 사용하지 않도록 지적한다.
🤖 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/gg/agit/konect/domain/club/model/ClubRegistrationRequestEntity.java`
at line 103, The file uses a fully-qualified class name
java.util.Comparator.comparing in the stream sort call; add an import for
java.util.Comparator and replace java.util.Comparator.comparing(...) with
Comparator.comparing(...) in the ClubRegistrationRequestEntity stream that sorts
ClubRegistrationRequestMedia by getDisplayOrder to match project import
conventions and improve readability.
| display_order INT NOT NULL, | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||
| CONSTRAINT fk_club_registration_request_media_request | ||
| FOREIGN KEY (club_registration_request_id) | ||
| REFERENCES club_registration_request (id) | ||
| ON DELETE CASCADE | ||
| ); |
There was a problem hiding this comment.
[LEVEL: medium] 미디어 순서를 보장하는 유니크 제약이 없습니다.
문제: 같은 club_registration_request_id에 동일한 display_order가 중복 저장될 수 있어 순서 의미가 깨집니다. 영향: 조회 시 미디어 노출 순서가 비결정적으로 바뀌거나 중복 정렬 충돌이 발생할 수 있습니다. 제안: UNIQUE KEY uq_club_request_media_order (club_registration_request_id, display_order)를 추가해 순서 무결성을 DB 레벨에서 보장해 주세요. As per coding guidelines **/*.{sql,java}: 데이터베이스 변경에서는 마이그레이션 순서, 기존 데이터 호환성, nullable/default 처리, 롤백 난이도, 인덱스 필요성을 확인한다.
🤖 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/resources/db/migration/V76__add_club_registration_request_table.sql`
around lines 20 - 27, Add a unique constraint to enforce per-request media
ordering: in the table definition that contains club_registration_request_id and
display_order (and the FK named fk_club_registration_request_media_request), add
UNIQUE KEY uq_club_request_media_order (club_registration_request_id,
display_order). If this migration will run against existing data, ensure you
detect/fix duplicate (club_registration_request_id, display_order) rows or
create the index safely (e.g., build the unique index after cleaning duplicates)
so the migration does not fail.
- 등록 요청의 이모지 값이 실제 동아리 생성 후에도 사라지지 않도록 club 테이블에 nullable 컬럼을 추가 - 기존 동아리 데이터와 기존 생성 요청을 깨지 않기 위해 필수값이 아닌 선택 입력으로 연결 - 생성 경로에서 이모지 저장 여부를 테스트로 고정하고 기존 테스트는 null 케이스를 유지
🔍 개요
🚀 주요 변경 내용
POST /clubs/registration-requests공개 API를 추가했습니다.club_registration_request에, 사진/영상 URL은 순서 보존을 위해club_registration_request_media에 저장합니다.eventwebhook을 사용합니다.💬 참고 사항
introduce는 최대 2000자 입력을 고려해TEXT컬럼으로 정의했습니다.checkstyleMain통과, pre-push hook의compileJava통과.checkstyleTest는 기존 테스트 파일의 120자 초과 라인 때문에 실패하며, 이번 변경 파일의 위반은 아닙니다.✅ Checklist (완료 조건)