Skip to content

Conversation

@zyovn
Copy link
Member

@zyovn zyovn commented Nov 13, 2025

🔗 연관된 이슈

🚀 변경 유형

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

📝 작업 내용

  • 앨범 상세 정보 API
  • 띱한 사용자 목록 API
  • 베스트 치즈 컷 (베스트 사진 4개) API
  • 사용자 앨범 생성 및 참여 시, albumCnt++
  • cdnUrl 파싱 수정
  • 프론트 요구사항 반영 (일단 몇가지만..)

📸 스크린샷

베스트 치즈 컷 (베스트 사진 4개) API
image

띱한 사용자 목록 조회 API
스크린샷 2025-11-14 012910

앨범 상세 정보 API (프론트가 여기저기 쓸)
스크린샷 2025-11-14 012848

💬 리뷰 요구사항

📜 리뷰 규칙

Reviewer는 아래 P5 Rule을 참고하여 리뷰를 진행합니다.
P5 Rule을 통해 Reviewer는 Reviewee에게 리뷰의 의도를 보다 정확히 전달할 수 있습니다.

  • P1: 꼭 반영해주세요 (Comment)
  • P2: 적극적으로 고려해주세요 (Comment)
  • P3: 웬만하면 반영해 주세요 (Comment)
  • P4: 반영해도 좋고 넘어가도 좋습니다 (Approve)
  • P5: 그냥 사소한 의견입니다 (Approve)

악정신없어~~

  • 다음 할 일: 온보딩 API 수정, 좋아요 생성 시 사용자 likeCnt 컬럼 증가, cdn 설정 수정

Summary by CodeRabbit

  • 새로운 기능

    • 앨범 정보 조회 API 추가(제목, 이벤트 날짜, 참여자 수, 총 사진 수 등)
    • 베스트 앨범컷 조회 API 추가(인기도 순 상위 4장, 좋아요 여부 표시)
    • 사진별 좋아요한 사용자 목록 조회 API 추가(유저 역할·내 여부 포함)
  • 개선사항

    • 앨범당 최대 업로드 가능 사진 수 증가(10 → 100)
    • 사진 응답에 업로더 이름, 원본/썸네일 URL, 촬영 시간·업로드 시간 추가
    • CDN 경로 정규화 및 URL 처리 개선

@zyovn zyovn self-assigned this Nov 13, 2025
@zyovn zyovn added the ✨feature New feature or request label Nov 13, 2025
@zyovn zyovn linked an issue Nov 13, 2025 that may be closed by this pull request
4 tasks
@coderabbitai
Copy link

coderabbitai bot commented Nov 13, 2025

Walkthrough

앨범 정보 조회, 베스트 4컷 조회, 사진 좋아요 사용자 목록 조회 API와 관련 DTO·매퍼·저장소·서비스·컨트롤러 변경을 추가합니다. 사진 상태 필터링, CDN URL 정규화, 사용자 앨범 카운트 증가 및 일부 캐시 무효화 연계가 포함됩니다. AlbumValidator.validateAlbumParticipant의 가시성이 private→public으로 변경되었습니다.

Changes

연번 Cohort / File(s) 변경 요약
1 앨범 서비스/API
src/main/java/com/cheeeese/album/application/AlbumService.java, src/main/java/com/cheeeese/album/presentation/AlbumController.java, src/main/java/com/cheeeese/album/presentation/swagger/AlbumSwagger.java
getAlbumInfo, getAlbumBest4Cut 공개 메서드 및 컨트롤러·Swagger 엔드포인트 추가
2 앨범 DTO·매퍼
src/main/java/com/cheeeese/album/dto/response/AlbumInfoResponse.java, src/main/java/com/cheeeese/album/dto/response/AlbumBest4CutResponse.java, src/main/java/com/cheeeese/album/infrastructure/mapper/AlbumMapper.java
AlbumInfoResponse, AlbumBest4CutResponse 레코드 추가; AlbumMapper.toBest4CutResponse() 추가; toEntity 내 maxPhotoCount 10→100
3 포토 좋아요 조회 서비스/컨트롤러
src/main/java/com/cheeeese/photo/application/PhotoInfoService.java, src/main/java/com/cheeeese/photo/presentation/PhotoQueryController.java, src/main/java/com/cheeeese/photo/presentation/swagger/PhotoQuerySwagger.java
사진 좋아요 사용자 목록 조회 서비스·엔드포인트(getPhotoLikedUsers) 추가
4 포토 DTO·매퍼 변경
src/main/java/com/cheeeese/photo/dto/response/PhotoLikedUserResponse.java, .../PhotoDetailResponse.java, .../PhotoListResponse.java, .../PhotoLikedResponse.java, .../PhotoLikedPageResponse.java, .../PhotoPageResponse.java, src/main/java/com/cheeeese/photo/infrastructure/mapper/PhotoMapper.java
DTO에 name, imageUrl, captureTime, createdAt 등 필드 추가 및 예제 업데이트; PhotoMapper 매핑 시그니처 및 toAlbumInfoResponse/toPhotoLiker 등 메서드 추가/변경
5 저장소 쿼리 추가·수정
src/main/java/com/cheeeese/photo/infrastructure/persistence/PhotoRepository.java, src/main/java/com/cheeeese/photo/infrastructure/persistence/PhotoLikesRepository.java, src/main/java/com/cheeeese/user/infrastructure/persistence/UserRepository.java
findAllByAlbumCodeAndStatus()로 상태 필터 추가, findTop4CompletedPhotosByLikes()·findAlbumCodeByPhotoId()·findLikersByPhotoId() 추가, incrementAlbumCnt() 추가
6 포토 쿼리·콜백·서비스 조정
src/main/java/com/cheeeese/photo/application/PhotoQueryService.java, src/main/java/com/cheeeese/photo/application/PhotoCallbackService.java, src/main/java/com/cheeeese/photo/application/PhotoService.java
PhotoQueryService에 상태 기반 조회 및 CDN URL 해석 보강; PhotoCallbackService에 PhotoQueryService 주입·캐시 무효화 호출 추가; PhotoService.createPresignedUrls에서 캐시 무효화 제거
7 검증/유틸/응답 코드
src/main/java/com/cheeeese/album/application/validator/AlbumValidator.java, src/main/java/com/cheeeese/global/common/code/SuccessCode.java, src/main/java/com/cheeeese/global/util/resolver/CdnUrlResolver.java
validateAlbumParticipant() 가시성 private→public 변경; 성공 코드 ALBUM_INFO_GET_SUCCESS, ALBUM_BEST4CUT_GET_SUCCESS, PHOTO_LIKERS_GET_SUCCESS 추가; CDN 경로에서 say-cheeeese/ 접두사 정규화 추가

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant AlbumCtrl as AlbumController
    participant AlbumSvc as AlbumService
    participant Validator as AlbumValidator
    participant PhotoRepo as PhotoRepository
    participant LikesRepo as PhotoLikesRepository
    participant CDN as CdnUrlResolver
    participant Mapper as AlbumMapper

    User->>AlbumCtrl: GET /v1/album/{code}/best-4cut
    AlbumCtrl->>AlbumSvc: getAlbumBest4Cut(user, code)
    AlbumSvc->>Validator: validateAlbumParticipant(album, user)
    AlbumSvc->>PhotoRepo: findTop4CompletedPhotosByLikes(albumId, COMPLETED, pageable)
    PhotoRepo-->>AlbumSvc: List<Photo>
    loop per photo
        AlbumSvc->>LikesRepo: fetch likes by photoId / check liked-by-user
        AlbumSvc->>CDN: resolve(thumbnailPath)
        CDN-->>AlbumSvc: thumbnailUrl
        AlbumSvc->>Mapper: toBest4CutResponse(photo, thumbnailUrl, isLiked)
    end
    AlbumSvc-->>AlbumCtrl: List<AlbumBest4CutResponse>
    AlbumCtrl-->>User: 200 (ALBUM_BEST4CUT_GET_SUCCESS)
