Conversation
1. 먼저 이미지 생성 2. 모임 내용 생성
|
Caution Review failedThe pull request is closed. Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. Walkthrough모임 이미지를 먼저 사전 업로드한 뒤 이미지 URL을 사용해 모임을 생성하도록 API, DTO, 서비스 및 컨트롤러 흐름을 변경합니다. 그룹 엔티티의 Changes
Sequence DiagramsequenceDiagram
participant Client
participant GroupImageCtrl as GroupImageController
participant GroupImageSvc as GroupImageService
participant ImageUploadSvc as ImageUploadService
participant GroupCtrl as GroupController
participant GroupSvc as GroupService
participant DB as Database
rect rgb(200,220,240)
note over Client,GroupImageSvc: 단계 1 — 이미지 사전 업로드
Client->>GroupImageCtrl: POST /upload (multipart images)
GroupImageCtrl->>GroupImageSvc: uploadGroupImages(images)
loop 각 이미지
GroupImageSvc->>ImageUploadSvc: uploadAsWebpWithSizes(file, sizes)
ImageUploadSvc-->>GroupImageSvc: 반환 (mainUrl 440x240, thumbUrl 100x100)
end
GroupImageSvc-->>GroupImageCtrl: PreUploadGroupImageResponse(images: [{sort, main, thumb},...])
GroupImageCtrl-->>Client: 200 OK (이미지 URL 목록)
end
rect rgb(220,240,200)
note over Client,GroupSvc: 단계 2 — 이미지 URL로 모임 생성
Client->>GroupCtrl: POST /groups (CreateGroupRequest + images URLs)
GroupCtrl->>GroupSvc: createGroup(hostUserId, request)
GroupSvc->>DB: Host 조회, Group 저장
GroupSvc->>GroupSvc: saveGroupImagesByUrl(request.images) -> GroupImage 엔티티 저장
GroupSvc->>DB: 태그/참여자 연결 저장
GroupSvc-->>GroupCtrl: CreateGroupResponse (images 포함)
GroupCtrl-->>Client: 201 Created (모임 + 이미지 정보)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/java/team/wego/wegobackend/group/application/service/GroupImageService.java (1)
75-140: Remove unusedsaveGroupImagesmethodThis private method is no longer called anywhere in the codebase. The new flow uses
GroupService.saveGroupImagesByUrlinstead. Delete this method to reduce code clutter.
🧹 Nitpick comments (6)
src/main/java/team/wego/wegobackend/group/application/dto/request/CreateGroupImageRequest.java (1)
3-7: 요청 DTO에 유효성 검증 어노테이션 추가를 권장합니다.
CreateGroupRequest의 다른 필드들처럼 이 요청 DTO에도 유효성 검증이 필요합니다. 이미지 URL이 필수라면@NotBlank, 정렬 순서가 필수라면@NotNull어노테이션을 추가하는 것이 좋습니다.package team.wego.wegobackend.group.application.dto.request; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + public record CreateGroupImageRequest( + @NotNull(message = "이미지: 정렬 순서는 필수입니다.") Integer sortOrder, + @NotBlank(message = "이미지: 440x240 URL은 필수입니다.") String imageUrl440x240, + @NotBlank(message = "이미지: 100x100 URL은 필수입니다.") String imageUrl100x100 ) {}src/main/java/team/wego/wegobackend/group/application/dto/request/CreateGroupRequest.java (1)
37-39: 중첩 객체 유효성 검증을 위해@Valid어노테이션이 필요합니다.
CreateGroupImageRequest에 유효성 검증 어노테이션을 추가하더라도, 리스트 내부 객체들에 대한 검증이 동작하려면@Valid어노테이션이 필요합니다.+ @Valid List<CreateGroupImageRequest> images
jakarta.validation.Valid를 import해야 합니다.src/main/java/team/wego/wegobackend/group/application/service/GroupService.java (1)
177-196: O(n²) 매칭 로직 개선 고려현재
sorted리스트를 순회하며 URL로 매칭하고 있습니다. 이미지 수가 최대 3개로 제한되어 있어 성능 이슈는 없지만, 가독성과 유지보수성을 위해 인덱스 기반 매칭을 고려해 보세요.- return images.stream() - .map(image -> { - // 요청에서 매칭되는 썸네일 URL 찾아오기 - CreateGroupImageRequest matched = sorted.stream() - .filter(req -> Objects.equals( - req.imageUrl440x240(), - image.getImageUrl() - )) - .findFirst() - .orElse(null); - - String thumbUrl = matched != null ? matched.imageUrl100x100() : null; - - return GroupImageItemResponse.from( - image, - image.getImageUrl(), // 440x240 - thumbUrl // 100x100 - ); - }) - .toList(); + List<GroupImageItemResponse> result = new ArrayList<>(); + for (int i = 0; i < images.size(); i++) { + GroupImage image = images.get(i); + CreateGroupImageRequest req = sorted.get(i); + result.add(GroupImageItemResponse.from( + image, + image.getImageUrl(), + req.imageUrl100x100() + )); + } + return result;src/main/java/team/wego/wegobackend/group/application/dto/response/GetGroupResponse.java (1)
66-66: TODO 주석 확인 필요
joinedCount가 하드코딩되어 있고 TODO 주석이 있습니다. 이 값이 참여 인원수를 나타낸다면attendUserCount와 동일하게 계산되어야 할 것 같습니다. 의도한 동작이 무엇인지 확인 후 수정이 필요합니다.이 부분을 구현하는 데 도움이 필요하시면 말씀해 주세요.
src/main/java/team/wego/wegobackend/group/presentation/GroupImageController.java (1)
36-38: 미완성 주석 정리 필요"모임 이미지 수정" 주석만 있고 구현이 없습니다. 구현 예정이라면 TODO로 표시하거나, 불필요하다면 제거해 주세요.
src/main/java/team/wego/wegobackend/group/application/service/GroupImageService.java (1)
30-35: 중복된 null/empty 검증
validateCreateGroupImageRequest(images)를 호출한 직후 다시images == null || images.isEmpty()체크를 수행합니다. 검증 메서드에서 이미 이 케이스를 처리하므로 중복입니다.public PreUploadGroupImageResponse uploadGroupImages(List<MultipartFile> images) { validateCreateGroupImageRequest(images); - if (images == null || images.isEmpty()) { - return new PreUploadGroupImageResponse(List.of()); - } + // validateCreateGroupImageRequest에서 null/empty를 허용하므로 여기서도 처리 필요 + if (images == null || images.isEmpty()) { + return new PreUploadGroupImageResponse(List.of()); + }또는
validateCreateGroupImageRequest내에서 빈 응답을 반환하도록 리팩토링하세요.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
src/main/java/team/wego/wegobackend/group/application/dto/request/CreateGroupImageRequest.java(1 hunks)src/main/java/team/wego/wegobackend/group/application/dto/request/CreateGroupRequest.java(1 hunks)src/main/java/team/wego/wegobackend/group/application/dto/response/CreateGroupResponse.java(3 hunks)src/main/java/team/wego/wegobackend/group/application/dto/response/GetGroupResponse.java(1 hunks)src/main/java/team/wego/wegobackend/group/application/dto/response/PreUploadGroupImageItemResponse.java(1 hunks)src/main/java/team/wego/wegobackend/group/application/dto/response/PreUploadGroupImageResponse.java(1 hunks)src/main/java/team/wego/wegobackend/group/application/service/GroupImageService.java(2 hunks)src/main/java/team/wego/wegobackend/group/application/service/GroupService.java(3 hunks)src/main/java/team/wego/wegobackend/group/domain/entity/Group.java(1 hunks)src/main/java/team/wego/wegobackend/group/presentation/GroupController.java(3 hunks)src/main/java/team/wego/wegobackend/group/presentation/GroupImageController.java(2 hunks)src/test/http/group/create.http(4 hunks)
⏰ 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: CodeQL analysis (java)
- GitHub Check: Agent
🔇 Additional comments (7)
src/main/java/team/wego/wegobackend/group/application/dto/response/PreUploadGroupImageResponse.java (1)
5-7: LGTM!사전 업로드 이미지 응답을 위한 간결한 래퍼 레코드입니다. 구조가 적절합니다.
src/main/java/team/wego/wegobackend/group/application/dto/response/PreUploadGroupImageItemResponse.java (1)
3-7: LGTM!이미지 정렬 순서와 두 가지 크기의 URL을 포함하는 명확한 응답 DTO입니다.
src/main/java/team/wego/wegobackend/group/presentation/GroupController.java (1)
33-33: LGTM!
groupService.createGroup메서드 호출이 올바르게 업데이트되었습니다.src/main/java/team/wego/wegobackend/group/application/dto/response/CreateGroupResponse.java (1)
31-38: LGTM!팩토리 메서드 오버로딩이 깔끔하게 구현되었습니다. 이미지가 없는 경우 빈 리스트를 기본값으로 사용하는 것도 적절합니다.
src/main/java/team/wego/wegobackend/group/application/service/GroupService.java (1)
105-138: LGTM!호스트 조회, 그룹 생성, 그룹 사용자 저장, 태그 저장, 이미지 저장의 흐름이 명확하고 트랜잭션 범위 내에서 일관되게 처리됩니다.
src/main/java/team/wego/wegobackend/group/application/dto/response/GetGroupResponse.java (1)
34-42: The null safety concern is not applicable. ThegroupTagsandusersfields in the Group entity are initialized asnew ArrayList<>()at declaration (lines 66 and 69), ensuring they will never be null. The stream operations in lines 34-42 are safe and will return empty streams if no records are loaded, not throw a NullPointerException.Likely an incorrect or invalid review comment.
src/main/java/team/wego/wegobackend/group/application/service/GroupImageService.java (1)
53-56: This concern is not applicable to this code.The
uploadAsWebpWithSizesmethod returns a list with size equal towidths.size(). SinceGROUP_WIDTHSis defined asList.of(440, 100)(always 2 elements) and the method loopsfor (int i = 0; i < widths.size(); i++)adding one element per iteration, the returned list is guaranteed to contain exactly 2 elements. Therefore,variants.get(0)andvariants.get(1)are always safe.Likely an incorrect or invalid review comment.
| CreatedBy createdByHost = new CreatedBy( | ||
| host.getId(), | ||
| host.getNickName(), | ||
| host.getProfileImage()); | ||
| host.getProfileImage() | ||
| ); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for CreatedBy record/class definition
rg -n --type=java 'record CreatedBy|class CreatedBy' -A 5
# Also check imports in the file under review
echo "=== Checking imports in CreateGroupResponse.java ==="
head -30 src/main/java/team/wego/wegobackend/group/application/dto/response/CreateGroupResponse.javaRepository: WeGo-Together/WeGo_BackEnd
Length of output: 1063
🏁 Script executed:
#!/bin/bash
# Search for any mention of CreatedBy in all Java files
echo "=== Searching for CreatedBy anywhere in Java files ==="
rg -n 'CreatedBy' --type=java
# Get the full CreateGroupResponse.java file
echo -e "\n=== Full CreateGroupResponse.java file ==="
cat src/main/java/team/wego/wegobackend/group/application/dto/response/CreateGroupResponse.javaRepository: WeGo-Together/WeGo_BackEnd
Length of output: 3197
🏁 Script executed:
#!/bin/bash
# Search for CreatedBy.java file
echo "=== Searching for CreatedBy.java file ==="
find . -name "*CreatedBy*" -type f
# Search in the response package directory
echo -e "\n=== Files in response package ==="
ls -la src/main/java/team/wego/wegobackend/group/application/dto/response/
# Search for nested record/class in any response file
echo -e "\n=== Checking for nested CreatedBy definition ==="
rg -n 'record CreatedBy|class CreatedBy' --type=java -B 2 -A 10Repository: WeGo-Together/WeGo_BackEnd
Length of output: 777
🏁 Script executed:
#!/bin/bash
# Check GetGroupResponse.java for comparison
echo "=== GetGroupResponse.java ==="
cat src/main/java/team/wego/wegobackend/group/application/dto/response/GetGroupResponse.javaRepository: WeGo-Together/WeGo_BackEnd
Length of output: 2410
CreatedBy 레코드 정의가 누락되었습니다.
CreatedBy는 이 파일뿐만 아니라 GetGroupResponse.java에서도 참조되고 있지만, 현재 코드베이스 어디에도 정의되어 있지 않습니다. 컴파일 오류를 발생시킵니다. CreatedBy 레코드를 생성해야 합니다:
public record CreatedBy(Long id, String nickName, String profileImage) {}이 레코드는 같은 패키지(team.wego.wegobackend.group.application.dto.response)에 정의하거나, 다른 위치에 정의 후 import 문을 추가해야 합니다.
🤖 Prompt for AI Agents
In
src/main/java/team/wego/wegobackend/group/application/dto/response/CreateGroupResponse.java
around lines 53 to 57, the code references a CreatedBy record that is not
defined causing compilation errors; add a record declaration public record
CreatedBy(Long id, String nickName, String profileImage) {} in the same package
(team.wego.wegobackend.group.application.dto.response) — either add it to this
file or create a new CreatedBy.java in that package and, if placed elsewhere,
add the appropriate import to CreateGroupResponse.java (and similarly ensure
GetGroupResponse.java can access it).
| @Column(name = "end_time") | ||
| private LocalDateTime endTime; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for endTime usage across the codebase (excluding Group.java)
rg -n --type=java -C3 'endTime|end_time' --glob '!**/Group.java' | head -200Repository: WeGo-Together/WeGo_BackEnd
Length of output: 6290
🏁 Script executed:
#!/bin/bash
# Check CreateGroupRequest definition
cat src/main/java/team/wego/wegobackend/group/application/dto/request/CreateGroupRequest.java
# Also search for any sorting or filtering operations on endTime
rg -n --type=java 'endTime.*sort|OrderBy.*endTime|endTime.*query|\.endTime' | head -100Repository: WeGo-Together/WeGo_BackEnd
Length of output: 1928
endTime nullable change introduces NullPointerException risk in validation logic.
endTime in CreateGroupRequest lacks @NotNull annotation (only @Future is present), which means it can be null. However, GroupService.validateCreateGroupRequest() at line 44 calls request.endTime().isAfter(request.startTime()) without null checking. Since @Future validation allows null values, a null endTime will bypass validation and trigger a NullPointerException when the comparison executes.
Add @NotNull annotation to endTime in CreateGroupRequest or implement null-safe handling in the validation method before calling .isAfter().
🤖 Prompt for AI Agents
In src/main/java/team/wego/wegobackend/group/domain/entity/Group.java around
lines 46-47, the DTO's endTime can be null and causes NPE in
GroupService.validateCreateGroupRequest() when calling
request.endTime().isAfter(...); fix by adding @NotNull to the endTime field in
CreateGroupRequest (import javax.validation.constraints.NotNull) so Bean
Validation rejects nulls before service logic runs, and run/update any
validation tests; alternatively, if you prefer defensive coding, add a null
check in GroupService.validateCreateGroupRequest() before calling .isAfter() and
return/throw a clear validation exception when endTime is null.
| // 모임 상세 조회 | ||
| @PostMapping("/{groupId}") | ||
| public ResponseEntity<ApiResponse<GetGroupResponse>> getGroupResponse( | ||
| @PathVariable Long groupId | ||
| ) { | ||
| // GetGroupResponse response = groupService.getGroup(groupId); | ||
|
|
||
| return ResponseEntity.noContent().build(); | ||
| } |
There was a problem hiding this comment.
HTTP 메서드가 잘못되었습니다.
getGroupResponse는 조회 작업이므로 @PostMapping 대신 @GetMapping을 사용해야 합니다. 또한 204 No Content 응답은 조회 작업에 적합하지 않습니다.
- // 모임 상세 조회
- @PostMapping("/{groupId}")
- public ResponseEntity<ApiResponse<GetGroupResponse>> getGroupResponse(
- @PathVariable Long groupId
- ) {
-// GetGroupResponse response = groupService.getGroup(groupId);
-
- return ResponseEntity.noContent().build();
- }
+ // 모임 상세 조회
+ @GetMapping("/{groupId}")
+ public ResponseEntity<ApiResponse<GetGroupResponse>> getGroupResponse(
+ @PathVariable Long groupId
+ ) {
+ GetGroupResponse response = groupService.getGroup(groupId);
+ return ResponseEntity.ok(ApiResponse.success(response));
+ }미구현 상태라면 해당 엔드포인트를 제거하거나 별도 PR에서 구현하는 것을 권장합니다.
🤖 Prompt for AI Agents
In src/main/java/team/wego/wegobackend/group/presentation/GroupController.java
around lines 40 to 48, the endpoint is declared with @PostMapping and returns
204 No Content but it represents a read operation; change the mapping to
@GetMapping("/{groupId}") and return an appropriate ResponseEntity with the
GetGroupResponse body (e.g., ResponseEntity.ok(response)) after implementing the
service call, or if the handler is not yet implemented remove the method
entirely or move it to a follow-up PR until the retrieval logic is added.
| @PostMapping("/upload") | ||
| public ResponseEntity<ApiResponse<PreUploadGroupImageResponse>> uploadImages( | ||
| @RequestParam("images") List<MultipartFile> images | ||
| ) { | ||
| CreateGroupImageResponse response = groupImageService.createGroupImage(userId, groupId, | ||
| PreUploadGroupImageResponse response = groupImageService.uploadGroupImages( | ||
| images); |
There was a problem hiding this comment.
userId 쿼리 파라미터 불일치
테스트 파일(create.http)에서는 ?userId={{userId}}를 전달하지만, 이 컨트롤러에서는 해당 파라미터를 받지 않습니다. 의도적으로 제거한 것이라면 테스트 파일도 업데이트해 주세요. 향후 사용자 인증이 필요하다면 Spring Security나 세션 기반 인증을 고려하세요.
🤖 Prompt for AI Agents
In
src/main/java/team/wego/wegobackend/group/presentation/GroupImageController.java
around lines 24-29, the controller method lacks the userId request parameter
while tests send ?userId={{userId}}; either add a request parameter to the
controller signature (e.g., add @RequestParam("userId") Long userId) and forward
it to the service call as required, or update the test create.http to stop
sending userId if it is intentionally unused; choose the approach consistent
with intended behavior (if authentication will be added later, prefer removing
test param or switch tests to authenticate properly).
| ### 3. 모임 이미지 선 업로드 (4장 → 예외 발생) | ||
| POST http://localhost:8080/api/v1/groups/images/upload?userId={{userId}} | ||
| Content-Type: multipart/form-data; boundary=boundary | ||
|
|
||
| --boundary-- | ||
| --boundary | ||
| Content-Disposition: form-data; name="images"; filename="test-webp1.webp" | ||
| Content-Type: image/webp | ||
|
|
||
| < ../image/resources/test-webp1.webp | ||
| --boundary-- | ||
| Content-Disposition: form-data; name="images"; filename="test-webp1.webp" | ||
| --boundary | ||
| Content-Disposition: form-data; name="images"; filename="test-webp2.webp" | ||
| Content-Type: image/webp | ||
|
|
||
| < ../image/resources/test-webp1.webp | ||
| --boundary-- | ||
| < ../image/resources/test-webp2.webp | ||
| --boundary | ||
| Content-Disposition: form-data; name="images"; filename="img1.png" | ||
| Content-Type: image/png | ||
|
|
||
| < ../image/resources/img1.png | ||
| --boundary-- | ||
| --boundary | ||
| Content-Disposition: form-data; name="images"; filename="img2.jpg" | ||
| Content-Type: image/jpeg | ||
|
|
||
| < ../image/resources/img2.jpg | ||
| --boundary-- | ||
|
|
||
| --boundary-- No newline at end of file |
There was a problem hiding this comment.
멀티파트 boundary 형식 불일치
테스트 1-1과 2-1에서는 --boundary--를 사용하지만, 테스트 3에서는 --boundary를 사용합니다. RFC 2046에 따르면 각 파트는 --boundary로 시작하고, 마지막 파트만 --boundary--로 끝나야 합니다. 현재 테스트 1-1과 2-1의 형식이 잘못되었을 수 있습니다.
올바른 형식 예시:
--boundary
Content-Disposition: form-data; name="images"; filename="img1.png"
...
--boundary
Content-Disposition: form-data; name="images"; filename="img2.jpg"
...
--boundary--
🤖 Prompt for AI Agents
In src/test/http/group/create.http around lines 155-179, the multipart/form-data
examples use inconsistent boundary markers (some parts end with `--boundary--`
prematurely while others use `--boundary`), violating RFC 2046; fix by ensuring
every part separator uses `--boundary` and only the final closing boundary uses
`--boundary--` (update the affected test cases so each part starts with
`--boundary` and append a single `--boundary--` after the last file).
There was a problem hiding this comment.
Pull request overview
This PR refactors the group creation flow from a two-step process (create group → upload images) to a more streamlined approach (upload images → create group with URLs). The change allows clients to first upload images and receive URLs, then include those URLs when creating a group, improving the API design and error handling.
Key Changes:
- New pre-upload endpoint for group images that returns URLs before group creation
- Modified group creation to accept image URLs in the request payload
- Made
endTimeoptional in the Group entity schema
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| src/main/java/team/wego/wegobackend/group/presentation/GroupImageController.java | Refactored to provide pre-upload endpoint without requiring groupId |
| src/main/java/team/wego/wegobackend/group/presentation/GroupController.java | Added placeholder for group detail retrieval endpoint; renamed service method |
| src/main/java/team/wego/wegobackend/group/application/service/GroupService.java | Integrated image URL handling into group creation logic with new helper method |
| src/main/java/team/wego/wegobackend/group/application/service/GroupImageService.java | Simplified to provide pre-upload functionality without group context |
| src/main/java/team/wego/wegobackend/group/domain/entity/Group.java | Changed endTime to nullable to support optional end times |
| src/main/java/team/wego/wegobackend/group/application/dto/request/CreateGroupRequest.java | Added images field to accept pre-uploaded image URLs |
| src/main/java/team/wego/wegobackend/group/application/dto/request/CreateGroupImageRequest.java | New DTO to represent image URL data in group creation requests |
| src/main/java/team/wego/wegobackend/group/application/dto/response/CreateGroupResponse.java | Updated to include images in response and removed joinedCount field |
| src/main/java/team/wego/wegobackend/group/application/dto/response/PreUploadGroupImageResponse.java | New DTO for pre-upload image response wrapper |
| src/main/java/team/wego/wegobackend/group/application/dto/response/PreUploadGroupImageItemResponse.java | New DTO for individual pre-uploaded image metadata |
| src/main/java/team/wego/wegobackend/group/application/dto/response/GetGroupResponse.java | New response DTO for group detail retrieval |
| src/test/http/group/create.http | Updated test scenarios to follow new flow: upload images first, then create group with URLs |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| // 나의 모임 목록 조회 | ||
|
|
||
| // |
There was a problem hiding this comment.
Empty or incomplete comments like "//" should be removed. If these are placeholders for future implementations, they should contain meaningful descriptions of what will be implemented.
| // |
|
|
||
| // 모임 이미지 수정 | ||
|
|
||
|
|
There was a problem hiding this comment.
Empty comment lines serve no purpose and reduce code readability. These should be removed.
| LocalDateTime startTime, | ||
|
|
||
| @NotNull(message = "모임: 종료 시간은 필수 입니다.") | ||
| @Future(message = "모임: 종료 시간은 현재 이후여야 합니다.") |
There was a problem hiding this comment.
The validation annotation @NotNull was removed from endTime, but it's still present in the entity with nullable = false in the schema. However, the diff shows the entity changed to @Column(name = "end_time") without nullable = false. This inconsistency should be clarified - if endTime is optional, the validation annotation @Future should also be updated to allow null values using @Future only when the value is present, or remove it entirely if null is acceptable.
| @Future(message = "모임: 종료 시간은 현재 이후여야 합니다.") |
| @Max(value = 12, message = "모임: 최대 인원은 최대 12명 이하이어야 합니다.") | ||
| Integer maxParticipants | ||
| Integer maxParticipants, | ||
|
|
There was a problem hiding this comment.
The images field in the request DTO lacks validation annotations. Consider adding validation to ensure data integrity:
@Size(max = 3, message = "모임: 이미지는 최대 3개까지 업로드 가능합니다.")
List<CreateGroupImageRequest> imagesAdditionally, CreateGroupImageRequest itself should have validation on its fields (e.g., @NotBlank for URLs, validation for sortOrder range).
| @Size(max = 3, message = "모임: 이미지는 최대 3개까지 업로드 가능합니다.") |
|
|
||
| public record CreateGroupImageRequest( | ||
| Integer sortOrder, | ||
| String imageUrl440x240, |
There was a problem hiding this comment.
The CreateGroupImageRequest record lacks validation for its fields. Since these URLs will be stored in the database, add appropriate validation:
public record CreateGroupImageRequest(
@Min(value = 0, message = "정렬 순서는 0 이상이어야 합니다.")
Integer sortOrder,
@NotBlank(message = "메인 이미지 URL은 필수입니다.")
@Pattern(regexp = "^https?://.*", message = "유효한 URL 형식이어야 합니다.")
String imageUrl440x240,
@NotBlank(message = "썸네일 이미지 URL은 필수입니다.")
@Pattern(regexp = "^https?://.*", message = "유효한 URL 형식이어야 합니다.")
String imageUrl100x100
) {}| public record CreateGroupImageRequest( | |
| Integer sortOrder, | |
| String imageUrl440x240, | |
| import jakarta.validation.constraints.Min; | |
| import jakarta.validation.constraints.NotBlank; | |
| import jakarta.validation.constraints.Pattern; | |
| public record CreateGroupImageRequest( | |
| @Min(value = 0, message = "정렬 순서는 0 이상이어야 합니다.") | |
| Integer sortOrder, | |
| @NotBlank(message = "메인 이미지 URL은 필수입니다.") | |
| @Pattern(regexp = "^https?://.*", message = "유효한 URL 형식이어야 합니다.") | |
| String imageUrl440x240, | |
| @NotBlank(message = "썸네일 이미지 URL은 필수입니다.") | |
| @Pattern(regexp = "^https?://.*", message = "유효한 URL 형식이어야 합니다.") |
| CreatedBy createdByHost = new CreatedBy( | ||
| host.getId(), | ||
| host.getNickName(), | ||
| host.getProfileImage()); |
There was a problem hiding this comment.
The CreatedBy record class is referenced but not defined. This will cause a compilation error. The class definition appears to have been accidentally removed from this file.
| @RequestPart(value = "images", required = false) List<MultipartFile> images | ||
| @PostMapping("/upload") | ||
| public ResponseEntity<ApiResponse<PreUploadGroupImageResponse>> uploadImages( | ||
| @RequestParam("images") List<MultipartFile> images |
There was a problem hiding this comment.
The @RequestParam("images") annotation is incorrect for List<MultipartFile>. For multipart file uploads, files are automatically bound from the request without needing to specify the parameter name. The correct approach is to use @RequestPart or simply @RequestParam without a value:
@RequestParam List<MultipartFile> imagesor
@RequestPart(value = "images", required = false) List<MultipartFile> imagesThe current annotation will cause issues with file upload binding.
| private final GroupImageService groupImageService; | ||
|
|
||
| private void validateCreateGroupRequest(CreateGroupRequest request) { | ||
| if (!request.endTime().isAfter(request.startTime())) { |
There was a problem hiding this comment.
The validation logic in validateCreateGroupRequest checks if endTime is after startTime, but since endTime is now nullable (based on the entity change), this method will throw a NullPointerException if endTime is null. Add a null check:
if (request.endTime() != null && !request.endTime().isAfter(request.startTime())) {
throw new GroupException(GroupErrorCode.INVALID_TIME_RANGE);
}| if (!request.endTime().isAfter(request.startTime())) { | |
| if (request.endTime() != null && !request.endTime().isAfter(request.startTime())) { |
| } | ||
|
|
||
| // 모임 상세 조회 | ||
| @PostMapping("/{groupId}") |
There was a problem hiding this comment.
Using @PostMapping for a retrieval operation is incorrect. This endpoint should use @GetMapping instead since it's fetching group details, not creating or modifying data. POST requests should be used for operations that create or modify resources, while GET should be used for read operations.
| @PostMapping("/{groupId}") | |
| @GetMapping("/{groupId}") |
| // GetGroupResponse response = groupService.getGroup(groupId); | ||
|
|
||
| return ResponseEntity.noContent().build(); |
There was a problem hiding this comment.
The endpoint returns ResponseEntity.noContent().build() which produces a 204 No Content response, but the return type is ResponseEntity<ApiResponse<GetGroupResponse>>. This is inconsistent. Either:
- Remove or comment out this entire method until it's implemented, or
- Return a proper response matching the declared return type
The current implementation is misleading and will cause confusion for API consumers.
| // GetGroupResponse response = groupService.getGroup(groupId); | |
| return ResponseEntity.noContent().build(); | |
| GetGroupResponse response = groupService.getGroup(groupId); | |
| return ResponseEntity.ok(ApiResponse.success(response)); |
📝 Pull Request
📌 PR 종류
해당하는 항목에 체크해주세요.
✨ 변경 내용
! 이전 플로우: 그룹 생성 → groupId로 이미지 업로드
위 .http는 이 새 구조에 맞춰서:
까지 한 번에 이어서 테스트할 수 있게 작성했습니다.
🔍 관련 이슈
🧪 테스트
변경된 기능에 대한 테스트 범위 또는 테스트 결과를 작성해주세요.
🚨 확인해야 할 사항 (Checklist)
PR을 제출하기 전에 아래 항목들을 확인해주세요.
🙋 기타 참고 사항
리뷰어가 참고하면 좋을 만한 추가 설명이 있다면 적어주세요.
Summary by CodeRabbit
릴리스 노트
New Features
Bug Fixes
Tests
✏️ Tip: You can customize this high-level summary in your review settings.