Skip to content

[FEAT] 모임 수정 및 삭제#70

Merged
LimdaeIl merged 4 commits intomainfrom
feat/group-img-update-delete
Dec 10, 2025
Merged

[FEAT] 모임 수정 및 삭제#70
LimdaeIl merged 4 commits intomainfrom
feat/group-img-update-delete

Conversation

@LimdaeIl
Copy link
Collaborator

@LimdaeIl LimdaeIl commented Dec 10, 2025

📝 Pull Request

📌 PR 종류

해당하는 항목에 체크해주세요.

  • 기능 추가 (Feature)
  • 버그 수정 (Fix)
  • 문서 수정 (Docs)
  • 코드 리팩터링 (Refactor)
  • 테스트 추가 (Test)
  • 기타 변경 (Chore)

✨ 변경 내용

모임 이미지 업데이트 및 삭제 기능을 추가합니다. S3 스토리지 관리 및 권한 확인 기능이 포함됩니다.
이미지 업데이트 요청 및 응답을 위한 DTO를 도입합니다. 이미지 관련 작업을 처리하도록 모임 서비스를 업데이트합니다.

자세한 로직 과정은 API 문서에서 최종 정리할 예정입니다.

  • 모임 이미지 수정
  • 모임 내용 수정
  • 모임 이미지 삭제
  • 모임 삭제(완전 삭제 + 이미지도 함께 삭제)

🔍 관련 이슈

🧪 테스트

변경된 기능에 대한 테스트 범위 또는 테스트 결과를 작성해주세요.

  • 유닛 테스트 추가 / 수정
  • 통합 테스트 검증
  • 수동 테스트 완료

🚨 확인해야 할 사항 (Checklist)

PR을 제출하기 전에 아래 항목들을 확인해주세요.

  • 코드 포매팅 완료
  • 불필요한 파일/코드 제거
  • 로직 검증 완료
  • 프로젝트 빌드 성공
  • 린트/정적 분석 통과 (해당 시)

🙋 기타 참고 사항

리뷰어가 참고하면 좋을 만한 추가 설명이 있다면 적어주세요.

Summary by CodeRabbit

릴리스 노트

  • New Features

    • 모임 수정 기능 추가 — 제목, 위치(세부), 시간(시작/종료), 설명, 태그, 최대인원 등 수정 가능
    • 모임 이미지 일괄 업데이트 및 삭제 기능 추가 (최대 3개 제한 및 썸네일 지원)
    • 모임 삭제 기능 추가
  • Chores

    • 그룹·이미지 관리 흐름을 검증하는 REST 테스트 컬렉션 추가 (업로드·수정·삭제 시나리오)

✏️ Tip: You can customize this high-level summary in your review settings.

모임 이미지 업데이트 및 삭제 기능을 추가합니다. S3 스토리지 관리 및 권한 확인 기능이 포함됩니다. 이미지 업데이트 요청 및 응답을 위한 DTO를 도입합니다. 이미지 관련 작업을 처리하도록 모임 서비스를 업데이트합니다.
@LimdaeIl LimdaeIl self-assigned this Dec 10, 2025
Copilot AI review requested due to automatic review settings December 10, 2025 07:28
@LimdaeIl LimdaeIl added the ✨enhancement New feature or request label Dec 10, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 10, 2025

Caution

Review failed

The pull request is closed.

Note

Other AI code review bot(s) detected

CodeRabbit 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

모임과 모임 이미지의 수정·삭제 기능을 추가합니다. 요청/응답 DTO, 서비스 메서드(update/delete), 컨트롤러 엔드포인트, 도메인 업데이트 메서드, S3 이미지 삭제 유틸 및 관련 HTTP 테스트 시나리오가 포함됩니다.

Changes

Cohort / File(s) Summary
요청 DTO
src/main/java/team/wego/wegobackend/group/application/dto/request/UpdateGroupRequest.java, src/main/java/team/wego/wegobackend/group/application/dto/request/UpdateGroupImageItemRequest.java
그룹 수정 정보와 이미지 아이템(정렬순서, main/thumbnail URL)을 담는 public 레코드 추가 및 검증 애노테이션 적용
응답 DTO
src/main/java/team/wego/wegobackend/group/application/dto/response/GroupImageItemResponse.java
필드 구조 변경(이미지별 ID 분리), 팩토리 메서드 시그니처를 main/thumb 엔티티 기준으로 변경하고 fromMainOnly 추가
이미지 업로드 서비스
src/main/java/team/wego/wegobackend/image/application/service/ImageUploadService.java
S3 키 추출(extractKeyFromUrl), 단건/배치 삭제(deleteByUrl, deleteAllByUrls) 메서드 추가 및 키 생성 로직 일부 변경
그룹 이미지 서비스
src/main/java/team/wego/wegobackend/group/application/service/GroupImageService.java
updateGroupImages, deleteGroupImages 트랜잭션 메서드 추가: 권한 검증, 기존 이미지 삭제(S3 포함), 새 이미지 엔티티 생성 및 응답 구성
그룹 서비스
src/main/java/team/wego/wegobackend/group/application/service/GroupService.java
updateGroup, deleteGroup 메서드 추가: 권한/검증 로직, 태그 업데이트, 이미지 삭제 연계 및 응답 생성
도메인 엔티티
src/main/java/team/wego/wegobackend/group/domain/entity/Group.java
그룹 필드 일괄 갱신을 위한 update(...) 메서드 추가
에러 코드
src/main/java/team/wego/wegobackend/group/domain/exception/GroupErrorCode.java
NO_PERMISSION_TO_UPDATE_GROUP, INVALID_MAX_PARTICIPANTS_LESS_THAN_CURRENT, NO_PERMISSION_TO_DELETE_GROUP 등 에러 코드 추가 및 enum 항목 흐름 조정
컨트롤러 엔드포인트
src/main/java/team/wego/wegobackend/group/presentation/GroupController.java, src/main/java/team/wego/wegobackend/group/presentation/GroupImageController.java
PATCH/DELETE 엔드포인트 추가: /api/v1/groups/{groupId} (PATCH, DELETE), /api/v1/groups/images/{groupId} (PATCH, DELETE)
테스트 시나리오
src/test/http/group/update.http, src/test/http/group/delete.http
이미지 업로드 → 그룹 생성 → 이미지 수정 → 이미지 삭제 → 그룹 삭제 등 E2E 흐름을 다루는 REST Client 스크립트 추가

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Controller as GroupController / GroupImageController
    participant Service as GroupService / GroupImageService
    participant Repo as GroupRepository
    participant ImgUpload as ImageUploadService
    participant S3 as AWS S3

    User->>Controller: PATCH /api/v1/groups/{groupId} (UpdateGroupRequest)
    Controller->>Service: updateGroup(userId, groupId, request)
    Service->>Repo: findByIdAndDeletedAtIsNull(groupId)
    Repo-->>Service: Group
    Service->>Service: 권한/요청 검증, 태그 처리
    Service->>Repo: save(updated Group)
    Service-->>Controller: GetGroupResponse
    Controller-->>User: 200 OK

    User->>Controller: DELETE /api/v1/groups/{groupId}
    Controller->>Service: deleteGroup(userId, groupId)
    Service->>Repo: findByIdAndDeletedAtIsNull(groupId)
    Repo-->>Service: Group
    Service->>ImgUpload: deleteAllByUrls(imageUrls)
    ImgUpload->>S3: Delete objects (batch)
    S3-->>ImgUpload: ACK
    Service->>Repo: delete(group)
    Service-->>Controller: void
    Controller-->>User: 200/204

    User->>Controller: PATCH /api/v1/groups/images/{groupId} (List<RequestItem>)
    Controller->>Service: updateGroupImages(userId, groupId, requests)
    Service->>Repo: findByIdAndDeletedAtIsNull(groupId)
    Repo-->>Service: Group
    Service->>Service: 권한 검증, 요청 제한(최대 3)
    Service->>ImgUpload: deleteAllByUrls(oldImageUrls)
    ImgUpload->>S3: Delete objects
    S3-->>ImgUpload: ACK
    Service->>Repo: saveAll(new GroupImage entities)
    Service-->>Controller: List<GroupImageItemResponse>
    Controller-->>User: 200 OK
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • 주의점:
    • GroupErrorCode enum 상수 추가로 인한 문법/초기화 확인
    • GroupImageItemResponse.from 시그니처 변경에 따른 호출 위치 전체 점검
    • ImageUploadService의 S3 키 추출 및 배치 삭제 필터링(빈/null 처리) 검증
    • 트랜잭션 경계와 권한 검증 흐름(GroupService / GroupImageService) 확인