Loading
sequenceDiagram
    actor User
    participant PhotoCtrl as PhotoQueryController
    participant PhotoInfoSvc as PhotoInfoService
    participant Validator as AlbumValidator
    participant PhotoRepo as PhotoRepository
    participant LikesRepo as PhotoLikesRepository
    participant Mapper as PhotoMapper

    User->>PhotoCtrl: GET /{code}/photos/{photoId}/likers
    PhotoCtrl->>PhotoInfoSvc: getPhotoLikedUsers(user, code, photoId)
    PhotoInfoSvc->>Validator: validateAlbumParticipant(album, user)
    PhotoInfoSvc->>PhotoRepo: findByIdAndAlbumCode(photoId, code)
    PhotoRepo-->>PhotoInfoSvc: Photo
    PhotoInfoSvc->>LikesRepo: findLikersByPhotoId(photoId)
    LikesRepo-->>PhotoInfoSvc: List<User>
    loop per liker
        PhotoInfoSvc->>Mapper: toPhotoLiker(user, isMe, role)
    end
    PhotoInfoSvc->>Mapper: toPhotoLikerResponse(photo, likers)
    Mapper-->>PhotoInfoSvc: PhotoLikedUserResponse
    PhotoInfoSvc-->>PhotoCtrl: PhotoLikedUserResponse
    PhotoCtrl-->>User: 200 (PHOTO_LIKERS_GET_SUCCESS)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • 검토 시 유의할 파일/영역:
    • AlbumService의 신규 공개 API와 의존성 연결(Mapper, PhotoRepository, CdnUrlResolver)
    • PhotoMapper 시그니처 변경에 따른 호출부 일관성 점검
    • PhotoRepository 쿼리 변경(상태 필터·정렬) 영향 범위
    • PhotoCallbackService의 캐시 무효화 흐름 및 동시성 영향
    • AlbumValidator 가시성 변경이 다른 모듈에서의 사용 의도에 미치는 영향

Possibly related issues

Possibly related PRs

Suggested reviewers

  • dahyun24

Poem

🐰 새 앨범 열고 발을 폴짝,
네 장 골라 반짝임을 봐요,
좋아요 건 얼굴들 하나하나 세고,
CDN 길 따라 썸네일 빛나네,
개발자님, 기쁜 배포 축하해요! 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.96% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 앨범 및 사진 조회 관련 API 기능 추가를 명확하게 설명하며, 실제 변경 사항(앨범 정보 조회, 베스트 컷 조회, 띱한 사용자 목록 조회 API 등)과 일치합니다.
✨ 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 feat/#54-get-etc

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.

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

🧹 Nitpick comments (4)
src/main/java/com/cheeeese/global/util/resolver/CdnUrlResolver.java (1)

33-35: CDN 경로 정규화 로직이 올바르게 구현되었습니다.

say-cheeeese/ 접두사를 제거하는 로직이 정확하게 동작합니다.

선택적으로, Java 11 이상을 사용 중이라면 더 명시적인 코드로 개선할 수 있습니다:

-        if (path.startsWith("say-cheeeese/")) {
-            path = path.substring("say-cheeeese/".length());
-        }
+        final String PREFIX = "say-cheeeese/";
+        if (path.startsWith(PREFIX)) {
+            path = path.substring(PREFIX.length());
+        }
src/main/java/com/cheeeese/photo/dto/response/PhotoBest4CutResponse.java (1)

1-18: photoId 필드 추가를 고려하세요.

현재 응답에는 thumbnailUrl, likeCnt, isLiked만 포함되어 있습니다. 클라이언트가 특정 사진에 대한 상세 페이지 이동이나 추가 액션을 수행하려면 photoId가 필요할 수 있습니다. 다른 사진 응답 DTO들(PhotoListResponse, PhotoLikedResponse, PhotoDetailResponse)은 모두 photoId를 포함하고 있습니다.

프론트엔드 요구사항을 확인한 후, 필요하다면 아래와 같이 photoId를 추가하세요:

 @Builder
 @Schema(description = "베스트 앨범컷 조회 API")
 public record PhotoBest4CutResponse(
+        @Schema(description = "사진 ID", example = "1")
+        Long photoId,
+
         @Schema(description = "썸네일 이미지 url", example = "https://cdn.say-cheese.me/...")
         String thumbnailUrl,
 
         @Schema(description = "좋아요 수", example = "1")
         int likeCnt,
 
         @Schema(description = "좋아요 여부", example = "true")
         boolean isLiked
 ) {
 }
src/main/java/com/cheeeese/photo/infrastructure/persistence/PhotoLikesRepository.java (1)

33-38: 쿼리에 정렬 기준 추가를 고려하세요.

현재 쿼리는 정렬 기준이 없어 좋아요를 누른 사용자들이 임의의 순서로 반환됩니다. 사용자 경험을 위해 명확한 정렬 기준(예: 좋아요 생성 시간순)을 추가하는 것을 권장합니다.

정렬 기준을 추가하려면:

     @Query("""
         SELECT pl.user
         FROM PhotoLikes pl
         WHERE pl.photo.id = :photoId
+        ORDER BY pl.createdAt DESC
     """)
     List<User> findLikersByPhotoId(@Param("photoId") Long photoId);

참고: 좋아요가 매우 많은 사진의 경우 페이지네이션이 필요할 수 있지만, 현재 요구사항에 맞다면 나중에 추가할 수 있습니다.

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

26-26: 불필요한 의존성

