Skip to content

Conversation

@dahyun24
Copy link
Contributor

@dahyun24 dahyun24 commented Nov 2, 2025

🔗 연관된 이슈

🚀 변경 유형

  • ✨ 기능 추가 (feature)
  • 🐛 버그 수정 (fix)
  • 📝 문서 변경 (docs)
  • ♻️ 리팩토링 (refactor)
  • 🧪 테스트 추가 / 수정 (test)
  • ⚙️ 설정 변경 (chore)

📝 작업 내용

  • 미구현되어있던 사용자의 photoCnt 증가, 감소 로직을 추가했습니다.
  • PhotoStatus에서 PROCESSING 을 없앴습니다.
    • 썸네일 callback 관련 서비스도 수정했습니다.
  • 따라서 성공에 대한 응답을 프론트에서 따로 받지 않고 (썸네일 생성 = 업로드 성공)이라고 간주합니다.

💬 리뷰 요구사항

  • 파이팅

Summary by CodeRabbit

릴리스 노트

  • 개선사항
    • 사진 업로드 실패 처리 로직 단순화 — 실패 전용 보고 흐름으로 정리됨.
    • 업로드 전 이미지 URL이 일관되게 생성되어 미리보기/링크 신뢰도 향상.
    • 업로드 실패 시 사용자·앨범의 사진 개수 동기화 개선으로 통계 정확성 향상.
    • 중복 보고 처리를 보완한 검증 로직으로 무결성 강화.
    • 상태 관리 범위 축소로 상태 전환 처리 간소화.

@coderabbitai
Copy link

coderabbitai bot commented Nov 2, 2025

Walkthrough

사진 업로드 워크플로우에서 PROCESSING 상태를 제거하고, 업로드 실패 전용 리포트로 단순화했으며 UserService를 도입해 사용자 사진 개수 증감 로직을 추가·연동했습니다. 일부 URL 생성 순서와 검증 중복-ID 처리도 조정되었습니다.

Changes

코호트 / 파일(s) 변경 요약
상태 정의 변경
src/main/java/com/cheeeese/photo/domain/PhotoStatus.java
PROCESSING enum 상수 제거 (UPLOADING, COMPLETED, FAILED)
콜백 상태 조정
src/main/java/com/cheeeese/photo/application/PhotoCallbackService.java
markUploadCompleted에서 photoRepository.updateStatusAndUrl에 전달하는 상태를 PROCESSING -> UPLOADING으로 변경
사진 서비스 리팩토링
src/main/java/com/cheeeese/photo/application/PhotoService.java
UserService 및 버킷 설정 주입, presigned URL 생성 전 이미지 URL 업데이트, 업로드 개수로 사용자/앨범 사진 카운트 증감, 실패 처리 로직(handleFailedUploads) 추가 및 성공 처리 경로 제거
검증 로직 업데이트
src/main/java/com/cheeeese/photo/application/validator/PhotoValidator.java
요청 ID에서 고유 ID 집합(uniqueRequestedIds)을 생성해 누락 ID 계산 로직 개선; fetch는 기존대로 findAllById(photoIds) 호출
요청 DTO 변경
src/main/java/com/cheeeese/photo/dto/request/PhotoUploadReportRequest.java
successPhotoIds 필드 제거, 클래스/필드 스키마 설명을 실패 전용으로 변경 (예시 값 및 설명 수정 포함)
Swagger 문서 단순화
src/main/java/com/cheeeese/photo/presentation/swagger/PhotoSwagger.java
업로드 결과 보고 API에서 부분 성공 경로 제거 — 실패 처리 중심으로 요약/응답 정의 조정
사용자 서비스 확장
src/main/java/com/cheeeese/user/application/UserService.java
UserRepository 주입 및 incrementPhotoCount(Long,int), decrementPhotoCount(Long,int) 공개 트랜잭션 메서드 추가 (실패 시 예외 발생)
사용자 리포지토리 쿼리 추가
src/main/java/com/cheeeese/user/infrastructure/persistence/UserRepository.java
@Modifying JPQL 쿼리로 incrementPhotoCount / decrementPhotoCount 메서드 추가
사용자 에러 코드 추가
src/main/java/com/cheeeese/user/exception/code/UserErrorCode.java
USER_PHOTO_COUNT_INCREMENT_FAILED, USER_PHOTO_COUNT_DECREMENT_FAILED 에러 코드 추가

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant PhotoService
    participant PhotoValidator
    participant PhotoRepository
    participant UserService
    participant UserRepository

    rect rgb(200,220,255)
    Note over Client,PhotoService: Presigned URL 생성 (성공 경로)
    Client->>PhotoService: createPresignedUrls(request)
    PhotoService->>PhotoService: uploadCount 계산, 이미지 URL 준비
    PhotoService->>UserService: incrementPhotoCount(userId, count)
    UserService->>UserRepository: photoCnt 증가 쿼리
    UserRepository-->>UserService: 결과(1)
    UserService-->>PhotoService: 성공
    PhotoService-->>Client: presigned URLs 반환
    end

    rect rgb(255,220,200)
    Note over Client,PhotoService: 업로드 실패 보고 (변경된 흐름)
    Client->>PhotoService: reportUploadResult(failurePhotoIds)
    PhotoService->>PhotoValidator: validate(userId, failurePhotoIds)
    PhotoValidator->>PhotoRepository: findAllById(photoIds)
    PhotoRepository-->>PhotoValidator: photos
    PhotoValidator-->>PhotoService: validated (albumId 등)
    PhotoService->>PhotoRepository: update status -> FAILED
    PhotoRepository-->>PhotoService: updatedCount
    alt updatedCount > 0
        PhotoService->>UserService: decrementPhotoCount(userId, count)
        UserService->>UserRepository: photoCnt 감소 쿼리
        UserRepository-->>UserService: 결과(1)
        UserService-->>PhotoService: 성공
        PhotoService->>PhotoRepository: album photoCnt 조정
    end
    PhotoService-->>Client: 응답
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25분

  • 주의할 파일/영역:
    • PhotoStatus 제거 영향 범위(프로젝트 전반의 상태 참조)
    • PhotoService의 트랜잭션/일관성: 이미지 URL 업데이트와 presigned URL 생성 순서, 사용자·앨범 카운트 동기화
    • UserService의 증감 쿼리 성공 조건(반환값 == 1)과 예외 처리
    • PhotoCallbackService 변경으로 인한 콜백 경로 호환성