Possibly related PRs

  • #70 — 동일 DTO 및 서비스/컨트롤러/에러코드 변경과 중복되는 코드 수정이 포함되어 있어 충돌 가능성 높음
  • #68 — 그룹 이미지 응답 및 서비스 로직 변경과 직접적으로 겹치는 부분 존재
  • #50 — 공통 Repository 메서드(findByIdAndDeletedAtIsNull) 및 에러코드/응답 흐름이 중복되어 연관성 큼

Poem

🐰 새로고침의 도약을 한 번,
이미지 깃털을 정리해 흩날리네.
PATCH로 고치고 DELETE로 정리하며,
호스트의 열쇠로 문을 닫네.
당근 한 조각, 배포 축하하노라! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning 필수 요구사항인 모임 내용 수정, 모임 이미지 수정, 모임 삭제, 모임 이미지 삭제 중 일부가 구현되었으나 GroupErrorCode 파일에 구문 오류가 있어 코드 컴파일이 불가능합니다. GroupErrorCode.java의 enum 상수 정의 끝부분의 구문 오류(',);')를 수정하여 코드가 정상적으로 컴파일되도록 해야 합니다.
Docstring Coverage ⚠️ Warning Docstring coverage is 6.90% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed 제목 '[FEAT] 모임 수정 및 삭제'는 PR의 주요 변경사항인 모임 수정 및 삭제 기능 추가를 명확하게 요약합니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 연결된 이슈 #69의 범위 내에 있으며, 모임 수정/삭제 및 이미지 수정/삭제 기능 구현과 관련된 필요한 코드 변경들입니다.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72d9194 and 6e0874a.

📒 Files selected for processing (8)
  • src/main/java/team/wego/wegobackend/group/application/dto/request/UpdateGroupImageItemRequest.java (1 hunks)
  • src/main/java/team/wego/wegobackend/group/application/service/GroupImageService.java (5 hunks)
  • src/main/java/team/wego/wegobackend/group/application/service/GroupService.java (6 hunks)
  • src/main/java/team/wego/wegobackend/group/domain/exception/GroupErrorCode.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/delete.http (1 hunks)
  • src/test/http/group/update.http (1 hunks)

Comment @coderabbitai help to get the list of available commands and usage tips.

@LimdaeIl LimdaeIl moved this from Backlog to In progress in WeGo-Together Backend Dec 10, 2025
Copy link

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

Actionable comments posted: 9

🧹 Nitpick comments (7)
src/main/java/team/wego/wegobackend/image/application/service/ImageUploadService.java (2)

56-57: 주석 처리된 코드 제거 필요.

디버깅 또는 이전 구현 흔적으로 보이는 주석 처리된 코드가 남아 있습니다. 프로덕션 코드에서는 제거하는 것이 좋습니다.

-//        String key = buildKey(dir, originalFilename, index);
         String key = buildKey(originalFilename, index);

410-416: 삭제 실패 시 로깅 부재.

deleteByUrl이 key가 null/blank일 때 조용히 반환합니다. 디버깅을 위해 경고 로그를 추가하는 것이 좋습니다.

     public void deleteByUrl(String imageUrl) {
         String key = extractKeyFromUrl(imageUrl);
         if (key == null || key.isBlank()) {
+            // 옵션: log.warn("이미지 URL에서 키 추출 실패: {}", imageUrl);
             return;
         }
         delete(key);
     }
src/main/java/team/wego/wegobackend/group/application/service/GroupImageService.java (1)

217-225: URL 문자열 기반 이미지 타입 판별은 취약합니다.

img.getImageUrl().contains("440x240") 방식은 URL 구조 변경 시 깨질 수 있습니다. GroupImage 엔티티에 이미지 타입(MAIN/THUMB) 필드를 추가하는 것이 더 안정적입니다.