CurrentUserProvider가 주입되었지만 실제로는 메서드 매개변수인 user를 사용해야 합니다. Line 43에서 currentUserProvider.getCurrentUser()를 호출하는 대신 메서드 매개변수 user를 직접 사용하면 되므로, 이 의존성을 제거할 수 있습니다.

-    private final CurrentUserProvider currentUserProvider;
     private final PhotoRepository photoRepository;
📜 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 6d8468e and 449a664.

📒 Files selected for processing (25)
  • src/main/java/com/cheeeese/album/application/AlbumService.java (4 hunks)
  • src/main/java/com/cheeeese/album/application/validator/AlbumValidator.java (1 hunks)
  • src/main/java/com/cheeeese/album/dto/response/AlbumInfoResponse.java (1 hunks)
  • src/main/java/com/cheeeese/album/infrastructure/mapper/AlbumMapper.java (3 hunks)
  • src/main/java/com/cheeeese/album/presentation/AlbumController.java (1 hunks)
  • src/main/java/com/cheeeese/album/presentation/swagger/AlbumSwagger.java (1 hunks)
  • src/main/java/com/cheeeese/global/common/code/SuccessCode.java (2 hunks)
  • src/main/java/com/cheeeese/global/util/resolver/CdnUrlResolver.java (1 hunks)
  • src/main/java/com/cheeeese/photo/application/PhotoCallbackService.java (2 hunks)
  • src/main/java/com/cheeeese/photo/application/PhotoInfoService.java (1 hunks)
  • src/main/java/com/cheeeese/photo/application/PhotoQueryService.java (4 hunks)
  • src/main/java/com/cheeeese/photo/application/PhotoService.java (0 hunks)
  • src/main/java/com/cheeeese/photo/dto/response/PhotoBest4CutResponse.java (1 hunks)
  • src/main/java/com/cheeeese/photo/dto/response/PhotoDetailResponse.java (2 hunks)
  • src/main/java/com/cheeeese/photo/dto/response/PhotoLikedPageResponse.java (1 hunks)
  • src/main/java/com/cheeeese/photo/dto/response/PhotoLikedResponse.java (1 hunks)
  • src/main/java/com/cheeeese/photo/dto/response/PhotoLikedUserResponse.java (1 hunks)
  • src/main/java/com/cheeeese/photo/dto/response/PhotoListResponse.java (1 hunks)
  • src/main/java/com/cheeeese/photo/dto/response/PhotoPageResponse.java (1 hunks)
  • src/main/java/com/cheeeese/photo/infrastructure/mapper/PhotoMapper.java (4 hunks)
  • src/main/java/com/cheeeese/photo/infrastructure/persistence/PhotoLikesRepository.java (2 hunks)
  • src/main/java/com/cheeeese/photo/infrastructure/persistence/PhotoRepository.java (3 hunks)
  • src/main/java/com/cheeeese/photo/presentation/PhotoQueryController.java (3 hunks)
  • src/main/java/com/cheeeese/photo/presentation/swagger/PhotoQuerySwagger.java (3 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/application/PhotoService.java
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-11-05T03:06:41.855Z
Learnt from: zyovn
Repo: Say-Cheeeese/BE PR: 44
File: src/main/java/com/cheeeese/photo/infrastructure/persistence/PhotoHistoryRepository.java:36-36
Timestamp: 2025-11-05T03:06:41.855Z
Learning: PhotoHistoryRepository의 existsByUserIdAndPhotoIdAndCreatedAt 메서드는 정확한 타임스탬프 일치를 확인하는 시그니처로, "1시간 이내 다운로드" 체크에는 부적합합니다. Spring Data JPA에서는 existsByUserIdAndPhotoIdAndCreatedAtAfter를 사용하여 >= 비교를 수행해야 합니다.

Applied to files:

  • src/main/java/com/cheeeese/photo/dto/response/PhotoDetailResponse.java
📚 Learning: 2025-11-13T12:56:22.154Z
Learnt from: dahyun24
Repo: Say-Cheeeese/BE PR: 58
File: src/main/java/com/cheeeese/cheese4cut/application/Cheese4cutService.java:149-156
Timestamp: 2025-11-13T12:56:22.154Z
Learning: In src/main/java/com/cheeeese/cheese4cut/application/Cheese4cutService.java, the finalizeCheese4cut method intentionally re-sorts photos using findAllByIdInOrderByLikesDescCreatedDesc(request.photoIds()) instead of preserving the client's requested order. This is a defensive measure to ensure photos are always ordered by likes (DESC) and creation time (DESC), regardless of what order the client sends, preventing incorrect ordering from client errors.

Applied to files:

  • src/main/java/com/cheeeese/photo/presentation/PhotoQueryController.java
  • src/main/java/com/cheeeese/photo/application/PhotoInfoService.java
  • src/main/java/com/cheeeese/photo/application/PhotoCallbackService.java
  • src/main/java/com/cheeeese/photo/infrastructure/persistence/PhotoLikesRepository.java
  • src/main/java/com/cheeeese/photo/application/PhotoQueryService.java
  • src/main/java/com/cheeeese/photo/dto/response/PhotoBest4CutResponse.java
  • src/main/java/com/cheeeese/photo/presentation/swagger/PhotoQuerySwagger.java
  • src/main/java/com/cheeeese/album/infrastructure/mapper/AlbumMapper.java
  • src/main/java/com/cheeeese/photo/infrastructure/persistence/PhotoRepository.java
  • src/main/java/com/cheeeese/photo/dto/response/PhotoLikedResponse.java
  • src/main/java/com/cheeeese/photo/infrastructure/mapper/PhotoMapper.java
📚 Learning: 2025-10-31T13:17:52.523Z
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.523Z
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/presentation/PhotoQueryController.java
  • src/main/java/com/cheeeese/photo/application/PhotoInfoService.java
  • src/main/java/com/cheeeese/photo/application/PhotoCallbackService.java
  • src/main/java/com/cheeeese/photo/application/PhotoQueryService.java
  • src/main/java/com/cheeeese/photo/dto/response/PhotoBest4CutResponse.java
  • src/main/java/com/cheeeese/photo/presentation/swagger/PhotoQuerySwagger.java
  • src/main/java/com/cheeeese/album/infrastructure/mapper/AlbumMapper.java
  • src/main/java/com/cheeeese/photo/infrastructure/persistence/PhotoRepository.java
  • src/main/java/com/cheeeese/photo/infrastructure/mapper/PhotoMapper.java
🧬 Code graph analysis (3)
src/main/java/com/cheeeese/photo/application/PhotoInfoService.java (2)
src/main/java/com/cheeeese/photo/infrastructure/mapper/PhotoMapper.java (1)
  • PhotoMapper (15-183)
src/main/java/com/cheeeese/photo/application/PhotoQueryService.java (1)
  • Service (32-212)
src/main/java/com/cheeeese/photo/application/PhotoQueryService.java (2)
src/main/java/com/cheeeese/album/infrastructure/mapper/AlbumMapper.java (1)
  • AlbumMapper (14-156)
src/main/java/com/cheeeese/photo/infrastructure/mapper/PhotoMapper.java (1)
  • PhotoMapper (15-183)
src/main/java/com/cheeeese/album/application/AlbumService.java (1)
src/main/java/com/cheeeese/photo/infrastructure/mapper/PhotoMapper.java (1)
  • PhotoMapper (15-183)
🔇 Additional comments (32)
src/main/java/com/cheeeese/global/common/code/SuccessCode.java (1)

28-28: 새로운 성공 코드가 올바르게 추가되었습니다.

앨범 정보 조회, 띱한 사람 목록 조회, 베스트 4컷 조회를 위한 성공 코드가 일관된 패턴으로 정의되었습니다.

Also applies to: 40-41

src/main/java/com/cheeeese/photo/dto/response/PhotoPageResponse.java (1)

16-18: 문서 예제가 올바르게 업데이트되었습니다.

새로운 nameimageUrl 필드가 정확한 JSON 문법으로 추가되었습니다.

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

18-18: 캐시 무효화를 위한 의존성 추가가 적절합니다.

썸네일 업데이트 후 관련 캐시를 무효화하기 위해 PhotoQueryService를 주입하는 것은 올바른 접근입니다.

src/main/java/com/cheeeese/album/application/validator/AlbumValidator.java (1)

89-89: 메서드 가시성 변경이 적절합니다.

validateAlbumParticipant를 public으로 변경하여 다른 서비스에서 앨범 참여자 검증 로직을 재사용할 수 있게 되었습니다.

src/main/java/com/cheeeese/album/presentation/AlbumController.java (1)

73-83: 새로운 앨범 정보 조회 엔드포인트가 올바르게 구현되었습니다.

기존 패턴을 따르며, 인증 처리와 응답 구조가 적절합니다.

src/main/java/com/cheeeese/photo/dto/response/PhotoDetailResponse.java (2)

11-11: 필드 설명이 더 명확해졌습니다.

"사용자 이름"에서 "업로더 이름"으로 변경하여 필드의 의미를 더 정확하게 전달합니다.


35-39: 타임스탬프 필드가 적절하게 추가되었습니다.

captureTimecreatedAt 필드는 사진 메타데이터를 제공하며, Swagger 문서도 올바르게 작성되었습니다.

src/main/java/com/cheeeese/photo/dto/response/PhotoLikedResponse.java (1)

9-10: LGTM!

레코드에 nameimageUrl 필드를 추가한 것은 PR의 다른 변경사항들(PhotoListResponse, PhotoMapper 업데이트)과 일관성이 있으며, 사진 좋아요 응답을 더 풍부하게 만듭니다. @Builder 어노테이션 덕분에 필드 순서 변경에 따른 영향이 최소화됩니다.

Also applies to: 15-16

src/main/java/com/cheeeese/photo/dto/response/PhotoListResponse.java (1)

9-10: LGTM!

nameimageUrl 필드 추가는 PhotoLikedResponse와 일관된 패턴을 따르며, withUserStatus 메서드는 사용자별 상태만 변경하므로 새 필드에 영향을 받지 않습니다. 변경사항이 올바르게 구현되었습니다.

Also applies to: 15-16

src/main/java/com/cheeeese/album/application/AlbumService.java (3)

20-20: LGTM!

PhotoMapper import는 새로운 getAlbumInfo 메서드에서 toAlbumInfoResponse를 호출하기 위해 필요하며, 적절하게 추가되었습니다.


80-80: LGTM!

userRepository.incrementAlbumCnt 호출이 두 곳에서 올바르게 추가되었습니다:

  • Line 80: 앨범 생성 시 MAKER 역할로 참여하는 경우
  • Line 130: 기존 앨범에 GUEST로 신규 참여하는 경우

두 호출 모두 @Transactional 메서드 내에 있어 트랜잭션 롤백 시 카운트 증가도 함께 롤백되므로 데이터 일관성이 보장됩니다.

Also applies to: 130-130


184-190: LGTM!

getAlbumInfo 메서드 구현이 올바릅니다:

  • 앨범 코드 유효성 검증
  • 사용자 참여 권한 검증
  • 적절한 매퍼를 통한 응답 생성

클래스 레벨의 @Transactional(readOnly = true) 컨텍스트에서 실행되므로 읽기 전용 작업으로 적절하게 처리됩니다.

src/main/java/com/cheeeese/album/infrastructure/mapper/AlbumMapper.java (2)

37-37: 앨범당 최대 사진 수가 10배 증가했습니다.

maxPhotoCount가 10에서 100으로 증가했습니다. 이는 상당한 변경사항이므로 제품 요구사항 및 시스템 용량(저장소, 성능, UX)과 일치하는지 확인하시기 바랍니다.


149-155: LGTM!

새로운 베스트 4컷 응답 매퍼 메서드가 기존 패턴을 잘 따르고 있으며, 로직이 명확합니다.

src/main/java/com/cheeeese/photo/presentation/PhotoQueryController.java (3)

25-25: LGTM!

새로운 PhotoInfoService 의존성이 적절하게 주입되었습니다.


69-80: LGTM!

좋아요한 사용자 목록 조회 엔드포인트가 RESTful 규칙을 잘 따르고 있으며, 서비스 계층으로 적절히 위임하고 있습니다.


82-92: LGTM!

베스트 4컷 조회 엔드포인트가 RESTful 규칙을 잘 따르고 있으며, 서비스 계층으로 적절히 위임하고 있습니다.

src/main/java/com/cheeeese/photo/dto/response/PhotoLikedUserResponse.java (1)

1-58: LGTM!

DTO 구조가 명확하고 Swagger 문서화도 잘 되어 있습니다. Java record를 적절히 활용하고 있습니다.

src/main/java/com/cheeeese/photo/application/PhotoQueryService.java (3)

117-134: LGTM!

베스트 4컷 조회 로직이 명확합니다. 앨범 코드와 참여자 검증을 수행하고, COMPLETED 상태의 사진만 조회하며, 사용자별 좋아요 상태를 올바르게 포함하고 있습니다.


136-149: LGTM!

완료된(COMPLETED) 사진만 필터링하고, 원본 이미지 URL과 썸네일 URL을 모두 CDN을 통해 올바르게 해석하고 있습니다.


200-211: LGTM!

좋아요한 사진 응답 생성 시 원본 이미지 URL과 썸네일 URL을 모두 CDN을 통해 올바르게 해석하고 있습니다.

src/main/java/com/cheeeese/photo/infrastructure/persistence/PhotoRepository.java (5)

19-31: LGTM!

사진 상태(status)를 명시적으로 필터링하도록 메서드 시그니처를 개선했습니다. 이는 불완전한 사진이 반환되는 것을 방지합니다.


64-77: LGTM!

최근 사진 조회 쿼리가 개선되었습니다. isDeleted 확인이 추가되었고, ORDER BY가 DESC로 변경되어 최신 사진부터 반환합니다.


99-111: LGTM!

좋아요 수 기준 상위 사진 ID 조회 쿼리가 개선되었습니다. isDeleted와 status 필터가 추가되었고, 동일한 좋아요 수일 때 최신 사진을 우선하도록 정렬이 수정되었습니다.


113-125: LGTM!

상위 4개 사진의 전체 엔티티를 조회하는 새로운 메서드가 추가되었습니다. 좋아요 수와 생성일 기준으로 올바르게 정렬됩니다.


129-134: LGTM!

사진 ID로 앨범 코드를 조회하는 유틸리티 메서드가 추가되었습니다. 쿼리가 간단하고 명확합니다.

src/main/java/com/cheeeese/photo/infrastructure/mapper/PhotoMapper.java (5)

66-82: LGTM!

메서드 시그니처가 imageUrl 매개변수를 포함하도록 개선되었고, 사용자 이름 필드가 응답에 추가되었습니다. CDN 해석 로직과 일관성이 있습니다.


84-99: LGTM!

toPhotoListResponse와 일관되게 imageUrl 매개변수와 사용자 이름 필드가 추가되었습니다.


153-163: LGTM!

앨범 정보 응답 매핑 메서드가 명확하고 모든 필드를 적절히 매핑하고 있습니다.


165-172: LGTM!

좋아요한 사용자를 PhotoLiker로 매핑하는 로직이 명확합니다. isMe와 role 플래그를 적절히 처리합니다.


174-182: LGTM!

사진과 좋아요한 사용자 목록을 최종 응답으로 매핑하는 로직이 명확합니다.

src/main/java/com/cheeeese/album/dto/response/AlbumInfoResponse.java (1)

1-32: LGTM!

앨범 정보 응답 DTO가 명확하게 정의되어 있고 Swagger 문서화도 잘 되어 있습니다. Java record를 적절히 활용하고 있습니다.

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

♻️ Duplicate comments (4)
src/main/java/com/cheeeese/photo/application/PhotoCallbackService.java (1)

32-35: LGTM! Null 안전성이 확보되었습니다.

findAlbumCodeByPhotoId가 null을 반환할 수 있는 경우를 적절하게 처리하여, 이전 리뷰에서 제기된 null 안전성 문제가 해결되었습니다.

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

92-111: 에러 응답 문서화 추가를 권장합니다.

다른 엔드포인트들과의 일관성을 위해 가능한 에러 응답(403: 참여자 아님, 404: 존재하지 않는 앨범/사진)을 문서화하면 API 명세가 더욱 완전해집니다.

예시:

     @ApiResponses(value = {
             @ApiResponse(
                     responseCode = "200",
                     description = "띱한 사용자 목록 조회가 성공적으로 실행되었습니다."
+            ),
+            @ApiResponse(
+                    responseCode = "403",
+                    description = "참여자가 아닌 사용자의 경우"
+            ),
+            @ApiResponse(
+                    responseCode = "404",
+                    description = "존재하지 않는 앨범 또는 사진"
             )
     })
src/main/java/com/cheeeese/album/presentation/swagger/AlbumSwagger.java (2)

261-278: 에러 응답 문서화 추가를 권장합니다.

다른 엔드포인트들(예: getAlbumParticipants, getAvailableUploadCount)과의 일관성을 위해 가능한 에러 응답(403: 참여자 아님, 404: 존재하지 않는 앨범)을 문서화하면 API 명세가 더욱 완전해집니다.

예시:

     @ApiResponses(value = {
             @ApiResponse(
                     responseCode = "200",
                     description = "앨범 정보 조회가 성공적으로 실행되었습니다."
+            ),
+            @ApiResponse(
+                    responseCode = "403",
+                    description = "참여자가 아닌 사용자의 경우"
+            ),
+            @ApiResponse(
+                    responseCode = "404",
+                    description = "존재하지 않거나 유효하지 않은 앨범 코드"
             )
     })

280-297: 에러 응답 문서화 추가를 권장합니다.

베스트컷 조회 API도 동일하게 에러 응답(403: 참여자 아님, 404: 존재하지 않는 앨범)을 문서화하면 API 명세가 더욱 완전해집니다.

예시:

     @ApiResponses(value = {
             @ApiResponse(
                     responseCode = "200",
                     description = "앨범 내 베스트컷 조회가 성공적으로 실행되었습니다."
+            ),
+            @ApiResponse(
+                    responseCode = "403",
+                    description = "참여자가 아닌 사용자의 경우"
+            ),
+            @ApiResponse(
+                    responseCode = "404",
+                    description = "존재하지 않는 앨범"
             )
     })
🧹 Nitpick comments (2)
src/main/java/com/cheeeese/album/infrastructure/mapper/AlbumMapper.java (1)

7-7: 중복 import 정리를 권장합니다.

Line 5에서 이미 com.cheeeese.album.dto.response.*를 와일드카드로 import하고 있어, Line 7의 AlbumBest4CutResponse 개별 import는 중복입니다.

 import com.cheeeese.album.domain.Album;
 import com.cheeeese.album.domain.type.AlbumJoinStatus;
 import com.cheeeese.album.dto.response.*;
 import com.cheeeese.photo.domain.Photo;
-import com.cheeeese.album.dto.response.AlbumBest4CutResponse;
 import com.cheeeese.user.domain.User;
src/main/java/com/cheeeese/album/presentation/swagger/AlbumSwagger.java (1)

7-7: 중복 import 정리를 권장합니다.

Line 4에서 이미 com.cheeeese.album.dto.response.*를 와일드카드로 import하고 있어, Line 7의 AlbumBest4CutResponse 개별 import는 중복입니다.

 import com.cheeeese.album.dto.request.AlbumCreationRequest;
 import com.cheeeese.album.dto.response.*;
 import com.cheeeese.global.common.CommonResponse;
 import com.cheeeese.global.util.CurrentUser;
-import com.cheeeese.album.dto.response.AlbumBest4CutResponse;
 import com.cheeeese.user.domain.User;
📜 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 449a664 and 6971ce1.

📒 Files selected for processing (13)
  • src/main/java/com/cheeeese/album/application/AlbumService.java (5 hunks)
  • src/main/java/com/cheeeese/album/dto/response/AlbumBest4CutResponse.java (1 hunks)
  • src/main/java/com/cheeeese/album/infrastructure/mapper/AlbumMapper.java (3 hunks)
  • src/main/java/com/cheeeese/album/presentation/AlbumController.java (2 hunks)
  • src/main/java/com/cheeeese/album/presentation/swagger/AlbumSwagger.java (3 hunks)
  • src/main/java/com/cheeeese/global/common/code/SuccessCode.java (2 hunks)
  • src/main/java/com/cheeeese/photo/application/PhotoCallbackService.java (2 hunks)
  • src/main/java/com/cheeeese/photo/application/PhotoInfoService.java (1 hunks)
  • src/main/java/com/cheeeese/photo/application/PhotoQueryService.java (3 hunks)
  • src/main/java/com/cheeeese/photo/dto/response/PhotoLikedPageResponse.java (1 hunks)
  • src/main/java/com/cheeeese/photo/presentation/PhotoQueryController.java (3 hunks)
  • src/main/java/com/cheeeese/photo/presentation/swagger/PhotoQuerySwagger.java (2 hunks)
  • src/main/java/com/cheeeese/user/infrastructure/persistence/UserRepository.java (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/main/java/com/cheeeese/photo/dto/response/PhotoLikedPageResponse.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main/java/com/cheeeese/photo/application/PhotoInfoService.java
  • src/main/java/com/cheeeese/user/infrastructure/persistence/UserRepository.java
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-31T13:17:52.523Z
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.523Z
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/album/infrastructure/mapper/AlbumMapper.java
  • src/main/java/com/cheeeese/photo/presentation/swagger/PhotoQuerySwagger.java
  • src/main/java/com/cheeeese/photo/presentation/PhotoQueryController.java
  • src/main/java/com/cheeeese/photo/application/PhotoQueryService.java
  • src/main/java/com/cheeeese/album/application/AlbumService.java
  • src/main/java/com/cheeeese/photo/application/PhotoCallbackService.java
📚 Learning: 2025-11-13T12:56:22.154Z
Learnt from: dahyun24
Repo: Say-Cheeeese/BE PR: 58
File: src/main/java/com/cheeeese/cheese4cut/application/Cheese4cutService.java:149-156
Timestamp: 2025-11-13T12:56:22.154Z
Learning: In src/main/java/com/cheeeese/cheese4cut/application/Cheese4cutService.java, the finalizeCheese4cut method intentionally re-sorts photos using findAllByIdInOrderByLikesDescCreatedDesc(request.photoIds()) instead of preserving the client's requested order. This is a defensive measure to ensure photos are always ordered by likes (DESC) and creation time (DESC), regardless of what order the client sends, preventing incorrect ordering from client errors.

Applied to files:

  • src/main/java/com/cheeeese/album/infrastructure/mapper/AlbumMapper.java
  • src/main/java/com/cheeeese/photo/presentation/swagger/PhotoQuerySwagger.java
  • src/main/java/com/cheeeese/photo/presentation/PhotoQueryController.java
  • src/main/java/com/cheeeese/photo/application/PhotoQueryService.java
  • src/main/java/com/cheeeese/album/presentation/swagger/AlbumSwagger.java
  • src/main/java/com/cheeeese/album/application/AlbumService.java
  • src/main/java/com/cheeeese/photo/application/PhotoCallbackService.java
🧬 Code graph analysis (2)
src/main/java/com/cheeeese/photo/application/PhotoQueryService.java (1)
src/main/java/com/cheeeese/photo/infrastructure/mapper/PhotoMapper.java (1)
  • PhotoMapper (15-183)
src/main/java/com/cheeeese/album/application/AlbumService.java (2)
src/main/java/com/cheeeese/photo/infrastructure/mapper/PhotoMapper.java (1)
  • PhotoMapper (15-183)
src/main/java/com/cheeeese/album/infrastructure/mapper/AlbumMapper.java (1)
  • AlbumMapper (14-156)
🔇 Additional comments (11)
src/main/java/com/cheeeese/photo/application/PhotoQueryService.java (2)

114-124: LGTM! 상태 필터링과 CDN URL 처리가 적절합니다.

PhotoStatus.COMPLETED 상태만 조회하여 완료된 사진만 반환하고, CDN URL을 명시적으로 해결하는 로직이 올바르게 구현되었습니다. 사용자별 상태(isLiked, isDownloaded)는 이후 attachUserStatus에서 정확하게 업데이트됩니다.


176-187: LGTM! 일관된 CDN URL 처리 패턴입니다.

buildPhotoLikedResponses에서도 동일한 방식으로 CDN URL을 해결하여 일관성을 유지하고 있습니다.

src/main/java/com/cheeeese/album/infrastructure/mapper/AlbumMapper.java (2)

37-37: maxPhotoCount 변경 사항을 확인하세요.

maxPhotoCount가 10에서 100으로 10배 증가했습니다. 이 변경이 제품 요구사항과 일치하는지, 스토리지 및 성능 영향을 고려했는지 확인이 필요합니다.

이 변경이 의도된 것인지 확인해주세요. 앨범당 최대 사진 수 증가가 시스템에 미치는 영향(스토리지, 쿼리 성능, 캐싱 전략 등)을 검토했는지 확인하시기 바랍니다.


149-155: LGTM! 베스트 4컷 응답 매핑이 적절합니다.

toBest4CutResponse 메서드가 Photo 엔티티를 AlbumBest4CutResponse DTO로 깔끔하게 변환하고 있습니다.

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

66-77: LGTM! 엔드포인트 구현이 일관성 있게 작성되었습니다.

새로운 getPhotoLikedUsers 엔드포인트가 기존 패턴과 일관되게 구현되었으며, PhotoInfoService로의 위임이 적절합니다.

src/main/java/com/cheeeese/album/dto/response/AlbumBest4CutResponse.java (1)

1-18: LGTM! DTO 구조가 명확하고 적절합니다.

AlbumBest4CutResponse 레코드가 간결하게 정의되어 있으며, Swagger 문서화도 적절하게 포함되어 있습니다.

src/main/java/com/cheeeese/global/common/code/SuccessCode.java (2)

28-29: LGTM! 앨범 관련 성공 코드가 적절하게 추가되었습니다.

새로운 앨범 정보 및 베스트컷 조회 API를 위한 성공 코드가 일관된 네이밍 컨벤션으로 추가되었습니다.


41-41: LGTM! 사진 좋아요 사용자 조회 성공 코드가 적절합니다.

새로운 사진 좋아요 사용자 목록 조회 API를 위한 성공 코드가 적절하게 추가되었습니다.

src/main/java/com/cheeeese/album/application/AlbumService.java (2)

193-199: 앨범 정보 조회 로직 정상 작동

앨범 코드 검증과 참여자 검증 후 앨범 정보를 반환하는 로직이 올바르게 구현되었습니다.


89-89: 앨범 카운트 증가 로직 검증 완료 - 원자적 업데이트 확인됨

userRepository.incrementAlbumCnt()의 구현을 확인한 결과, 데이터베이스 레벨에서 원자적 업데이트가 올바르게 수행되고 있습니다.

  • @Modifying(clearAutomatically = true, flushAutomatically = true) 어노테이션으로 적절히 설정됨
  • SQL 쿼리: UPDATE User u SET u.albumCnt = u.albumCnt + 1 WHERE u.id = :userId
  • 동시성 문제 없음: 데이터베이스 레벨 원자성 보장
src/main/java/com/cheeeese/album/presentation/AlbumController.java (1)

76-98: 새로운 엔드포인트 구현 확인

앨범 정보 조회(/info)와 베스트 4컷 조회(/best-4cut) 엔드포인트가 표준 REST 패턴을 따라 올바르게 구현되었습니다. @CurrentUser를 통한 인증, 서비스 레이어로의 위임, 적절한 성공 코드 반환이 모두 정상적으로 처리되고 있습니다.

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/album/application/AlbumService.java (1)

194-200: 앨범 정보 조회 로직이 올바르게 구현되었습니다.

앨범 코드 및 참여자 검증 후 정보를 반환하는 로직이 정확합니다. 다만 구조적 관점에서 AlbumInfoResponsePhotoMapper가 아닌 AlbumMapper에서 생성하는 것이 더 자연스러울 수 있습니다 (앨범 관련 응답은 앨범 매퍼에서 처리).

필요 시 다음과 같이 리팩토링을 고려할 수 있습니다:

-        return PhotoMapper.toAlbumInfoResponse(album);
+        return AlbumMapper.toAlbumInfoResponse(album);

그리고 AlbumMapper에 해당 메서드를 이동:

// AlbumMapper.java에 추가
public static AlbumInfoResponse toAlbumInfoResponse(Album album) {
    return AlbumInfoResponse.builder()
            .title(album.getTitle())
            .makerId(album.getMakerId())
            .themeEmoji(album.getThemeEmoji())
            .participant(album.getParticipant())
            .currentParticipant(album.getCurrentParticipant())
            .eventDate(album.getEventDate())
            .currentPhotoCnt(album.getCurrentPhotoCount())
            .build();
}
📜 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 6971ce1 and 6e4d3eb.

📒 Files selected for processing (1)
  • src/main/java/com/cheeeese/album/application/AlbumService.java (6 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-11-13T12:56:22.154Z
Learnt from: dahyun24
Repo: Say-Cheeeese/BE PR: 58
File: src/main/java/com/cheeeese/cheese4cut/application/Cheese4cutService.java:149-156
Timestamp: 2025-11-13T12:56:22.154Z
Learning: In src/main/java/com/cheeeese/cheese4cut/application/Cheese4cutService.java, the finalizeCheese4cut method intentionally re-sorts photos using findAllByIdInOrderByLikesDescCreatedDesc(request.photoIds()) instead of preserving the client's requested order. This is a defensive measure to ensure photos are always ordered by likes (DESC) and creation time (DESC), regardless of what order the client sends, preventing incorrect ordering from client errors.

Applied to files:

  • src/main/java/com/cheeeese/album/application/AlbumService.java
📚 Learning: 2025-10-31T13:17:52.523Z
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.523Z
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/album/application/AlbumService.java
📚 Learning: 2025-11-05T03:06:41.855Z
Learnt from: zyovn
Repo: Say-Cheeeese/BE PR: 44
File: src/main/java/com/cheeeese/photo/infrastructure/persistence/PhotoHistoryRepository.java:36-36
Timestamp: 2025-11-05T03:06:41.855Z
Learning: PhotoHistoryRepository의 existsByUserIdAndPhotoIdAndCreatedAt 메서드는 정확한 타임스탬프 일치를 확인하는 시그니처로, "1시간 이내 다운로드" 체크에는 부적합합니다. Spring Data JPA에서는 existsByUserIdAndPhotoIdAndCreatedAtAfter를 사용하여 >= 비교를 수행해야 합니다.

Applied to files:

  • src/main/java/com/cheeeese/album/application/AlbumService.java
🧬 Code graph analysis (1)
src/main/java/com/cheeeese/album/application/AlbumService.java (2)
src/main/java/com/cheeeese/photo/infrastructure/mapper/PhotoMapper.java (1)
  • PhotoMapper (15-183)
src/main/java/com/cheeeese/album/infrastructure/mapper/AlbumMapper.java (1)
  • AlbumMapper (14-156)
🔇 Additional comments (3)
src/main/java/com/cheeeese/album/application/AlbumService.java (3)

16-25: LGTM! 새로운 의존성 추가가 적절합니다.

베스트 4컷 및 앨범 정보 조회 기능 구현을 위한 의존성들이 모두 적절하게 추가되었습니다:

  • CdnUrlResolver: 썸네일 URL 변환
  • PhotoRepository, PhotoLikesRepository: 사진 및 좋아요 데이터 조회
  • PhotoMapper: 응답 DTO 매핑
  • PageRequest, Set: 페이징 및 컬렉션 처리

Also applies to: 33-33, 46-46, 59-60, 63-63


90-90: LGTM! 앨범 카운트 증가 로직이 올바르게 구현되었습니다.

앨범 생성 및 신규 참여 시 user.albumCnt를 증가시키는 로직이 PR 목표에 명시된 대로 정확하게 구현되었습니다. 재참여(REJOINED) 케이스에서 카운트를 증가시키지 않는 것도 의도된 동작으로 적절합니다.

Also applies to: 140-140


202-226: LGTM! N+1 쿼리 문제가 해결되었습니다.

베스트 4컷 조회 로직이 올바르게 구현되었으며, 이전 리뷰에서 지적된 N+1 쿼리 문제가 Line 217의 배치 조회(findAllLikedPhotoIds)를 통해 완벽하게 해결되었습니다.

주요 개선 사항:

  • 사진 ID를 먼저 수집 (Lines 213-215)
  • 한 번의 쿼리로 모든 좋아요 정보 조회 (Line 217)
  • Set을 사용한 효율적인 멤버십 체크 (Line 222)

Copy link
Contributor

@dahyun24 dahyun24 left a comment

Choose a reason for hiding this comment

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

LGTM

작은 수정 사항들이 계속 생기네ㅜㅜ 끝까지 파이팅이ㅕ~~

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/photo/infrastructure/persistence/PhotoRepository.java (1)

107-125: 중복 메서드 제거 권장

findTop4CompletedPhotoIdsByLikes(ID 반환)와 findTop4CompletedPhotosByLikes(엔티티 반환) 두 메서드가 거의 동일한 쿼리를 수행합니다. AlbumService는 엔티티 버전만 사용하므로, ID 버전은 불필요해 보입니다.

다음 스크립트로 ID 반환 메서드의 사용처를 확인한 후, 사용되지 않는다면 제거를 고려하세요:

#!/bin/bash
# Description: findTop4CompletedPhotoIdsByLikes 메서드 사용처 확인

rg -nP '\bfindTop4CompletedPhotoIdsByLikes\s*\(' --type=java -C3

사용되지 않는다면 다음 diff를 적용하여 중복 메서드를 제거하세요:

-    @Query("""
-        SELECT p.id
-        FROM Photo p
-        WHERE p.album.id = :albumId
-        AND p.isDeleted = FALSE
-        AND p.status = :status
-        ORDER BY p.likesCnt DESC, p.createdAt DESC
-    """)
-    List<Long> findTop4CompletedPhotoIdsByLikes(
-            @Param("albumId") Long albumId,
-            @Param("status") PhotoStatus status,
-            Pageable pageable
-    );
-
📜 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 6e4d3eb and a5bbb7b.

📒 Files selected for processing (2)
  • src/main/java/com/cheeeese/album/application/AlbumService.java (6 hunks)
  • src/main/java/com/cheeeese/photo/infrastructure/persistence/PhotoRepository.java (4 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-11-13T12:56:22.154Z
Learnt from: dahyun24
Repo: Say-Cheeeese/BE PR: 58
File: src/main/java/com/cheeeese/cheese4cut/application/Cheese4cutService.java:149-156
Timestamp: 2025-11-13T12:56:22.154Z
Learning: In src/main/java/com/cheeeese/cheese4cut/application/Cheese4cutService.java, the finalizeCheese4cut method intentionally re-sorts photos using findAllByIdInOrderByLikesDescCreatedDesc(request.photoIds()) instead of preserving the client's requested order. This is a defensive measure to ensure photos are always ordered by likes (DESC) and creation time (DESC), regardless of what order the client sends, preventing incorrect ordering from client errors.

Applied to files:

  • src/main/java/com/cheeeese/photo/infrastructure/persistence/PhotoRepository.java
  • src/main/java/com/cheeeese/album/application/AlbumService.java
📚 Learning: 2025-10-31T13:17:52.523Z
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.523Z
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/infrastructure/persistence/PhotoRepository.java
  • src/main/java/com/cheeeese/album/application/AlbumService.java
📚 Learning: 2025-11-05T03:06:41.855Z
Learnt from: zyovn
Repo: Say-Cheeeese/BE PR: 44
File: src/main/java/com/cheeeese/photo/infrastructure/persistence/PhotoHistoryRepository.java:36-36
Timestamp: 2025-11-05T03:06:41.855Z
Learning: PhotoHistoryRepository의 existsByUserIdAndPhotoIdAndCreatedAt 메서드는 정확한 타임스탬프 일치를 확인하는 시그니처로, "1시간 이내 다운로드" 체크에는 부적합합니다. Spring Data JPA에서는 existsByUserIdAndPhotoIdAndCreatedAtAfter를 사용하여 >= 비교를 수행해야 합니다.

Applied to files:

  • src/main/java/com/cheeeese/album/application/AlbumService.java
🧬 Code graph analysis (1)
src/main/java/com/cheeeese/album/application/AlbumService.java (2)
src/main/java/com/cheeeese/photo/infrastructure/mapper/PhotoMapper.java (1)
  • PhotoMapper (15-183)
src/main/java/com/cheeeese/album/infrastructure/mapper/AlbumMapper.java (1)
  • AlbumMapper (14-156)
🔇 Additional comments (6)
src/main/java/com/cheeeese/photo/infrastructure/persistence/PhotoRepository.java (2)

138-143: LGTM!

findAlbumCodeByPhotoId 메서드는 간단하고 명확하게 구현되었습니다.


27-31: 검증 완료: 메서드 시그니처 변경으로 인한 미해결 호출 없음

호출 지점 검증 결과, findAllByAlbumCodeAndStatus 메서드는 PhotoQueryService.java의 114줄에서 올바른 시그니처로 호출되고 있으며, 이전 메서드명에 대한 미업데이트된 호출은 발견되지 않았습니다. 모든 호출 지점이 새로운 시그니처에 맞게 업데이트되어 있습니다.

src/main/java/com/cheeeese/album/application/AlbumService.java (4)

92-92: LGTM!

앨범 생성 시 사용자의 앨범 카운트를 증가시키는 로직이 적절히 구현되었습니다.


142-142: LGTM!

신규 참여 시 사용자의 앨범 카운트를 증가시키는 로직이 적절히 구현되었습니다.


196-202: LGTM!

앨범 정보 조회 메서드가 명확하게 구현되었습니다. 앨범 코드 검증과 참여자 확인이 적절히 수행됩니다.


204-228: N+1 쿼리 문제 해결 확인!

이전 리뷰에서 지적된 N+1 쿼리 문제가 올바르게 해결되었습니다:

  • Line 215-217: 모든 사진 ID를 먼저 추출
  • Line 219: 한 번의 배치 쿼리로 좋아요한 사진 ID들을 조회 (findAllLikedPhotoIds)
  • Line 224: Set 멤버십 체크로 각 사진의 좋아요 여부 확인

이제 4개의 사진에 대해 총 2개의 쿼리(1개 사진 조회 + 1개 좋아요 배치 조회)만 실행되어 성능이 크게 개선되었습니다.

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/cheese4cut/presentation/Cheese4cutController.java (1)

18-18: 명시적 static import 사용을 고려하세요.

와일드카드 static import는 코드를 간결하게 만들지만, 상수의 출처를 파악하기 어렵게 만들고 네이밍 충돌 가능성을 높일 수 있습니다. 명시적으로 필요한 상수만 import하는 것이 코드의 가독성과 유지보수성 측면에서 더 나을 수 있습니다.

예시:

-import static com.cheeeese.global.common.code.SuccessCode.*;
+import static com.cheeeese.global.common.code.SuccessCode.CHEESE4CUT_GET_SUCCESS;
+import static com.cheeeese.global.common.code.SuccessCode.PRESIGNED_URL_ISSUE_SUCCESS;
+import static com.cheeeese.global.common.code.SuccessCode.CHEESE4CUT_FINALIZE_SUCCESS;
📜 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 a5bbb7b and 44255e6.

📒 Files selected for processing (1)
  • src/main/java/com/cheeeese/cheese4cut/presentation/Cheese4cutController.java (2 hunks)
🔇 Additional comments (1)
src/main/java/com/cheeeese/cheese4cut/presentation/Cheese4cutController.java (1)

34-35: LGTM!

static import 스타일 변경에 맞춰 일관되게 수정되었습니다.

@zyovn zyovn merged commit f1140e8 into develop Nov 14, 2025
1 check passed
@zyovn zyovn deleted the feat/#54-get-etc branch November 14, 2025 15:01
@coderabbitai coderabbitai bot mentioned this pull request Jan 21, 2026
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: 앨범 및 사진 조회 관련 API

3 participants