-
Notifications
You must be signed in to change notification settings - Fork 0
Refactor: 그룹 스웨거 추가 및 그룹 가입 신청 리팩토링 #41
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
Conversation
Walkthrough문서화 인터페이스(ControllerDocs) 추가 및 컨트롤러 시그니처 구현, 그룹 검증 메시지 한글화, 그룹 권한 초기화 보조 로직 및 동시성 예외 처리 추가, GroupJoin 관련 DTO·커스텀 리포지토리·Impl 도입 및 서비스 리팩터링, 이미지 업로드 요청 검증 강화. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Controller as GroupJoinController
participant Service as GroupJoinService
participant Repo as GroupJoinRepository (Impl)
participant DB as Database
Controller->>Service: findGroupJoinList(groupId)
Service->>Repo: findByGroup(groupId)
Repo->>DB: SELECT ... (QueryDSL projection) -> DTO(GroupJoinInfo)
DB-->>Repo: List<GroupJoinInfo)
Repo-->>Service: List<GroupJoinInfo)
Service-->>Controller: GroupJoinListResponse.from(dtoList)
sequenceDiagram
autonumber
participant Svc as GroupService
participant PermRepo as GroupPermissionRepository
participant DB as Database
Svc->>PermRepo: findAll()
PermRepo-->>Svc: existingPermissions
alt existing < enum.size
Svc->>PermRepo: saveAll(missingPermissions)
Note right of Svc: DataIntegrityViolationException 허용(동시성)
opt on DataIntegrityViolationException
Svc->>PermRepo: findAll() (재조회)
end
end
Svc->>Svc: initializeGroupPermissions(group) with ensured permissions
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
⏰ 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)
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
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: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
src/main/java/project/flipnote/groupjoin/service/GroupJoinService.java (4)
177-183: 알림 수신자 ID 매핑 버그: 사용자 ID 대신 그룹 ID를 담고 있음 (Line 179)
receiverIds가groupMember.getGroup().getId()로 매핑되어 있어, 알림 수신자가 전부 그룹 ID로 전송됩니다. 사용자 ID로 수정해야 합니다.- .map((groupMember -> groupMember.getGroup().getId())) + .map(groupMember -> groupMember.getUser().getId())
127-134: 중복 가입 검증이 ‘가입신청 존재’만 확인함 — 기존 멤버 여부도 차단 필요현재
existGroupJoin만 확인하여 기존 그룹 멤버가 다시 신청하는 케이스를 막지 못합니다. 멤버십 존재 여부도 함께 검사해 주세요.//그룹 조회 Group group = findGroup(groupId); - if (existGroupJoin(group, user)) { + //기존 멤버인지 우선 확인 + if (groupMemberRepository.existsByGroup_IdAndUser_Id(group.getId(), user.getId())) { + throw new BizException(GroupJoinErrorCode.ALREADY_JOINED_GROUP); + } + //이미 신청 이력 존재 여부 확인 + if (existGroupJoin(group, user)) { throw new BizException(GroupJoinErrorCode.ALREADY_JOINED_GROUP); }
139-159: 공개 그룹(신청 불필요) 즉시 가입 처리 누락 — 멤버 추가 필요
applicationRequired == false이면 상태를ACCEPT로만 저장하고 멤버를 추가하지 않습니다. 즉시 멤버십 생성이 필요합니다.groupJoinRepository.save(groupJoin); - if (group.getApplicationRequired()) { + if (group.getApplicationRequired()) { sendJoinRequestNotification(group, user); - } + } else { + // 공개 그룹: 즉시 멤버 추가 + GroupMember groupMember = GroupMember.builder() + .group(group) + .user(user) + .role(GroupMemberRole.MEMBER) + .build(); + groupMemberRepository.save(groupMember); + }
226-235: 보안 취약점: 다른 그룹의 joinId를 조작 가능 — 그룹 일치 검증 추가 필요
respondToJoinRequest에서groupId와joinId간 소속 그룹 일치 검증이 없습니다. 권한이 있는 A그룹 컨텍스트로 B그룹의 신청을 변경할 수 있습니다.//그룹 가입 신청 조회 GroupJoin groupJoin = findGroupJoin(joinId); + // joinId가 해당 groupId에 속하는지 검증 + if (!groupJoin.getGroup().getId().equals(groupId)) { + throw new BizException(GroupJoinErrorCode.USER_NOT_PERMISSION); + }
🧹 Nitpick comments (23)
src/main/java/project/flipnote/image/model/ImageUploadRequestDto.java (2)
11-12: String 필드는 @NotNull 대신 @notblank 권장프로젝트 전반에서 String 유효성에 @notblank를 일관 사용 중입니다(UserUpdateRequest.nickname, CreateCardSetRequest.name 등). 빈 문자열에 대해 보다 명확한 메시지를 주기 위해 @notblank로 교체를 제안합니다.
-import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; @@ - @NotNull(message = "파일 이름을 입력해주세요.") + @NotBlank(message = "파일 이름을 입력해주세요.") String fileName
7-12: 확장자 대소문자 허용 및 에러 메시지 품질 개선현재 정규식은 확장자 소문자만 허용합니다. 클라이언트가 JPG/PNG 대문자를 보낼 수 있으므로 대소문자 무시 플래그를 추가하면 UX가 좋아집니다(해시 부분도 동일 이득). 동시에 공백 문자열은 @notblank에서 걸리고, 형식 오류는 @pattern에서 분리되어 메시지가 명확해집니다.
- @Pattern( - regexp = "^[a-fA-F0-9]{32}\\.(jpg|jpeg|png|gif)$", - message = "파일 이름은 32자리 MD5 해시와 jpg/jpeg/png/gif 확장자 형식이어야 합니다." - ) + @Pattern( + regexp = "^[a-f0-9]{32}\\.(jpg|jpeg|png|gif)$", + flags = { jakarta.validation.constraints.Pattern.Flag.CASE_INSENSITIVE }, + message = "파일 이름은 32자리 MD5 해시와 jpg/jpeg/png/gif 확장자 형식이어야 합니다." + )src/main/java/project/flipnote/image/controller/ImageUploadController.java (2)
22-29: 필드명 의미 구체화 제안ImageUploadService를 주입받는 필드명이 fileService로 되어 있어 맥락 파악이 어렵습니다. 일관성과 가독성을 위해 이름을 imageUploadService로 변경을 제안합니다.
- private final ImageUploadService fileService; + private final ImageUploadService imageUploadService; @@ - ImageUploadResponseDto res = fileService.getPresignedUrl(req.fileName()); + ImageUploadResponseDto res = imageUploadService.getPresignedUrl(req.fileName());
21-29: 보안 요구 여부 확인 필요해당 엔드포인트가 인증이 필요한지 정책 확인 부탁드립니다. 다른 컨트롤러 문서화 패턴(User, Group 등)에서는 보호 API에 @securityrequirement를 명시합니다. 필요하다면 docs 인터페이스에 추가하는 편이 일관됩니다.
src/main/java/project/flipnote/image/controller/docs/ImageUploadControllerDocs.java (2)
15-35: 보호 리소스라면 보안 스키마와 401 응답 명시이미지 업로드용 Presigned URL 발급은 일반적으로 인증된 사용자 전용입니다. 보호 리소스라면 @securityrequirement와 401 응답을 추가해주세요. 또한 Content에 mediaType을 명시하면 문서 정확도가 올라갑니다.
@@ -import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; @@ @Operation( summary = "이미지 업로드 URL 생성", - description = "S3에 이미지를 업로드할 수 있는 Presigned PUT URL을 발급합니다. " - + "파일 이름은 32자리 MD5 + 확장자(jpg|jpeg|png|gif) 형식이어야 합니다." - ) + description = "S3에 이미지를 업로드할 수 있는 Presigned PUT URL을 발급합니다. " + + "파일 이름은 32자리 MD5 + 확장자(jpg|jpeg|png|gif) 형식이어야 합니다.", + security = { @SecurityRequirement(name = "access-token") } + ) @@ - content = @Content(schema = @Schema(implementation = ImageUploadRequestDto.class)) + content = @Content(mediaType = "application/json", + schema = @Schema(implementation = ImageUploadRequestDto.class)) ) @ApiResponses({ @ApiResponse(responseCode = "200", description = "URL 발급 성공", content = @Content(schema = @Schema(implementation = ImageUploadResponseDto.class))), + @ApiResponse(responseCode = "401", description = "인증 필요 또는 토큰 만료"), @ApiResponse(responseCode = "400", description = "잘못된 요청(파일명 형식 오류 등)"), @ApiResponse(responseCode = "409", description = "이미 존재하는 파일명(CONFLICT_IMAGE)"), @ApiResponse(responseCode = "500", description = "S3 서비스 오류(S3_SERVICE_ERROR)") }) - public ResponseEntity<ImageUploadResponseDto> getPresignedUrl(ImageUploadRequestDto req); + ResponseEntity<ImageUploadResponseDto> getPresignedUrl(ImageUploadRequestDto req);
35-35: interface 메서드의 public 키워드는 불필요다른 Docs 인터페이스들과의 일관성을 위해 public 제거를 권장합니다(기본이 public).
- public ResponseEntity<ImageUploadResponseDto> getPresignedUrl(ImageUploadRequestDto req); + ResponseEntity<ImageUploadResponseDto> getPresignedUrl(ImageUploadRequestDto req);src/main/java/project/flipnote/groupjoin/controller/GroupJoinController.java (2)
33-41: 조인 신청 리스트 조회: 페이징 고려 권장그룹 단위 신청 건수가 많아질 수 있으니 Cursor/Paging 응답으로 확장하기 쉽게 인터페이스를 설계해 두는 걸 권장합니다(예: CursorPagingResponse).
68-76: "me" 엔드포인트 경로 컨벤션 정합성 확인현재 "/groups/joins/me"를 사용 중인데, 기존 초대 조회는 "/group-invitations" 형태입니다. 일관성을 위해 "/group-joins/me" 또는 기존 패턴 중 하나로 정렬하는지 검토해 주세요. 호환성 영향이 있으면 문서에 명시해 주세요.
src/main/java/project/flipnote/groupjoin/model/GroupJoinListResponse.java (1)
3-3: 미사용 import 제거GroupJoin 엔티티 import는 더 이상 사용되지 않습니다. 제거해 주세요(정적 분석/빌드 경고 예방).
-import project.flipnote.groupjoin.entity.GroupJoin;src/main/java/project/flipnote/groupjoin/repository/GroupJoinRepositoryCustom.java (1)
8-12: 조회 규모 대비 확장성 옵션 노출 검토현재 단순 List 반환입니다. 운영 규모를 고려해 정렬/커서/페이지 크기 인자를 받는 오버로드를 추가하거나, 최소한 정렬 기준(예: id desc)을 명세해 두는 것을 권장합니다. 인터페이스 변경이 부담되면 구현체에서 일관된 정렬을 강제하고 Javadoc으로 문서화해 주세요.
src/main/java/project/flipnote/groupjoin/model/FindGroupJoinListMeResponse.java (1)
5-5: 미사용 import 제거GroupJoin import는 사용되지 않습니다. 정리해 주세요.
-import project.flipnote.groupjoin.entity.GroupJoin;src/main/java/project/flipnote/groupjoin/model/MyGroupJoinInfo.java (1)
12-14: 사소한 포맷팅 수정 제안
from내부 인자 사이 공백 누락이 있습니다. 자동 포매터가 없다면 아래처럼 정리해 주세요.- return new MyGroupJoinInfo(groupJoinId, groupId, groupName,joinIntro,status); + return new MyGroupJoinInfo(groupJoinId, groupId, groupName, joinIntro, status);src/main/java/project/flipnote/groupjoin/service/GroupJoinService.java (2)
201-206: 목록 조회에 상태 필터 추가 고려 (PENDING 중심)운영 관점에서 가입신청 리스트는 보통 PENDING 위주로 보게 됩니다. 레포지토리에 상태 조건(예: PENDING) 추가하는 것을 권장합니다.
- List<GroupJoinInfo> groupJoins = findGroupJoins(group); + List<GroupJoinInfo> groupJoins = groupJoinRepository.findByGroupAndStatusPending(group.getId());(필요 시
GroupJoinRepositoryCustom에 전용 메서드 추가)
288-291: 중복 로직 정리: 헬퍼 메서드 활용이미
findMyGroupJoins(UserProfile)가 존재합니다. 동일 로직을 재사용해 가독성을 높이세요.- List<MyGroupJoinInfo> groupJoins = groupJoinRepository.findByUser(user.getId()); + List<MyGroupJoinInfo> groupJoins = findMyGroupJoins(user);src/main/java/project/flipnote/groupjoin/repository/GroupJoinRepositoryImpl.java (1)
10-10: 불필요한 import 제거 제안
GroupMemberInfo는 사용되지 않습니다. 정리해 주세요.-import project.flipnote.group.model.GroupMemberInfo;src/main/java/project/flipnote/groupjoin/controller/docs/GroupJoinControllerDocs.java (6)
23-25: 태그/보안 선언은 적절. 다만 문서 언어/네이밍 일관화 권장다른 Docs 인터페이스(예: Group Invitation)는 영문 태그명을 사용합니다. 이 파일만 국문 태그를 쓰면 탐색/분류가 흐트러질 수 있어 전반 언어 전략을 통일하는 편이 좋습니다.
26-40: joinRequest: operationId 부여, 201 Location 헤더/에러 예시 명확화API 식별 안정성을 위해 operationId를 추가하고, 생성(201)에 Location 헤더, 403/409의 예시 페이로드를 ExampleObject로 명시하면 Swagger UI 가독성이 좋아집니다.
아래와 같이 보강 제안:
@Operation( summary = "가입 신청 요청", description = "공개 그룹에 대해 가입 신청을 생성합니다. 그룹 정책에 따라 PENDING 또는 즉시 ACCEPT로 저장됩니다." + , operationId = "joinRequest" ) @ApiResponses({ - @ApiResponse(responseCode = "201", description = "가입 신청 생성 성공", - content = @Content(schema = @Schema(implementation = GroupJoinResponse.class))), + @ApiResponse(responseCode = "201", description = "가입 신청 생성 성공", + content = @Content(schema = @Schema(implementation = GroupJoinResponse.class)), + headers = { + @io.swagger.v3.oas.annotations.headers.Header( + name = "Location", + description = "생성된 가입 신청 리소스 위치", + schema = @Schema(example = "/groups/123/join-requests/456") + ) + } + ), @ApiResponse(responseCode = "400", description = "잘못된 요청 (검증 실패 등)"), @ApiResponse(responseCode = "401", description = "인증 실패"), - @ApiResponse(responseCode = "403", description = "비공개 그룹 → GROUP_JOIN_003", - content = @Content(schema = @Schema(example = "{\"code\":\"GROUP_JOIN_003\",\"message\":\"그룹이 비공개입니다.\"}"))), + @ApiResponse(responseCode = "403", description = "비공개 그룹 → GROUP_JOIN_003", + content = @Content( + mediaType = "application/json", + examples = { + @io.swagger.v3.oas.annotations.media.ExampleObject( + name = "GROUP_JOIN_003", + value = "{\"code\":\"GROUP_JOIN_003\",\"message\":\"그룹이 비공개입니다.\"}" + ) + } + ) + ), @ApiResponse(responseCode = "404", description = "그룹 없음"), - @ApiResponse(responseCode = "409", description = "이미 가입 신청 존재 → GROUP_JOIN_005 / 정원 초과 → GROUP_JOIN_006", - content = @Content(schema = @Schema(example = "{\"code\":\"GROUP_JOIN_005\",\"message\":\"이미 신청한 그룹입니다.\"}"))) + @ApiResponse(responseCode = "409", description = "이미 가입 신청 존재 → GROUP_JOIN_005 / 정원 초과 → GROUP_JOIN_006", + content = @Content( + mediaType = "application/json", + examples = { + @io.swagger.v3.oas.annotations.media.ExampleObject( + name = "이미 신청", + value = "{\"code\":\"GROUP_JOIN_005\",\"message\":\"이미 신청한 그룹입니다.\"}" + ), + @io.swagger.v3.oas.annotations.media.ExampleObject( + name = "정원 초과", + value = "{\"code\":\"GROUP_JOIN_006\",\"message\":\"그룹 정원이 가득 찼습니다.\"}" + ) + } + ) + ) })추가 import 필요:
+import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ExampleObject;
41-50: 파라미터 순서 일관화: 경로/본문 → 인증 주체(Principal) 순프로젝트 내 다른 Docs(예: GroupInvitation*)와 동일하게 경로/본문 파라미터를 먼저, 인증 주체를 마지막에 두면 가독성과 일관성이 좋아집니다.
예시 수정:
ResponseEntity<GroupJoinResponse> joinRequest( - @Parameter(hidden = true) @AuthenticationPrincipal AuthPrinciple authPrinciple, - @Parameter(description = "그룹 ID", example = "123") Long groupId, + @Parameter(description = "그룹 ID", example = "123") Long groupId, @io.swagger.v3.oas.annotations.parameters.RequestBody( description = "가입 신청 요청 데이터", required = true, content = @Content(schema = @Schema(implementation = GroupJoinRequest.class)) ) - @Valid GroupJoinRequest req + @Valid GroupJoinRequest req, + @Parameter(hidden = true) @AuthenticationPrincipal AuthPrinciple authPrinciple ); ResponseEntity<GroupJoinListResponse> findGroupJoinList( - @Parameter(hidden = true) @AuthenticationPrincipal AuthPrinciple authPrinciple, - @Parameter(description = "그룹 ID", example = "123") Long groupId + @Parameter(description = "그룹 ID", example = "123") Long groupId, + @Parameter(hidden = true) @AuthenticationPrincipal AuthPrinciple authPrinciple ); ResponseEntity<GroupJoinRespondResponse> respondToJoinRequest( - @Parameter(hidden = true) @AuthenticationPrincipal AuthPrinciple authPrinciple, @Parameter(description = "그룹 ID", example = "123") Long groupId, @Parameter(description = "가입신청 ID", example = "456") Long joinId, @io.swagger.v3.oas.annotations.parameters.RequestBody( description = "승인/거절 상태", required = true, content = @Content(schema = @Schema(implementation = GroupJoinRespondRequest.class)) ) - @Valid GroupJoinRespondRequest req + @Valid GroupJoinRespondRequest req, + @Parameter(hidden = true) @AuthenticationPrincipal AuthPrinciple authPrinciple ); -public ResponseEntity<Void> groupJoinDelete( - @Parameter(hidden = true) @AuthenticationPrincipal AuthPrinciple authPrinciple, - @Parameter(description = "그룹 ID", required = true, example = "123") Long groupId, - @Parameter(description = "가입신청 ID", required = true, example = "456") Long joinId +ResponseEntity<Void> groupJoinDelete( + @Parameter(description = "그룹 ID", required = true, example = "123") Long groupId, + @Parameter(description = "가입신청 ID", required = true, example = "456") Long joinId, + @Parameter(hidden = true) @AuthenticationPrincipal AuthPrinciple authPrinciple ); -public ResponseEntity<FindGroupJoinListMeResponse> findGroupJoinMe( +ResponseEntity<FindGroupJoinListMeResponse> findGroupJoinMe( @Parameter(hidden = true) @AuthenticationPrincipal AuthPrinciple authPrinciple );Also applies to: 64-67, 82-92, 105-109, 121-123
73-81: respondToJoinRequest: 오류 응답 예시 통일(403/404) 제안해당 메서드에서는 403/404의 예시가 누락되어 있어, 다른 엔드포인트와 동일하게 ExampleObject로 명시하면 좋습니다.
@ApiResponses({ @ApiResponse(responseCode = "200", description = "응답 처리 성공", content = @Content(schema = @Schema(implementation = GroupJoinRespondResponse.class))), @ApiResponse(responseCode = "401", description = "인증 실패"), - @ApiResponse(responseCode = "403", description = "권한 없음 → GROUP_JOIN_002"), - @ApiResponse(responseCode = "404", description = "가입신청 없음 → GROUP_JOIN_004"), + @ApiResponse(responseCode = "403", description = "권한 없음 → GROUP_JOIN_002", + content = @Content( + mediaType = "application/json", + examples = @io.swagger.v3.oas.annotations.media.ExampleObject( + name = "GROUP_JOIN_002", + value = "{\"code\":\"GROUP_JOIN_002\",\"message\":\"그룹 내 권한이 없습니다.\"}" + ) + ) + ), + @ApiResponse(responseCode = "404", description = "가입신청 없음 → GROUP_JOIN_004", + content = @Content( + mediaType = "application/json", + examples = @io.swagger.v3.oas.annotations.media.ExampleObject( + name = "GROUP_JOIN_004", + value = "{\"code\":\"GROUP_JOIN_004\",\"message\":\"가입신청을 찾을 수 없습니다.\"}" + ) + ) + ),
94-99: 문서 표현 일관성(‘가입 신청’ vs ‘가입신청’ 표기)요약/설명에서 띄어쓰기 표기가 혼재되어 있습니다. 한 가지로 통일하면 검색성과 가독성이 좋아집니다. 예: 모두 ‘가입 신청’로 통일.
Also applies to: 111-116
105-109: interface 메서드의 public 키워드 불필요 — 제거로 일관성 확보Java interface 메서드는 암묵적으로 public입니다. 일부 메서드만 public을 명시해 스타일이 섞여 있어 제거 권장(위 파라미터 순서 정리 diff에 포함).
Also applies to: 121-123
src/main/java/project/flipnote/group/service/GroupService.java (1)
114-139: 권한 시드 동시성 처리 👍 + 로그/미세 최적화 제안
- getOrCreateGroupPermissions로 누락 enum을 채우고 경합을 DataIntegrityViolationException으로 흡수하는 접근 괜찮습니다.
- 예외를 완전히 무시하면 원인 추적이 어려우니 debug 로그를 남기길 권장합니다.
- Set 구축 시 EnumSet을 쓰면 메모리/성능에 유리합니다.
제안 diff:
@@ - Set<GroupPermissionStatus> existing = all.stream() - .map(GroupPermission::getName) - .collect(Collectors.toSet()); + Set<GroupPermissionStatus> existing = all.stream() + .map(GroupPermission::getName) + .collect(Collectors.toCollection(() -> java.util.EnumSet.noneOf(GroupPermissionStatus.class))); @@ - if (!missing.isEmpty()) { + if (!missing.isEmpty()) { try { groupPermissionRepository.saveAll(missing); - } catch (DataIntegrityViolationException ignore) { - // 다른 트랜잭션이 먼저 넣은 경우: 무시하고 재조회 + } catch (DataIntegrityViolationException e) { + // 다른 트랜잭션이 먼저 넣은 경우: 무시하고 재조회 + log.debug("GroupPermission 동시 생성 경합 감지: {}", e.getMessage()); } all = groupPermissionRepository.findAll(); } return all;Also applies to: 184-184
src/main/java/project/flipnote/group/controller/docs/GroupControllerDocs.java (1)
187-197: 미사용 더미 파라미터는 제거하거나 숨김 처리 권장sortBy/order가 실제로 사용되지 않는다면 문서에서 제거하거나 hidden=true로 숨겨 노이즈를 줄이는 것이 좋습니다. deprecated만으론 UI에 계속 노출됩니다.
예시(제거):
- @Parameter( - name = "sortBy", - description = "(더미) 현재 미사용", - example = "string", - deprecated = true - ), - @Parameter( - name = "order", - description = "(더미) 현재 미사용", - example = "string", - deprecated = true - )또는 숨김 처리:
- @Parameter(name = "sortBy", description = "(더미) 현재 미사용", example = "string", deprecated = true), - @Parameter(name = "order", description = "(더미) 현재 미사용", example = "string", deprecated = true) + @Parameter(name = "sortBy", hidden = true, deprecated = true), + @Parameter(name = "order", hidden = true, deprecated = true)Also applies to: 235-245
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (19)
src/main/java/project/flipnote/group/controller/GroupController.java(2 hunks)src/main/java/project/flipnote/group/controller/docs/GroupControllerDocs.java(1 hunks)src/main/java/project/flipnote/group/model/GroupCreateRequest.java(1 hunks)src/main/java/project/flipnote/group/model/GroupPutRequest.java(1 hunks)src/main/java/project/flipnote/group/service/GroupService.java(3 hunks)src/main/java/project/flipnote/groupjoin/controller/GroupJoinController.java(1 hunks)src/main/java/project/flipnote/groupjoin/controller/docs/GroupJoinControllerDocs.java(1 hunks)src/main/java/project/flipnote/groupjoin/model/FindGroupJoinListMeResponse.java(1 hunks)src/main/java/project/flipnote/groupjoin/model/GroupJoinInfo.java(1 hunks)src/main/java/project/flipnote/groupjoin/model/GroupJoinListResponse.java(1 hunks)src/main/java/project/flipnote/groupjoin/model/GroupJoinRespondRequest.java(1 hunks)src/main/java/project/flipnote/groupjoin/model/MyGroupJoinInfo.java(1 hunks)src/main/java/project/flipnote/groupjoin/repository/GroupJoinRepository.java(1 hunks)src/main/java/project/flipnote/groupjoin/repository/GroupJoinRepositoryCustom.java(1 hunks)src/main/java/project/flipnote/groupjoin/repository/GroupJoinRepositoryImpl.java(1 hunks)src/main/java/project/flipnote/groupjoin/service/GroupJoinService.java(5 hunks)src/main/java/project/flipnote/image/controller/ImageUploadController.java(1 hunks)src/main/java/project/flipnote/image/controller/docs/ImageUploadControllerDocs.java(1 hunks)src/main/java/project/flipnote/image/model/ImageUploadRequestDto.java(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (17)
src/main/java/project/flipnote/groupjoin/model/GroupJoinInfo.java (1)
src/main/java/project/flipnote/groupjoin/entity/GroupJoin.java (1)
Getter(22-65)
src/main/java/project/flipnote/group/model/GroupCreateRequest.java (3)
src/main/java/project/flipnote/group/model/GroupInvitationCreateRequest.java (1)
GroupInvitationCreateRequest(6-10)src/main/java/project/flipnote/group/entity/Group.java (2)
Getter(30-119)changeGroup(110-118)src/main/java/project/flipnote/cardset/model/CreateCardSetRequest.java (1)
CreateCardSetRequest(12-30)
src/main/java/project/flipnote/image/model/ImageUploadRequestDto.java (5)
src/main/java/project/flipnote/cardset/model/CardSetUpdateRequest.java (1)
CardSetUpdateRequest(13-36)src/main/java/project/flipnote/auth/model/PasswordResetRequest.java (1)
PasswordResetRequest(6-14)src/main/java/project/flipnote/cardset/model/CreateCardSetRequest.java (1)
CreateCardSetRequest(12-30)src/main/java/project/flipnote/user/model/UserUpdateRequest.java (1)
UserUpdateRequest(8-25)src/main/java/project/flipnote/group/model/GroupInvitationCreateRequest.java (1)
GroupInvitationCreateRequest(6-10)
src/main/java/project/flipnote/groupjoin/model/GroupJoinRespondRequest.java (3)
src/main/java/project/flipnote/group/model/GroupInvitationRespondRequest.java (1)
GroupInvitationRespondRequest(6-17)src/main/java/project/flipnote/groupjoin/entity/GroupJoin.java (2)
Getter(22-65)updateStatus(62-64)src/main/java/project/flipnote/groupjoin/model/GroupJoinResponse.java (1)
GroupJoinResponse(5-11)
src/main/java/project/flipnote/groupjoin/model/MyGroupJoinInfo.java (2)
src/main/java/project/flipnote/groupjoin/entity/GroupJoin.java (2)
Getter(22-65)updateStatus(62-64)src/main/java/project/flipnote/groupjoin/model/GroupJoinResponse.java (1)
GroupJoinResponse(5-11)
src/main/java/project/flipnote/groupjoin/model/GroupJoinListResponse.java (1)
src/main/java/project/flipnote/group/model/FindGroupMemberResponse.java (1)
FindGroupMemberResponse(5-11)
src/main/java/project/flipnote/group/controller/docs/GroupControllerDocs.java (2)
src/main/java/project/flipnote/group/controller/docs/GroupInvitationControllerDocs.java (3)
Tag(13-28)Operation(16-19)Operation(24-27)src/main/java/project/flipnote/auth/controller/docs/AuthControllerDocs.java (1)
AuthControllerDocs(19-53)
src/main/java/project/flipnote/group/service/GroupService.java (4)
src/main/java/project/flipnote/group/entity/GroupPermission.java (2)
Entity(12-29)Builder(25-28)src/main/java/project/flipnote/group/entity/GroupRolePermission.java (2)
Entity(11-41)Builder(35-40)src/main/java/project/flipnote/group/repository/GroupRolePermissionRepository.java (1)
Repository(13-18)src/main/java/project/flipnote/group/repository/GroupPermissionRepository.java (1)
Repository(9-12)
src/main/java/project/flipnote/groupjoin/repository/GroupJoinRepositoryImpl.java (2)
src/main/java/project/flipnote/group/repository/GroupMemberRepositoryImpl.java (1)
RequiredArgsConstructor(13-35)src/main/java/project/flipnote/groupjoin/entity/GroupJoin.java (1)
Getter(22-65)
src/main/java/project/flipnote/groupjoin/controller/GroupJoinController.java (2)
src/main/java/project/flipnote/image/controller/ImageUploadController.java (1)
RestController(18-31)src/main/java/project/flipnote/group/controller/GroupController.java (1)
RequiredArgsConstructor(32-109)
src/main/java/project/flipnote/image/controller/docs/ImageUploadControllerDocs.java (3)
src/main/java/project/flipnote/auth/controller/docs/AuthControllerDocs.java (3)
AuthControllerDocs(19-53)Operation(36-37)Operation(21-22)src/main/java/project/flipnote/group/controller/docs/GroupInvitationControllerDocs.java (1)
Tag(13-28)src/main/java/project/flipnote/user/controller/docs/UserControllerDocs.java (1)
Tag(14-28)
src/main/java/project/flipnote/image/controller/ImageUploadController.java (3)
src/main/java/project/flipnote/groupjoin/controller/GroupJoinController.java (1)
RestController(15-77)src/main/java/project/flipnote/group/controller/GroupController.java (1)
RequiredArgsConstructor(32-109)src/main/java/project/flipnote/auth/controller/docs/AuthControllerDocs.java (1)
AuthControllerDocs(19-53)
src/main/java/project/flipnote/groupjoin/repository/GroupJoinRepository.java (4)
src/main/java/project/flipnote/group/repository/GroupMemberRepository.java (1)
Repository(14-29)src/main/java/project/flipnote/groupjoin/entity/GroupJoin.java (1)
Getter(22-65)src/main/java/project/flipnote/group/repository/GroupMemberRepositoryImpl.java (1)
RequiredArgsConstructor(13-35)src/main/java/project/flipnote/group/repository/GroupMemberRepositoryCustom.java (1)
GroupMemberRepositoryCustom(7-9)
src/main/java/project/flipnote/groupjoin/repository/GroupJoinRepositoryCustom.java (3)
src/main/java/project/flipnote/group/repository/GroupRepositoryCustom.java (1)
GroupRepositoryCustom(8-12)src/main/java/project/flipnote/group/repository/GroupMemberRepositoryCustom.java (2)
GroupMemberRepositoryCustom(7-9)findGroupMembers(8-8)src/main/java/project/flipnote/groupjoin/entity/GroupJoin.java (1)
Getter(22-65)
src/main/java/project/flipnote/groupjoin/controller/docs/GroupJoinControllerDocs.java (2)
src/main/java/project/flipnote/group/controller/docs/GroupInvitationControllerDocs.java (3)
Tag(13-28)Operation(24-27)Operation(16-19)src/main/java/project/flipnote/group/controller/docs/GroupInvitationQueryControllerDocs.java (2)
Tag(14-29)Operation(24-28)
src/main/java/project/flipnote/group/model/GroupPutRequest.java (3)
src/main/java/project/flipnote/group/entity/Group.java (1)
changeGroup(110-118)src/main/java/project/flipnote/group/model/GroupPutResponse.java (1)
GroupPutResponse(8-40)src/test/java/project/flipnote/group/service/GroupServiceTest.java (1)
Test(362-403)
src/main/java/project/flipnote/groupjoin/service/GroupJoinService.java (2)
src/main/java/project/flipnote/groupjoin/entity/GroupJoin.java (1)
Getter(22-65)src/test/java/project/flipnote/groupjoin/service/GroupJoinServiceTest.java (1)
ExtendWith(35-283)
⏰ 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 (13)
src/main/java/project/flipnote/image/controller/ImageUploadController.java (1)
21-21: 문서 인터페이스 구현 일치 — 잘 반영됨컨트롤러가 docs 인터페이스를 구현하도록 정리된 점 좋습니다. Swagger 스펙과 시그니처 동기화에 도움이 됩니다.
src/main/java/project/flipnote/groupjoin/controller/GroupJoinController.java (1)
18-18: Docs 인터페이스 구현 LGTM컨트롤러가 GroupJoinControllerDocs를 구현하도록 한 방향성 좋습니다. 시그니처/매핑 일치만 유지해 주세요.
src/main/java/project/flipnote/groupjoin/model/GroupJoinListResponse.java (1)
8-11: DTO로의 전환 LGTM엔티티 노출을 List로 치환한 점 적절합니다. 팩토리 메서드도 간결합니다.
src/main/java/project/flipnote/groupjoin/model/FindGroupJoinListMeResponse.java (1)
8-12: 내 신청 리스트 DTO 전환 LGTM엔티티 노출 최소화 방향에 부합합니다.
src/main/java/project/flipnote/groupjoin/model/GroupJoinInfo.java (2)
12-14: 정적 팩토리 메서드 from 구성 적절합니다레코드 컴포넌트 순서와 일치하며, 불변 DTO로 사용하기에 적합합니다.
5-11: UserProfile 엔티티에nickname필드 존재 확인 완료
src/main/java/project/flipnote/user/entity/UserProfile.java39행에private String nickname;으로 선언되어 있어 QueryDSL 프로젝션 그대로 사용 가능합니다.src/main/java/project/flipnote/groupjoin/model/MyGroupJoinInfo.java (1)
5-11: 레코드 구성 적절필드 구성이 의도와 일치하며 DTO 용도로 적합합니다.
src/main/java/project/flipnote/groupjoin/repository/GroupJoinRepository.java (1)
13-15: 커스텀 레포지토리 확장 구조 적절읽기 전용 DTO 프로젝션으로 전환된 설계가 서비스 단 단순화를 돕습니다.
existsByGroup_idAndUser_id유지도 합리적입니다.src/main/java/project/flipnote/groupjoin/repository/GroupJoinRepositoryImpl.java (1)
31-33: UserProfile.nickname 필드 사용 검증 필요프로젝션에
groupJoin.user.nickname을 사용합니다.UserProfile에 해당 필드가 없으면 QueryDSL 코드 생성/실행 시 오류가 납니다.name등 실제 필드명과 DTO(GroupJoinInfo.nickname)를 일치시키세요.위 파일의 검증 스크립트(첫 파일 코멘트)를 재사용해 필드 존재를 확인해 주세요.
src/main/java/project/flipnote/groupjoin/controller/docs/GroupJoinControllerDocs.java (2)
1-124: 전체적으로 품질 양호보안 스키마 적용, Principal hidden 처리, 요청 본문 @Valid, 상태코드 정의가 잘 정리되어 있습니다.
26-92: 확인 완료: Docs와 컨트롤러 구현 일치
모든 메서드 시그니처, @PathVariable 이름·순서, 에러코드 정의가 Docs 인터페이스와 일치합니다.src/main/java/project/flipnote/group/controller/GroupController.java (1)
21-21: 문서 인터페이스 구현 방향 좋습니다컨트롤러가 GroupControllerDocs를 구현하도록 바꾼 점 좋습니다. 시그니처 불일치를 컴파일 타임에 막고, springdoc가 인터페이스의 어노테이션을 반영해 스웨거 스펙을 생성할 수 있습니다.
Also applies to: 35-35
src/main/java/project/flipnote/group/controller/docs/GroupControllerDocs.java (1)
169-173:cursor파라미터명은 실제 DTO 필드명(cursor)과 일치하므로 변경 불필요Likely an incorrect or invalid review comment.
📝 변경 내용
✅ 체크리스트
💬 기타 참고 사항
Summary by CodeRabbit