src/test/http/group/update.http (1)

215-240: 테스트 파일이 불완전합니다.

테스트 2-5 (4장 업로드 - 실패 예상)가 응답 핸들러 스크립트 없이 끝났습니다. 실패 케이스의 예상 응답을 검증하는 스크립트를 추가하거나, 최소한 테스트 파일을 올바르게 종료해 주세요.

예시:

> {%
  // 4장 업로드 시 실패 예상 검증
  client.test("Should fail with IMAGE_UPLOAD_EXCEED", function() {
    client.assert(response.status === 400, "Expected 400 Bad Request");
  });
%}
src/main/java/team/wego/wegobackend/group/presentation/GroupImageController.java (1)

57-67: DELETE 엔드포인트에 204 No Content 응답 고려.

삭제 작업 후 반환할 콘텐츠가 없으므로 HttpStatus.NO_CONTENT (204)가 RESTful 관례에 더 부합합니다. 다만 기존 API 응답 패턴과 일관성을 유지하려면 현재 구현도 허용됩니다.

     @DeleteMapping("/{groupId}")
     public ResponseEntity<ApiResponse<Void>> deleteGroupImages(
             @RequestParam Long userId,   // TODO: 나중에 인증 정보에서 꺼내기
             @PathVariable Long groupId
     ) {
         groupImageService.deleteGroupImages(userId, groupId);

         return ResponseEntity
-                .status(HttpStatus.OK)
-                .body(ApiResponse.success(HttpStatus.OK.value(), null));
+                .status(HttpStatus.NO_CONTENT)
+                .body(ApiResponse.success(HttpStatus.NO_CONTENT.value(), null));
     }
src/main/java/team/wego/wegobackend/group/domain/exception/GroupErrorCode.java (1)

24-26: 열거형 상수 끝의 ,; 구문 정리.

Line 26의 ,;는 Java에서 유효한 구문이지만 (trailing comma 허용), 코드 가독성을 위해 쉼표를 제거하는 것이 좋습니다.

     HOST_CANNOT_LEAVE_OWN_GROUP(HttpStatus.BAD_REQUEST, "모임: HOST는 나갈 수 없습니다. 모임 ID: %s 회원 ID: %s"),
     NO_PERMISSION_TO_UPDATE_GROUP(HttpStatus.FORBIDDEN, "모임: 해당 모임을 수정할 권한이 없습니다. 모임 ID: %s 회원 ID: %s"),
-    INVALID_MAX_PARTICIPANTS_LESS_THAN_CURRENT(HttpStatus.BAD_REQUEST, "모임: 현재 참여 인원 수(%s)보다 작은 값으로 최대 인원을 줄일 수 없습니다."),;
+    INVALID_MAX_PARTICIPANTS_LESS_THAN_CURRENT(HttpStatus.BAD_REQUEST, "모임: 현재 참여 인원 수(%s)보다 작은 값으로 최대 인원을 줄일 수 없습니다.");
src/main/java/team/wego/wegobackend/group/application/service/GroupService.java (1)

471-477: 태그 업데이트 로직이 적절하지만, 지연 로딩 고려가 필요할 수 있습니다.

group.getGroupTags().clear()를 호출하기 전에 컬렉션이 로드되지 않았다면 LazyInitializationException이 발생할 수 있습니다. 현재는 @Transactional 메서드 내에서 호출되므로 문제없지만, 향후 안전성을 위해 명시적으로 컬렉션을 로드하는 것을 고려해보세요.