Possibly related PRs

Suggested reviewers

  • zyovn

Poem

🐰 깡충, PROCESSING 사라지고,
작은 실패들만 모아두네.
유저 카운트 살피며 폴짝폴짝,
업로드 길을 단순히 하니,
새 URL로 반짝 — 찰칵! 📸

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.56% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive PR 제목 "fix: photo status 관련 로직 수정"은 실제 변경 사항과 관련이 있습니다. 실제로 PhotoStatus 열거형에서 PROCESSING 상수가 제거되었고, PhotoService 및 PhotoCallbackService에서 photo status와 관련된 로직이 수정되었습니다. 그러나 "photo status 관련 로직"이라는 표현이 다소 모호하여, 정확히 어떤 상태 관리 로직이나 어떤 측면의 수정을 의미하는지 명확하지 않습니다. 또한 이 PR의 중요한 변경 사항 중 하나인 사용자의 photoCnt 증가/감소 로직 추가 부분이 제목에 반영되어 있지 않습니다. 제목을 더 구체적으로 수정하여 변경의 핵심을 명확히 하는 것을 권장합니다. 예를 들어 "fix: PhotoStatus PROCESSING 상태 제거 및 사용자 사진 개수 관리 로직 추가" 또는 "fix: 사진 업로드 상태 처리 로직 정리 및 사진 개수 추적 기능 개선" 같이 변경의 주요 목적을 분명하게 드러내는 제목으로 변경하면 더욱 명확할 것입니다.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/#42-change-status

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@dahyun24 dahyun24 self-assigned this Nov 2, 2025
@dahyun24 dahyun24 added the 🐛bug Something isn't working label Nov 2, 2025
@dahyun24 dahyun24 linked an issue Nov 2, 2025 that may be closed by this pull request
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: 2

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/com/cheeeese/photo/application/PhotoService.java (1)

140-159: 실패 처리 로직에서 사용자와 앨범 카운트 감소 순서가 일관성 문제를 유발할 수 있습니다.

Lines 153-157에서 사용자 카운트를 먼저 감소시킨 후 앨범 카운트를 감소시키는데, 앨범 카운트 감소가 실패하면 사용자 카운트만 감소된 불일치 상태가 됩니다.