예시:

 private void updateGroupTags(Group group, List<String> tagNames) {
     if (tagNames == null) {
         return;
     }
+    // Ensure collection is initialized
+    group.getGroupTags().size();
     group.getGroupTags().clear();
     saveGroupTags(group, tagNames);
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb85b23 and 72d9194.

📒 Files selected for processing (12)
  • src/main/java/team/wego/wegobackend/group/application/dto/request/UpdateGroupImageItemRequest.java (1 hunks)
  • src/main/java/team/wego/wegobackend/group/application/dto/request/UpdateGroupRequest.java (1 hunks)
  • src/main/java/team/wego/wegobackend/group/application/dto/response/GroupImageItemResponse.java (1 hunks)
  • src/main/java/team/wego/wegobackend/group/application/service/GroupImageService.java (5 hunks)
  • src/main/java/team/wego/wegobackend/group/application/service/GroupService.java (6 hunks)
  • src/main/java/team/wego/wegobackend/group/domain/entity/Group.java (1 hunks)
  • src/main/java/team/wego/wegobackend/group/domain/exception/GroupErrorCode.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/main/java/team/wego/wegobackend/image/application/service/ImageUploadService.java (2 hunks)
  • src/test/http/group/delete.http (1 hunks)
  • src/test/http/group/update.http (1 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 (15)
src/main/java/team/wego/wegobackend/image/application/service/ImageUploadService.java (1)

418-433: 배치 삭제 로직 적절함.

null-safe 스트림 처리와 빈 리스트 체크가 잘 구현되어 있습니다.

src/main/java/team/wego/wegobackend/group/application/dto/request/UpdateGroupImageItemRequest.java (1)

3-8: DTO 구조 적절함. 선택적으로 Bean Validation 추가 고려.

서비스 레이어에서 null 처리를 하고 있지만, 컨트롤러 레벨에서 조기 검증을 원한다면 @NotNull, @URL 등의 어노테이션 추가를 고려할 수 있습니다.

src/test/http/group/delete.http (1)

1-174: 테스트 시나리오 커버리지 양호.

전체 CRUD 플로우(생성, 수정, 삭제)와 삭제 후 404 확인까지 포함하여 종합적인 테스트입니다.

src/main/java/team/wego/wegobackend/group/application/service/GroupImageService.java (1)

220-220: The project is configured for Java 21 (as specified in build.gradle: languageVersion = JavaLanguageVersion.of(21)). The list.getFirst() method is fully compatible and appropriate for this project. No change needed.

Likely an incorrect or invalid review comment.

src/main/java/team/wego/wegobackend/group/domain/entity/Group.java (1)

106-122: Consider nullable field handling in the update() method.

The update() method unconditionally assigns all parameters, which means locationDetail and endTime can be overwritten with null values since they lack non-null validation in UpdateGroupRequest. While endTime nullability appears intentional (based on the conditional time range validation that checks "if both startTime AND endTime are non-null"), locationDetail has no such guard. If partial updates are needed in the future, consider either: (1) adding non-null validation to required fields, or (2) adopting an optional/nullable parameter pattern similar to the updateGroupTags() method where null means "don't update this field."

src/main/java/team/wego/wegobackend/group/application/dto/request/UpdateGroupRequest.java (2)

22-27: endTime의 cross-field 검증 확인 필요.

endTime@NotNull이 없어 nullable이고, @Future는 null 값을 유효하게 처리합니다. startTime < endTime 검증은 서비스 레이어에서 INVALID_TIME_RANGE 에러코드로 처리되는 것으로 보입니다.

endTime이 null일 때의 비즈니스 로직이 의도된 것인지 확인해 주세요. 종료 시간이 필수라면 @NotNull을 추가하는 것이 좋습니다.


13-38: LGTM - 검증 어노테이션이 적절히 적용되었습니다.

필수 필드에 대한 @NotBlank, @NotNull 검증과 maxParticipants의 범위 검증(2-12)이 잘 구성되어 있습니다. 한국어 에러 메시지도 일관성 있게 작성되었습니다.

src/main/java/team/wego/wegobackend/group/application/dto/response/GroupImageItemResponse.java (2)

13-34: LGTM - null 처리가 적절합니다.

mainthumb의 null 케이스를 안전하게 처리하고 있습니다. sortOrder의 fallback 로직(main → thumb → 0)도 명확합니다.


36-38: 유용한 헬퍼 메서드.

fromMainOnly는 thumb 이미지가 없는 경우에 대한 간결한 팩토리 메서드입니다.

src/main/java/team/wego/wegobackend/group/application/service/GroupService.java (4)

37-37: 이미지 삭제를 위한 의존성 추가가 적절합니다.

모임 삭제 시 S3 이미지 정리를 위해 ImageUploadService 의존성이 추가되었습니다. 의존성 주입이 올바르게 구성되어 있습니다.

Also applies to: 55-55


479-499: 검증 로직이 적절합니다.

모임 수정 요청 검증이 잘 구현되어 있습니다:

  • 시간 범위 검증
  • 최소 인원 검증 (2명 이상)
  • 현재 참여 인원보다 적게 줄일 수 없는 검증

모든 엣지 케이스가 적절히 처리되고 있습니다.


501-541: 모임 수정 로직이 잘 구현되어 있습니다.

모임 수정 플로우가 체계적으로 구현되었습니다:

  1. 모임 조회 및 권한 확인 (HOST만 수정 가능)
  2. 현재 참여 인원 계산
  3. 요청 검증 (시간, 인원 등)
  4. 엔티티 필드 업데이트 (이미지 제외)
  5. 태그 업데이트
  6. 업데이트된 응답 반환

권한 체크와 검증 로직이 적절하며, 트랜잭션 경계도 올바르게 설정되어 있습니다.


221-221: 이미지 응답 생성 로직이 새로운 DTO 구조에 맞게 업데이트되었습니다.

GroupImageItemResponse.from(main, thumb) 시그니처를 사용하여 메인/썸네일 이미지를 그룹화하는 패턴으로 변경되었습니다. 이는 PR에서 변경된 DTO 구조와 일치합니다.

Also applies to: 389-389

src/main/java/team/wego/wegobackend/group/presentation/GroupController.java (2)

8-8: 필요한 import 추가가 적절합니다.

REST 엔드포인트 구현을 위한 DeleteMapping, PatchMapping 어노테이션과 UpdateGroupRequest DTO import가 추가되었습니다.

Also applies to: 10-10, 19-19


100-111: 모임 수정 엔드포인트가 적절히 구현되었습니다.

PATCH 메서드를 사용한 부분 업데이트 엔드포인트가 올바르게 구현되었습니다:

  • @Valid 어노테이션으로 요청 검증 수행
  • 서비스 레이어로 적절히 위임
  • HTTP 200 OK 상태 코드 반환

Comment on lines 170 to 180
// 4. 기존 이미지 URL 수집 -> S3 삭제
List<String> oldUrls = group.getImages().stream()
.map(GroupImage::getImageUrl)
.filter(Objects::nonNull)
.toList();

imageUploadService.deleteAllByUrls(oldUrls);

// 5. 기존 GroupImage 엔티티들을 관계에서 제거: DB에서도 삭제됨
group.getImages().clear();
groupImageRepository.flush(); // DB 즉시 삭제하기 위해 추가
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

S3 삭제와 DB 삭제 순서로 인한 데이터 불일치 위험.

S3 이미지 삭제(Line 176)가 DB 삭제(Line 179-180)보다 먼저 발생합니다. 이후 DB 작업에서 예외가 발생하면 트랜잭션이 롤백되지만, S3에서 삭제된 이미지는 복구되지 않아 데이터 불일치가 발생할 수 있습니다.

순서를 변경하거나, S3 삭제를 트랜잭션 커밋 후 수행하는 방식을 고려하세요:

-        // 4. 기존 이미지 URL 수집 -> S3 삭제
         List<String> oldUrls = group.getImages().stream()
                 .map(GroupImage::getImageUrl)
                 .filter(Objects::nonNull)
                 .toList();
 
-        imageUploadService.deleteAllByUrls(oldUrls);
-
         // 5. 기존 GroupImage 엔티티들을 관계에서 제거: DB에서도 삭제됨
         group.getImages().clear();
         groupImageRepository.flush();
+
+        // S3 삭제는 DB 변경 확정 후 수행 (또는 @TransactionalEventListener 사용)
+        imageUploadService.deleteAllByUrls(oldUrls);
🤖 Prompt for AI Agents
In
src/main/java/team/wego/wegobackend/group/application/service/GroupImageService.java
around lines 170-180, S3 deletion is performed before removing GroupImage
entities from the DB which can cause permanent S3 data loss if the DB
transaction later fails; to fix this, collect the existing image URLs as you
already do, then perform the DB removal and flush inside the transaction first,
and schedule the S3 deletion to run only after the transaction successfully
commits (e.g., register a TransactionSynchronization post-commit callback or
invoke the deletion from code executed after transaction commit); ensure you
still pass the previously collected URL list to the post-commit task so the S3
delete happens only on successful DB commit.

Comment on lines 251 to 260
// 3. 기존 URL들 수집 후 S3 삭제
List<String> oldUrls = group.getImages().stream()
.map(GroupImage::getImageUrl)
.filter(Objects::nonNull)
.toList();

imageUploadService.deleteAllByUrls(oldUrls);

group.getImages().clear();
groupImageRepository.flush(); // DB 즉시 삭제하기 위해 추가
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

deleteGroupImages도 동일한 S3/DB 순서 문제가 있습니다.

updateGroupImages와 마찬가지로 S3 삭제가 DB 삭제보다 먼저 발생하여 트랜잭션 롤백 시 데이터 불일치가 발생할 수 있습니다.


imageUploadService.deleteAllByUrls(imageUrls);

groupRepository.delete(group);
Copy link

@coderabbitai coderabbitai bot Dec 10, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "GroupService.java" | head -5

Repository: WeGo-Together/WeGo_BackEnd

Length of output: 151


🏁 Script executed:

fd "GroupService.java" --type f

Repository: WeGo-Together/WeGo_BackEnd

Length of output: 149


🏁 Script executed:

# Get the line count first
wc -l "src/main/java/team/wego/wegobackend/group/application/service/GroupService.java"

Repository: WeGo-Together/WeGo_BackEnd

Length of output: 153


🏁 Script executed:

sed -n '550,580p' "src/main/java/team/wego/wegobackend/group/application/service/GroupService.java"

Repository: WeGo-Together/WeGo_BackEnd

Length of output: 701


🏁 Script executed:

fd "Group.java" --type f | grep -E "entity|model|domain"

Repository: WeGo-Together/WeGo_BackEnd

Length of output: 136


🏁 Script executed:

# Search for soft delete patterns
rg "deletedAt|DeletedAt|findByIdAndDeletedAtIsNull" --type java -n

Repository: WeGo-Together/WeGo_BackEnd

Length of output: 1591


🏁 Script executed:

# Find Group entity and examine its relationships
rg -A5 "class Group\s" --type java | head -100

Repository: WeGo-Together/WeGo_BackEnd

Length of output: 665


🏁 Script executed:

# Find all cascade configurations
rg "@OneToMany|@ManyToOne|@ManyToMany|@JoinColumn|orphanRemoval|cascade" --type java -B2 -A2 | grep -A10 -B10 "Group"

Repository: WeGo-Together/WeGo_BackEnd

Length of output: 4335


Replace hard delete with soft delete to maintain consistency with established soft delete pattern.

The codebase uses a soft delete pattern throughout: the Group entity has a deletedAt field, and all queries filter using findByIdAndDeletedAtIsNull. However, line 568 performs a physical delete with groupRepository.delete(group), which is inconsistent and causes problems since cascade delete will physically remove all related GroupImage, GroupTag, and GroupUser records.

Use soft delete instead:

-    groupRepository.delete(group);
+    group.setDeletedAt(LocalDateTime.now());
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
groupRepository.delete(group);
group.setDeletedAt(LocalDateTime.now());
🤖 Prompt for AI Agents
In
src/main/java/team/wego/wegobackend/group/application/service/GroupService.java
around line 568, replace the hard/physical delete call with a soft-delete: set
the Group entity's deletedAt timestamp to the current time (use Instant.now() or
LocalDateTime.now() to match the field type) and persist the change via
groupRepository.save(group) instead of groupRepository.delete(group); do not
remove related records—rely on the existing deletedAt-based query filters.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

의도한대로 완전 삭제 구현이므로 해당 리뷰는 수정 없이 넘어갑니다.

Copy link

Choose a reason for hiding this comment

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

@LimdaeIl, 알겠습니다! 완전 삭제로 진행하시는 것으로 이해했습니다.

참고로, 완전 삭제 시 관련 테이블들(GroupImage, GroupTag, GroupUser 등)이 cascade 설정에 따라 함께 삭제되므로, 필요한 경우 삭제 전에 관련 데이터를 별도로 백업하거나 로깅하는 것을 고려해보실 수 있습니다.

Comment on lines +387 to +408
public String extractKeyFromUrl(String imageUrl) {
if (imageUrl == null || imageUrl.isBlank()) {
return null;
}

String endpoint = awsS3Properties.getPublicEndpoint();
if (endpoint != null && !endpoint.isBlank()) {
String prefix = endpoint.endsWith("/") ? endpoint : endpoint + "/";
if (imageUrl.startsWith(prefix)) {
return imageUrl.substring(prefix.length());
}
}

// fallback: 마지막 "/" 이후를 key로 사용
int idx = imageUrl.lastIndexOf('/');
if (idx >= 0 && idx + 1 < imageUrl.length()) {
return imageUrl.substring(idx + 1);
}

// 그래도 안 되면 전체를 key로 시도 (최악의 경우)
return imageUrl;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fallback 로직이 다중 경로 세그먼트 URL에서 잘못된 키를 추출할 수 있습니다.

lastIndexOf('/') fallback은 https://cdn.example.com/bucket/path/to/image.webp 같은 URL에서 전체 경로(bucket/path/to/image.webp) 대신 파일명(image.webp)만 반환합니다. S3 키가 경로를 포함하는 경우 삭제가 실패할 수 있습니다.

         // fallback: 마지막 "/" 이후를 key로 사용
-        int idx = imageUrl.lastIndexOf('/');
-        if (idx >= 0 && idx + 1 < imageUrl.length()) {
-            return imageUrl.substring(idx + 1);
+        // endpoint가 매칭되지 않으면 전체 URL을 key로 시도
+        // (실제 S3 키 구조에 맞게 조정 필요)
+        try {
+            java.net.URI uri = java.net.URI.create(imageUrl);
+            String path = uri.getPath();
+            if (path != null && path.startsWith("/")) {
+                return path.substring(1);
+            }
+        } catch (IllegalArgumentException e) {
+            // URI 파싱 실패 시 전체 URL 반환
         }
 
         // 그래도 안 되면 전체를 key로 시도 (최악의 경우)
         return imageUrl;
🤖 Prompt for AI Agents
In
src/main/java/team/wego/wegobackend/image/application/service/ImageUploadService.java
around lines 387 to 408, the fallback using lastIndexOf('/') returns only the
filename for multi-segment paths and breaks S3 keys that include directories;
instead, parse the imageUrl as a URI/URL: if it contains a scheme/host, extract
the full path component (strip any leading '/' and remove query/fragment) and
return that as the key; if it is not a full URL (no scheme/host), return the
input unchanged (or the entire remaining string) so multi-segment keys are
preserved. Ensure existing null/blank checks remain and handle
URISyntaxException/ MalformedURLException by falling back to returning the
original string.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds update and delete functionality for groups (모임) and their associated images. The implementation includes permission checks (HOST-only operations), S3 storage management for image cleanup, and new DTOs for update operations.

  • Adds PATCH /api/v1/groups/{groupId} and DELETE /api/v1/groups/{groupId} endpoints for group modification
  • Adds PATCH /api/v1/groups/images/{groupId} and DELETE /api/v1/groups/images/{groupId} endpoints for image management
  • Implements permission validation ensuring only the HOST can modify or delete groups

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
src/test/http/group/update.http HTTP test scenarios for group image update operations with various image formats and counts
src/test/http/group/delete.http HTTP test scenarios for group image and group deletion operations
src/main/java/team/wego/wegobackend/image/application/service/ImageUploadService.java Adds URL-to-key extraction and bulk deletion methods for S3 image cleanup
src/main/java/team/wego/wegobackend/group/presentation/GroupImageController.java Adds PATCH and DELETE endpoints for group image management
src/main/java/team/wego/wegobackend/group/presentation/GroupController.java Adds PATCH and DELETE endpoints for group management
src/main/java/team/wego/wegobackend/group/domain/exception/GroupErrorCode.java Adds new error codes for permission denial and invalid participant count reduction
src/main/java/team/wego/wegobackend/group/domain/entity/Group.java Adds update method for modifying group properties
src/main/java/team/wego/wegobackend/group/application/service/GroupService.java Implements updateGroup and deleteGroup methods with validation and S3 cleanup
src/main/java/team/wego/wegobackend/group/application/service/GroupImageService.java Implements updateGroupImages and deleteGroupImages methods with permission checks and S3 management
src/main/java/team/wego/wegobackend/group/application/dto/response/GroupImageItemResponse.java Refactors to include separate IDs for main and thumbnail images
src/main/java/team/wego/wegobackend/group/application/dto/request/UpdateGroupRequest.java New DTO for group update requests with validation constraints
src/main/java/team/wego/wegobackend/group/application/dto/request/UpdateGroupImageItemRequest.java New DTO for image update requests
Comments suppressed due to low confidence (2)

src/main/java/team/wego/wegobackend/group/domain/entity/Group.java:66

    private List<GroupTag> groupTags = new ArrayList<>();

src/main/java/team/wego/wegobackend/group/domain/entity/Group.java:63

    private List<GroupImage> images = new ArrayList<>();

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +400 to +407
// fallback: 마지막 "/" 이후를 key로 사용
int idx = imageUrl.lastIndexOf('/');
if (idx >= 0 && idx + 1 < imageUrl.length()) {
return imageUrl.substring(idx + 1);
}

// 그래도 안 되면 전체를 key로 시도 (최악의 경우)
return imageUrl;
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

The fallback logic may not work as intended. When extractKeyFromUrl fails to extract a proper key using the endpoint prefix, it falls back to extracting everything after the last /. However, this doesn't account for URLs with query parameters or other path segments. For example, if imageUrl is https://domain.com/bucket/folder/image.jpg?v=123, this will return image.jpg?v=123 which is not a valid S3 key. Consider parsing the URL more carefully or validating the extracted key before returning it.

Suggested change
// fallback: 마지막 "/" 이후를 key로 사용
int idx = imageUrl.lastIndexOf('/');
if (idx >= 0 && idx + 1 < imageUrl.length()) {
return imageUrl.substring(idx + 1);
}
// 그래도 안 되면 전체를 key로 시도 (최악의 경우)
return imageUrl;
// fallback: 마지막 "/" 이후를 key로 사용, 그리고 query/fragment 제거
int idx = imageUrl.lastIndexOf('/');
if (idx >= 0 && idx + 1 < imageUrl.length()) {
String key = imageUrl.substring(idx + 1);
int qIdx = key.indexOf('?');
if (qIdx >= 0) {
key = key.substring(0, qIdx);
}
int fIdx = key.indexOf('#');
if (fIdx >= 0) {
key = key.substring(0, fIdx);
}
return key;
}
// 그래도 안 되면 전체를 key로 시도 (최악의 경우)
String key = imageUrl;
int qIdx = key.indexOf('?');
if (qIdx >= 0) {
key = key.substring(0, qIdx);
}
int fIdx = key.indexOf('#');
if (fIdx >= 0) {
key = key.substring(0, fIdx);
}
return key;

Copilot uses AI. Check for mistakes.
Comment on lines +218 to +223
.filter(img -> img.getImageUrl().contains("440x240"))
.findFirst()
.orElse(list.getFirst());

GroupImage thumb = list.stream()
.filter(img -> img.getImageUrl().contains("100x100"))
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

The logic assumes that image URLs will contain the strings "440x240" or "100x100" to differentiate between main and thumbnail images. This is fragile and relies on a specific URL naming convention. If the URL format changes or doesn't contain these strings, the logic will incorrectly identify images. Consider storing the image type/size as metadata in the GroupImage entity or using a more robust identification mechanism.

Suggested change
.filter(img -> img.getImageUrl().contains("440x240"))
.findFirst()
.orElse(list.getFirst());
GroupImage thumb = list.stream()
.filter(img -> img.getImageUrl().contains("100x100"))
.filter(img -> "MAIN".equals(img.getImageType()))
.findFirst()
.orElse(list.getFirst());
GroupImage thumb = list.stream()
.filter(img -> "THUMBNAIL".equals(img.getImageType()))

Copilot uses AI. Check for mistakes.
Comment on lines +502 to +541
public GetGroupResponse updateGroup(Long userId, Long groupId, UpdateGroupRequest request) {
// 1. 모임 조회
Group group = groupRepository.findByIdAndDeletedAtIsNull(groupId)
.orElseThrow(
() -> new GroupException(GroupErrorCode.GROUP_NOT_FOUND_BY_ID, groupId));

// 2. 권한 체크: HOST만 수정 가능
if (!group.getHost().getId().equals(userId)) {
throw new GroupException(
GroupErrorCode.NO_PERMISSION_TO_UPDATE_GROUP,
groupId,
userId
);
}

// 3. 현재 ATTEND 인원 수 (HOST 포함)
int currentAttendCount = (int) group.getUsers().stream()
.filter(gu -> gu.getStatus() == ATTEND)
.count();

// 4. 요청 값 검증 (시간 / 최대 인원 / 현재 인원 대비)
validateUpdateGroupRequest(request, currentAttendCount);

// 5. 엔티티 필드 수정 (이미지는 건드리지 않음)
group.update(
request.title(),
request.location(),
request.locationDetail(),
request.startTime(),
request.endTime(),
request.description(),
request.maxParticipants()
);

// 6. 태그 수정
updateGroupTags(group, request.tags());

// 7. 수정 결과 응답 (현재 유저 기준)
return buildGetGroupResponse(group, userId);
}
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

The new updateGroup method lacks unit test coverage. Given that the repository has existing tests for GroupService, consider adding tests to cover scenarios such as:

  • Successful update by HOST
  • Permission denied when non-HOST tries to update
  • Validation failures (invalid time range, max participants less than current count)
  • Tag updates

Copilot uses AI. Check for mistakes.
Comment on lines 544 to 569
public void deleteGroup(Long userId, Long groupId) {
// 1. 모임 조회 (soft delete 고려 쿼리 사용 중이지만, 여기서는 실제 삭제)
Group group = groupRepository.findByIdAndDeletedAtIsNull(groupId)
.orElseThrow(
() -> new GroupException(GroupErrorCode.GROUP_NOT_FOUND_BY_ID, groupId)
);

// 2. HOST 권한 체크
if (!group.getHost().getId().equals(userId)) {
throw new GroupException(
GroupErrorCode.NO_PERMISSION_TO_UPDATE_GROUP, // 삭제도 동일 코드 재사용
groupId,
userId
);
}

// 3. S3 이미지 삭제 (이미지 URL -> key 변환은 ImageUploadService 가 담당)
List<String> imageUrls = group.getImages().stream()
.map(GroupImage::getImageUrl)
.filter(Objects::nonNull)
.toList();

imageUploadService.deleteAllByUrls(imageUrls);

groupRepository.delete(group);
}
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

The new deleteGroup method lacks unit test coverage. Given that the repository has existing tests for GroupService, consider adding tests to cover scenarios such as:

  • Successful deletion by HOST
  • Permission denied when non-HOST tries to delete
  • S3 cleanup verification
  • Cascading deletion of related entities

Copilot uses AI. Check for mistakes.
Comment on lines 140 to 231
public List<GroupImageItemResponse> updateGroupImages(
Long userId,
Long groupId,
List<UpdateGroupImageItemRequest> requests
) {
// 1. 그룹 조회 (soft delete 고려)
Group group = groupRepository.findByIdAndDeletedAtIsNull(groupId)
.orElseThrow(
() -> new GroupException(GroupErrorCode.GROUP_NOT_FOUND_BY_ID, groupId)
);

// 2. HOST 권한 체크
if (!group.getHost().getId().equals(userId)) {
throw new GroupException(
GroupErrorCode.NO_PERMISSION_TO_UPDATE_GROUP,
groupId,
userId
);
}

// 3. null 방어 및 최대 개수 제한: 논리 이미지 세트 기준
List<UpdateGroupImageItemRequest> safeList =
(requests == null) ? List.of() : requests.stream()
.filter(Objects::nonNull)
.toList();

if (safeList.size() > 3) {
throw new GroupException(GroupErrorCode.IMAGE_UPLOAD_EXCEED, safeList.size());
}

// 4. 기존 이미지 URL 수집 -> S3 삭제
List<String> oldUrls = group.getImages().stream()
.map(GroupImage::getImageUrl)
.filter(Objects::nonNull)
.toList();

imageUploadService.deleteAllByUrls(oldUrls);

// 5. 기존 GroupImage 엔티티들을 관계에서 제거: DB에서도 삭제됨
group.getImages().clear();
groupImageRepository.flush(); // DB 즉시 삭제하기 위해 추가

// 6. 새 GroupImage 엔티티 생성
List<GroupImage> newEntities = new ArrayList<>();

for (int i = 0; i < safeList.size(); i++) {
UpdateGroupImageItemRequest item = safeList.get(i);

int sortOrder = (item.sortOrder() != null) ? item.sortOrder() : i;

String mainUrl = item.imageUrl440x240();
String thumbUrl = item.imageUrl100x100();

if (mainUrl != null && !mainUrl.isBlank()) {
GroupImage main = GroupImage.create(group, mainUrl, sortOrder);
newEntities.add(main);
}

if (thumbUrl != null && !thumbUrl.isBlank()) {
GroupImage thumb = GroupImage.create(group, thumbUrl, sortOrder);
newEntities.add(thumb);
}
}

if (!newEntities.isEmpty()) {
groupImageRepository.saveAll(newEntities);
}

// 7. sortOrder 기준으로 한 세트 단위 응답 DTO 구성
Map<Integer, List<GroupImage>> byOrder = newEntities.stream()
.collect(Collectors.groupingBy(GroupImage::getSortOrder));

return byOrder.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.map(entry -> {
List<GroupImage> list = entry.getValue();

GroupImage main = list.stream()
.filter(img -> img.getImageUrl().contains("440x240"))
.findFirst()
.orElse(list.getFirst());

GroupImage thumb = list.stream()
.filter(img -> img.getImageUrl().contains("100x100"))
.findFirst()
.orElse(null);

return GroupImageItemResponse.from(main, thumb);

})
.toList();
}
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

The new updateGroupImages method lacks unit test coverage. Given that the repository has existing tests, consider adding tests to cover scenarios such as:

  • Successful image update by HOST
  • Permission denied when non-HOST tries to update
  • Validation for maximum 3 images
  • Old images properly deleted from S3
  • Correct handling of null/empty requests

Copilot uses AI. Check for mistakes.
Comment on lines +387 to +433
public String extractKeyFromUrl(String imageUrl) {
if (imageUrl == null || imageUrl.isBlank()) {
return null;
}

String endpoint = awsS3Properties.getPublicEndpoint();
if (endpoint != null && !endpoint.isBlank()) {
String prefix = endpoint.endsWith("/") ? endpoint : endpoint + "/";
if (imageUrl.startsWith(prefix)) {
return imageUrl.substring(prefix.length());
}
}

// fallback: 마지막 "/" 이후를 key로 사용
int idx = imageUrl.lastIndexOf('/');
if (idx >= 0 && idx + 1 < imageUrl.length()) {
return imageUrl.substring(idx + 1);
}

// 그래도 안 되면 전체를 key로 시도 (최악의 경우)
return imageUrl;
}

public void deleteByUrl(String imageUrl) {
String key = extractKeyFromUrl(imageUrl);
if (key == null || key.isBlank()) {
return;
}
delete(key);
}

public void deleteAllByUrls(List<String> imageUrls) {
if (imageUrls == null || imageUrls.isEmpty()) {
return;
}

List<String> keys = imageUrls.stream()
.filter(Objects::nonNull)
.map(this::extractKeyFromUrl)
.filter(Objects::nonNull)
.filter(key -> !key.isBlank())
.toList();

if (!keys.isEmpty()) {
deleteAll(keys);
}
}
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

The new deleteByUrl, deleteAllByUrls, and extractKeyFromUrl methods lack unit test coverage. Consider adding tests to verify:

  • Correct key extraction from various URL formats
  • Handling of null/empty URLs
  • Proper delegation to existing delete methods
  • Edge cases in URL parsing

Copilot uses AI. Check for mistakes.
Comment on lines +26 to +27
@Future(message = "모임: 종료 시간은 현재 이후여야 합니다.")
LocalDateTime endTime,
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

[nitpick] The @Future constraint on endTime requires it to be in the future at the time of validation, but this doesn't guarantee that endTime will be after startTime. The validation in the service layer (lines 481-484) partially addresses this, but only when both values are non-null. Consider adding a custom validator or ensuring that the relationship between startTime and endTime is properly validated even when one is null.

Copilot uses AI. Check for mistakes.

--boundary
Content-Disposition: form-data; name="images"; filename="img1.png"
Content-Type: image/jpeg
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

The Content-Type is declared as image/jpeg but the file being uploaded is img1.png. This mismatch between the declared Content-Type and actual file type could cause issues. The Content-Type should be image/png.

Suggested change
Content-Type: image/jpeg
Content-Type: image/png

Copilot uses AI. Check for mistakes.
// 2. HOST 권한 체크
if (!group.getHost().getId().equals(userId)) {
throw new GroupException(
GroupErrorCode.NO_PERMISSION_TO_UPDATE_GROUP, // 삭제도 동일 코드 재사용
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

The error code NO_PERMISSION_TO_UPDATE_GROUP is being reused for delete operations, but the message says "수정할 권한이 없습니다" (no permission to update). Consider creating a separate error code like NO_PERMISSION_TO_DELETE_GROUP with an appropriate message, or rename the existing one to be more generic (e.g., NO_PERMISSION_TO_MODIFY_GROUP).

Suggested change
GroupErrorCode.NO_PERMISSION_TO_UPDATE_GROUP, // 삭제도 동일 코드 재사용
GroupErrorCode.NO_PERMISSION_TO_DELETE_GROUP,

Copilot uses AI. Check for mistakes.
HOST_CANNOT_LEAVE_OWN_GROUP(HttpStatus.BAD_REQUEST, "모임: HOST는 나갈 수 없습니다. 모임 ID: %s 회원 ID: %s");
HOST_CANNOT_LEAVE_OWN_GROUP(HttpStatus.BAD_REQUEST, "모임: HOST는 나갈 수 없습니다. 모임 ID: %s 회원 ID: %s"),
NO_PERMISSION_TO_UPDATE_GROUP(HttpStatus.FORBIDDEN, "모임: 해당 모임을 수정할 권한이 없습니다. 모임 ID: %s 회원 ID: %s"),
INVALID_MAX_PARTICIPANTS_LESS_THAN_CURRENT(HttpStatus.BAD_REQUEST, "모임: 현재 참여 인원 수(%s)보다 작은 값으로 최대 인원을 줄일 수 없습니다."),;
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

There's a trailing semicolon after the comma at the end of this line. This is a syntax error that should be removed.

Suggested change
INVALID_MAX_PARTICIPANTS_LESS_THAN_CURRENT(HttpStatus.BAD_REQUEST, "모임: 현재 참여 인원 수(%s)보다 작은 값으로 최대 인원을 줄일 수 없습니다."),;
INVALID_MAX_PARTICIPANTS_LESS_THAN_CURRENT(HttpStatus.BAD_REQUEST, "모임: 현재 참여 인원 수(%s)보다 작은 값으로 최대 인원을 줄일 수 없습니다.");

Copilot uses AI. Check for mistakes.
모임 이미지 관리의 일관성을 개선하고 잠재적인 문제를 방지하기 위해 이미지 삭제 프로세스 순서를 재정렬했습니다. 모임 삭제 권한 확인 시 올바른 오류 코드를 사용하도록 업데이트했습니다. 또한 이미지 업데이트 요청의 유효성을 검사합니다.
액세스 토큰을 가져오기 위해 사용자 로그인 기능을 추가합니다.
가져온 토큰을 사용하여 그룹에 참여합니다.
이미지 콘텐츠 형식을 png로 변경합니다.
@LimdaeIl LimdaeIl merged commit f781c7c into main Dec 10, 2025
1 check was pending
@LimdaeIl LimdaeIl deleted the feat/group-img-update-delete branch December 10, 2025 07:53
@github-project-automation github-project-automation bot moved this from In progress to Done in WeGo-Together Backend Dec 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[FEAT] 모임 수정 및 삭제

1 participant