다음과 같이 순서를 변경하여 일관성을 보장하세요:

         if (updatedRows > 0) {
-            userService.decrementPhotoCount(user.getId(), updatedRows);
+            // 앨범 카운트를 먼저 감소 (실패 시 사용자 카운트는 영향 없음)
             int decremented = albumRepository.decrementPhotoCount(albumId, updatedRows);
             if (decremented == 0) {
                 throw new PhotoException(PhotoErrorCode.PHOTO_COUNT_DECREMENT_FAILED);
             }
+            
+            userService.decrementPhotoCount(user.getId(), updatedRows);
         }

이렇게 하면 앨범 카운트 감소가 실패해도 사용자 카운트는 변경되지 않아 일관성이 유지됩니다.

추가 고려사항: createPresignedUrls 메서드(Lines 52-68)에서도 동일한 순서(앨범 먼저, 사용자 나중)를 적용하여 전체적인 일관성을 확보하는 것이 좋습니다.

🧹 Nitpick comments (1)
src/main/java/com/cheeeese/photo/application/PhotoService.java (1)

122-123: 이미지 URL 구성 로직이 올바르게 추가되었습니다.

버킷과 객체 키를 조합하여 전체 이미지 URL을 생성하고 있습니다. 문자열 연결이 정상 작동하지만, 더 명확한 표현을 위해 String.format 사용을 고려할 수 있습니다.

선택 사항: 가독성 향상을 위해 다음과 같이 변경할 수 있습니다:

-        String imageUrl = bucket + "/" + objectKey;
+        String imageUrl = String.format("%s/%s", bucket, objectKey);
📜 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 a211887 and 958d51d.

📒 Files selected for processing (9)
  • src/main/java/com/cheeeese/photo/application/PhotoCallbackService.java (1 hunks)
  • src/main/java/com/cheeeese/photo/application/PhotoService.java (5 hunks)
  • src/main/java/com/cheeeese/photo/application/validator/PhotoValidator.java (1 hunks)
  • src/main/java/com/cheeeese/photo/domain/PhotoStatus.java (0 hunks)
  • src/main/java/com/cheeeese/photo/dto/request/PhotoUploadReportRequest.java (1 hunks)
  • src/main/java/com/cheeeese/photo/presentation/swagger/PhotoSwagger.java (1 hunks)
  • src/main/java/com/cheeeese/user/application/UserService.java (3 hunks)
  • src/main/java/com/cheeeese/user/exception/code/UserErrorCode.java (1 hunks)
  • src/main/java/com/cheeeese/user/infrastructure/persistence/UserRepository.java (1 hunks)
💤 Files with no reviewable changes (1)
  • src/main/java/com/cheeeese/photo/domain/PhotoStatus.java
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-31T13:17:52.512Z
Learnt from: dahyun24
Repo: Say-Cheeeese/BE PR: 35
File: src/main/java/com/cheeeese/photo/application/PhotoService.java:46-52
Timestamp: 2025-10-31T13:17:52.512Z
Learning: In src/main/java/com/cheeeese/photo/application/PhotoService.java, the getRecentThumbnailUrls method intentionally returns only the first thumbnail URL when photos.size() < 5, rather than returning all available thumbnails. This is according to product requirements: 0 photos → empty list, 1-4 photos → single thumbnail (most recent), 5 photos → all 5 thumbnails.

Applied to files:

  • src/main/java/com/cheeeese/photo/application/PhotoService.java
  • src/main/java/com/cheeeese/photo/application/validator/PhotoValidator.java
  • src/main/java/com/cheeeese/photo/application/PhotoCallbackService.java
🧬 Code graph analysis (1)
src/main/java/com/cheeeese/photo/application/PhotoService.java (2)
src/main/java/com/cheeeese/user/application/UserService.java (1)
  • Service (14-56)
src/main/java/com/cheeeese/photo/infrastructure/mapper/PhotoMapper.java (1)
  • PhotoMapper (12-42)
🔇 Additional comments (8)
src/main/java/com/cheeeese/photo/application/PhotoCallbackService.java (1)

19-30: PROCESSING 상태 제거에 따른 변경사항이 올바르게 반영되었습니다.

콜백 메서드가 UPLOADING 상태에서 COMPLETED 상태로 전환하도록 수정되었으며, 예상 상태 검증 패턴이 적용되어 동시성 문제를 방지하고 있습니다.

src/main/java/com/cheeeese/photo/application/validator/PhotoValidator.java (1)

82-100: 중복 ID 처리 로직이 개선되었습니다.

입력된 photoIds를 직접 조회하고, 중복 제거된 uniqueRequestedIds를 사용하여 누락된 ID를 검증하는 방식으로 변경되었습니다. JPA의 findAllById는 중복된 ID가 입력되어도 고유한 엔티티만 반환하므로, 이 변경은 올바른 검증을 보장합니다.

src/main/java/com/cheeeese/user/exception/code/UserErrorCode.java (1)

14-15: 사용자 사진 개수 증감 실패를 위한 에러 코드가 적절하게 추가되었습니다.

HttpStatus.CONFLICT (409)를 사용하여 동시성 업데이트 실패를 명확히 표현하고 있으며, 네이밍도 일관성 있게 작성되었습니다.

src/main/java/com/cheeeese/photo/presentation/swagger/PhotoSwagger.java (1)

76-87: API 문서가 변경된 요구사항에 맞게 업데이트되었습니다.

성공 경로가 제거되고 실패 처리에만 집중하도록 문서가 수정되었습니다. 프론트엔드가 썸네일 생성을 업로드 성공으로 처리하는 새로운 동작 방식과 일치합니다.

src/main/java/com/cheeeese/user/infrastructure/persistence/UserRepository.java (1)

14-16: 사용자 사진 개수 증가 메서드가 올바르게 구현되었습니다.

JPQL 업데이트 쿼리와 적절한 @Modifying 플래그 설정이 적용되었습니다.

src/main/java/com/cheeeese/user/application/UserService.java (1)

41-55: 사용자 사진 개수 관리 메서드가 적절하게 구현되었습니다.

두 메서드 모두 트랜잭션 처리와 엄격한 업데이트 검증(updated != 1)을 수행하여 동시성 문제나 존재하지 않는 사용자를 감지합니다. UserRepository에 음수 방지 로직이 추가되면, decrementPhotoCount에서 photoCnt가 부족한 경우 적절히 예외가 발생합니다.

UserRepository의 decrementPhotoCount에 음수 방지 로직이 추가되었는지 확인해주세요.

src/main/java/com/cheeeese/photo/application/PhotoService.java (2)

16-16: UserService 의존성과 버킷 설정이 적절하게 추가되었습니다.

사용자 사진 개수 관리를 위한 UserService와 URL 구성을 위한 버킷 설정이 올바르게 주입되었습니다.

Also applies to: 19-20, 32-32, 39-40


52-68: 트랜잭션 전파 구조상 일관성 문제는 발생하지 않습니다.

스크립트 결과에서 UserService.incrementPhotoCount@Transactional로 명시되어 있으며, 기본 전파 방식(REQUIRED)을 사용합니다. PhotoService.createPresignedUrls@Transactional이므로, 두 저장소 업데이트는 동일한 트랜잭션 컨텍스트에서 참여합니다. 따라서 albumRepository.incrementPhotoCount 또는 userService.incrementPhotoCount 중 하나라도 실패하면 전체 트랜잭션이 롤백되어 원자성이 보장됩니다. 원본 검토 의견의 우려사항은 유효하지 않습니다.

Likely an incorrect or invalid review comment.

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: 0

🧹 Nitpick comments (1)
src/main/java/com/cheeeese/user/infrastructure/persistence/UserRepository.java (1)

14-16: 선택적 제안: 입력 검증 추가를 고려해보세요.

현재 구현은 정상적으로 작동하지만, count가 음수이거나 0인 경우에 대한 방어 로직이 없습니다. 서비스 레이어에서 검증하고 있다면 문제없지만, 리포지토리 레벨에서 추가 안전장치를 고려할 수 있습니다.

필요하다면 다음과 같이 수정할 수 있습니다:

-    @Query("UPDATE User u SET u.photoCnt = u.photoCnt + :count WHERE u.id = :userId")
+    @Query("UPDATE User u SET u.photoCnt = u.photoCnt + :count WHERE u.id = :userId AND :count > 0")
     int incrementPhotoCount(@Param("userId") Long userId, @Param("count") int count);
📜 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 958d51d and 80df22f.

📒 Files selected for processing (3)
  • src/main/java/com/cheeeese/photo/application/PhotoService.java (5 hunks)
  • src/main/java/com/cheeeese/photo/dto/request/PhotoUploadReportRequest.java (1 hunks)
  • src/main/java/com/cheeeese/user/infrastructure/persistence/UserRepository.java (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-31T13:17:52.512Z
Learnt from: dahyun24
Repo: Say-Cheeeese/BE PR: 35
File: src/main/java/com/cheeeese/photo/application/PhotoService.java:46-52
Timestamp: 2025-10-31T13:17:52.512Z
Learning: In src/main/java/com/cheeeese/photo/application/PhotoService.java, the getRecentThumbnailUrls method intentionally returns only the first thumbnail URL when photos.size() < 5, rather than returning all available thumbnails. This is according to product requirements: 0 photos → empty list, 1-4 photos → single thumbnail (most recent), 5 photos → all 5 thumbnails.

Applied to files:

  • src/main/java/com/cheeeese/photo/application/PhotoService.java
🧬 Code graph analysis (1)
src/main/java/com/cheeeese/photo/application/PhotoService.java (2)
src/main/java/com/cheeeese/user/application/UserService.java (1)
  • Service (14-56)
src/main/java/com/cheeeese/photo/infrastructure/mapper/PhotoMapper.java (1)
  • PhotoMapper (12-42)
🔇 Additional comments (8)
src/main/java/com/cheeeese/user/infrastructure/persistence/UserRepository.java (1)

18-20: 이전 리뷰 우려사항이 해결되었습니다!

u.photoCnt >= :count 조건이 추가되어 사진 개수가 음수가 되는 것을 방지합니다. 이전 리뷰에서 요청된 개선사항이 정확하게 반영되었습니다.

src/main/java/com/cheeeese/photo/dto/request/PhotoUploadReportRequest.java (1)

10-14: 이전 리뷰 우려사항이 해결되었습니다!

DTO가 실패 처리 전용으로 단순화되었고, 상태 전환 설명도 "UPLOADING -> FAILED"로 정확하게 수정되었습니다. PROCESSING 상태 제거와 일관성있게 정리되었습니다.

src/main/java/com/cheeeese/photo/application/PhotoService.java (6)

16-16: LGTM: 의존성 추가가 적절합니다.

UserService와 bucket 설정값이 올바르게 추가되어 사용자 사진 개수 관리 및 이미지 URL 구성에 활용됩니다.

Also applies to: 19-19, 32-32, 39-40


57-64: LGTM: 사용자 사진 개수 증가 로직이 올바르게 추가되었습니다.

앨범 사진 개수 증가 후 사용자 사진 개수를 증가시키는 순서가 적절하며, @transactional 경계 내에서 실행되어 실패 시 함께 롤백됩니다.


72-79: LGTM: 실패 처리 로직이 잘 단순화되었습니다.

Line 73의 distinct() 호출로 중복 ID를 제거하여 불필요한 중복 처리를 방지하고, 검증 후 실패 처리를 위임하는 흐름이 명확합니다.


122-123: LGTM: 이미지 URL 구성 방식이 개선되었습니다.

bucket을 포함한 전체 URL을 구성하여 이미지 URL을 업데이트하는 것이 적절하며, presigned URL 생성 전에 설정되어 올바른 순서로 처리됩니다.


140-150: LGTM: 실패 사진 상태 업데이트 로직이 정확합니다.

UPLOADING 상태의 사진만 FAILED로 변경하고, 업데이트된 행 수를 검증하여 부분 업데이트나 경쟁 상태를 방지합니다.


152-158: LGTM: 사진 개수 감소 로직이 일관성있게 구현되었습니다.

앨범과 사용자 사진 개수를 모두 감소시키며, UserService를 통한 사용자 개수 감소 실패 시 예외가 발생하여 전체 트랜잭션이 롤백됩니다.

Copy link
Member

@zyovn zyovn left a comment

Choose a reason for hiding this comment

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

수고하셧습니다~~🧀🦖

@dahyun24 dahyun24 merged commit f7e8f94 into develop Nov 3, 2025
1 check passed
@zyovn zyovn deleted the fix/#42-change-status branch November 3, 2025 16:39
@coderabbitai coderabbitai bot mentioned this pull request Nov 4, 2025
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐛bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: 이미지 업로드 설계 수정

3 participants