Skip to content

Conversation

@sweatbuckets
Copy link
Contributor

@sweatbuckets sweatbuckets commented Dec 31, 2025

  1. #⃣ 연관된 이슈
    • 관련 이슈를 명시해주세요.
    • 예: #이슈번호#이슈번호
  2. 📝 작업 내용
    • deleteShow 관련 이미지 id로 뽑아서 한번에 삭제하도록 -> 성능 개선
    • 댓글작성자가 아닌 게시글 작성자에게 알림가도록 수정
    • 핫한 공연 totalSoldTicket 순서로 3개 뽑아오기
    • 컨버터에서 npe 처리
  3. 📸 스크린샷 (선택)
    • 작업 내용을 시각적으로 표현할 스크린샷을 포함하세요.
  4. 💬 리뷰 요구사항 (선택)
    • 리뷰어가 특히 검토해주었으면 하는 부분이 있다면 작성해주세요.
    • 예: "메서드 XXX의 이름을 더 명확히 하고 싶은데, 좋은 아이디어가 있으신가요?"

Summary by CodeRabbit

  • New Features

    • Incoming shows endpoint now returns a "recently hot" list limited to the top 3 trending shows.
  • Bug Fixes

    • Comment notifications now route to the board author instead of the commenter.
    • Image cleanup during show deletion now removes related files in batch.
    • Safer handling of optional images to prevent null-related errors.
  • Database

    • Casting entries now require a non-null parent show reference.

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

@coderabbitai
Copy link

coderabbitai bot commented Dec 31, 2025

📝 Walkthrough

Walkthrough

Replaced getIncomingShow with getRecentlyHotShow (returns top-3 hot shows via new repository query); switched casting-image deletion to a batch lookup/delete; added ImageRepository batch finder; made converter null-safe; set AmateurCasting.amateurShow FK non-nullable; changed notifyNewComment recipient to board writer.

Changes

Cohort / File(s) Summary
Amateur show service & API
src/main/java/cc/backend/amateurShow/service/amateurShowService/AmateurServiceImpl.java, src/main/java/cc/backend/amateurShow/service/amateurShowService/AmateurService.java, src/main/java/cc/backend/amateurShow/controller/AmateurController.java
Replaced public API getIncomingShow(Long) with getRecentlyHotShow(Long); controller now calls getRecentlyHotShow; service queries findHotShows(today, PageRequest.of(0,3)) and maps top-3 to DTOs.
Repository additions
src/main/java/cc/backend/amateurShow/repository/AmateurShowRepository.java, src/main/java/cc/backend/image/repository/ImageRepository.java
Added findHotShows(LocalDate today, Pageable pageable) (JPQL: end >= :today ordered by totalSoldTicket DESC, start ASC) and findByFilePathAndContentIdIn(FilePath, List<Long>) for batch image lookup.
Image deletion flow
src/main/java/cc/backend/amateurShow/service/amateurShowService/AmateurServiceImpl.java
deleteShow refactored to batch-fetch images via findByFilePathAndContentIdIn and delete them in one pass instead of per-casting lookups.
Converters — null-safety
src/main/java/cc/backend/amateurShow/converter/AmateurConverter.java
Added null checks and local extraction for casting/notice imageUrl and keyName; replaced some stream terminals with List.toList().
Entity constraint
src/main/java/cc/backend/amateurShow/entity/AmateurCasting.java
Marked @JoinColumn(..., nullable = false) on the amateurShow relationship (non-null FK).
Notice routing change
src/main/java/cc/backend/notice/service/NoticeServiceImpl.java
notifyNewComment now creates a MemberNotice addressed to the board writer instead of the comment writer.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant Controller as AmateurController
  participant Service as AmateurServiceImpl
  participant Repo as AmateurShowRepository

  Client->>Controller: GET /incoming (memberId)
  Controller->>Service: getRecentlyHotShow(memberId)
  Service->>Repo: findHotShows(today, PageRequest.of(0,3))
  Repo-->>Service: List<AmateurShow> (ordered by totalSoldTicket desc, start asc)
  Service->>Service: map to AmateurShowList DTOs (limit 3)
  Service-->>Controller: List<AmateurShowList>
  Controller-->>Client: 200 OK (DTO list)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hop and fetch the top three shows with glee,
One pull for images, tidy as can be.
Null-safe converters keep surprises far,
FK now strict — a steadfast star.
I drum a carrot beat for notices to tree.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title check ⚠️ Warning The title focuses on fixing a notification bug for comment writers, but the PR also includes multiple other changes unrelated to this primary fix: performance improvements in deleteShow, changing the notification recipient, retrieving hot shows by sales, and NPE handling in converters. Revise the title to reflect the main change or use a more comprehensive title that encompasses the multiple improvements included in this PR, such as '[FIX] 댓글 알림 오류 및 성능 개선' or '[REFACTOR] 공연 조회 및 알림 처리 개선'
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description includes the required sections with work content details (deleteShow optimization, notification recipient fix, hot show retrieval, NPE handling), but the related issues section is incomplete (missing actual issue numbers) and lacks implementation details.

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 13ccdcf and ff5f43f.

📒 Files selected for processing (1)
  • src/main/java/cc/backend/amateurShow/converter/AmateurConverter.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/cc/backend/amateurShow/converter/AmateurConverter.java

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

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4647810 and bcdfc4c.

📒 Files selected for processing (2)
  • src/main/java/cc/backend/amateurShow/service/amateurShowService/AmateurServiceImpl.java
  • src/main/java/cc/backend/notice/service/NoticeServiceImpl.java
🔇 Additional comments (1)
src/main/java/cc/backend/notice/service/NoticeServiceImpl.java (1)

79-115: Fix correctly routes comment notifications to board author.

The change to .member(boardWriter) is correct—the board author receives notifications when comments are posted. The self-notification guard (lines 89-91) properly prevents duplicate notifications when authors comment on their own posts. Event integration is properly wired: CommentService publishes the event, CommentEventListener receives it via @eventlistener, and passes it to notifyNewComment().

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/cc/backend/amateurShow/converter/AmateurConverter.java (1)

158-166: Potential NPE in toSingleCasting.

Line 163 calls dto.getCastingImageRequestDTO().getImageUrl() without checking if getCastingImageRequestDTO() returns null. This is inconsistent with the null-safe approach used in toAmateurCastingEntity (lines 58-76).

🔎 Proposed fix
 public static AmateurCasting toSingleCasting(AmateurUpdateRequestDTO.UpdateCasting dto, AmateurShow show) {
+    String imageUrl = null;
+    if (dto.getCastingImageRequestDTO() != null) {
+        imageUrl = dto.getCastingImageRequestDTO().getImageUrl();
+    }
+
     return AmateurCasting.builder()
             .amateurShow(show)
             .actorName(dto.getActorName())
             .castingName(dto.getCastingName())
-            .castingImageUrl(dto.getCastingImageRequestDTO().getImageUrl() != null ?
-                    dto.getCastingImageRequestDTO().getImageUrl() : null)
+            .castingImageUrl(imageUrl)
             .build();
 }
♻️ Duplicate comments (1)
src/main/java/cc/backend/amateurShow/service/amateurShowService/AmateurServiceImpl.java (1)

632-655: Extract hardcoded page size to a named constant.

The PageRequest.of(0, 3) hardcodes the limit of 3 hot shows. Extract this to a named constant (e.g., RECENTLY_HOT_SHOW_LIMIT = 3) for better maintainability and clarity.

🔎 Proposed refactor

Add a constant at the class level:

private static final int RECENTLY_HOT_SHOW_LIMIT = 3;

Then use it:

-List<AmateurShow> shows = amateurShowRepository.findHotShows(today, PageRequest.of(0, 3));
+List<AmateurShow> shows = amateurShowRepository.findHotShows(today, PageRequest.of(0, RECENTLY_HOT_SHOW_LIMIT));

Based on learnings, a previous review flagged a similar hardcoded limit issue.

🧹 Nitpick comments (1)
src/main/java/cc/backend/amateurShow/entity/AmateurCasting.java (1)

31-31: Standardize nullable constraints on amateur_show_id foreign keys for data consistency.

AmateurCasting enforces nullable = false on the amateur_show_id foreign key, while related entities (AmateurStaff, AmateurTicket, AmateurNotice, AmateurRounds, PhotoAlbum) do not explicitly specify this constraint, defaulting to nullable. Either apply nullable = false consistently across all related entities if all amateur_show_id relationships should be mandatory, or add a comment explaining why certain entities allow nullable values.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bcdfc4c and 4a89847.

📒 Files selected for processing (7)
  • src/main/java/cc/backend/amateurShow/controller/AmateurController.java
  • src/main/java/cc/backend/amateurShow/converter/AmateurConverter.java
  • src/main/java/cc/backend/amateurShow/entity/AmateurCasting.java
  • src/main/java/cc/backend/amateurShow/repository/AmateurShowRepository.java
  • src/main/java/cc/backend/amateurShow/service/amateurShowService/AmateurService.java
  • src/main/java/cc/backend/amateurShow/service/amateurShowService/AmateurServiceImpl.java
  • src/main/java/cc/backend/image/repository/ImageRepository.java
🧰 Additional context used
🧬 Code graph analysis (3)
src/main/java/cc/backend/image/repository/ImageRepository.java (1)
src/main/java/cc/backend/image/entity/Image.java (1)
  • Entity (16-62)
src/main/java/cc/backend/amateurShow/converter/AmateurConverter.java (2)
src/main/java/cc/backend/amateurShow/entity/AmateurNotice.java (2)
  • Entity (11-41)
  • update (33-40)
src/main/java/cc/backend/amateurShow/dto/AmateurUpdateRequestDTO.java (2)
  • Getter (12-85)
  • Getter (57-65)
src/main/java/cc/backend/amateurShow/entity/AmateurCasting.java (4)
src/main/java/cc/backend/amateurShow/entity/AmateurStaff.java (1)
  • Entity (10-32)
src/main/java/cc/backend/amateurShow/entity/AmateurNotice.java (1)
  • Entity (11-41)
src/main/java/cc/backend/amateurShow/entity/AmateurRounds.java (1)
  • Entity (12-50)
src/main/java/cc/backend/amateurShow/entity/AmateurTicket.java (1)
  • Entity (15-41)
🔇 Additional comments (7)
src/main/java/cc/backend/image/repository/ImageRepository.java (1)

28-31: LGTM!

The new batch query method is well-designed and leverages the existing composite index idx_file_content on (file_path, content_id) for efficient retrieval.

src/main/java/cc/backend/amateurShow/converter/AmateurConverter.java (3)

58-76: LGTM: Improved null-safety.

The refactored null-safe extraction of image data is a good improvement, preventing potential NPEs when castingImageRequestDTO is null.


79-94: LGTM: Added null checks.

The null checks prevent issues when notice or content is null, improving robustness.


98-113: LGTM: Consistent null-safety.

The null-safety pattern is consistent with the first overload.

src/main/java/cc/backend/amateurShow/service/amateurShowService/AmateurServiceImpl.java (3)

426-438: LGTM: Batch deletion improves performance.

The refactored batch deletion using findByFilePathAndContentIdIn eliminates the N+1 query problem and is more efficient than the previous approach.


1-41: No unintended Swing imports found. Verification confirms that the file contains no javax.swing.* or java.awt.* imports. The AI summary's mention of an "added unintended Swing import" does not reflect the actual code state.


632-655: The original review comment's premise is incorrect.

The actual commit message is "fix: enrollShow casting, notice npe처리" (enrollShow casting and notice NPE handling), not "댓글 작성자에게 알림이 가는 오류 해결" as claimed. Both AmateurServiceImpl.java and CommentEventListener.java are new files added in the same commit (4a89847), so the AmateurServiceImpl changes are legitimately part of the same PR scope rather than inconsistent with the PR's objectives.

Likely an incorrect or invalid review comment.

Comment on lines 92 to 96
@GetMapping("/incoming")
@Operation(summary = "공연 임박인 공연 조회 API")
public ApiResponse<List<AmateurShowResponseDTO.AmateurShowList>> getShowIncoming(@AuthenticationPrincipal(expression = "member") Member member) {
return ApiResponse.onSuccess(amateurService.getIncomingShow(member.getId()));
return ApiResponse.onSuccess(amateurService.getRecentlyHotShow(member.getId()));
}
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

Semantic mismatch between endpoint and implementation.

The endpoint /incoming with operation summary "공연 임박인 공연 조회 API" (retrieve upcoming shows) now calls getRecentlyHotShow(), which returns shows sorted by sales (hot shows), not by temporal proximity (incoming shows). This creates a confusing API contract.

Consider either:

  • Renaming the endpoint to /hot or /popular and updating the operation summary to reflect sales-based ranking
  • Or reverting the implementation to match the "incoming" semantic intent
🤖 Prompt for AI Agents
In src/main/java/cc/backend/amateurShow/controller/AmateurController.java around
lines 92-96, the /incoming endpoint and its Operation summary indicate "upcoming
shows" but the method calls amateurService.getRecentlyHotShow()
(sales/popularity-based), causing a semantic mismatch; fix by either (A)
renaming the endpoint and summary to reflect popularity (e.g.,
@GetMapping("/hot") and update Operation summary to "인기 공연 조회 API" or similar)
and keep calling getRecentlyHotShow(), or (B) change the service call to the
correct temporal-based method (e.g.,
amateurService.getIncomingShows(member.getId())) and ensure the Operation
summary remains "공연 임박인 공연 조회 API"; apply consistent naming to method, mapping,
and javadoc/annotations accordingly.

Comment on lines +69 to +78
@Query("""
SELECT a
FROM AmateurShow a
WHERE a.end >= :today
ORDER BY a.totalSoldTicket DESC, a.start ASC
""")
List<AmateurShow> findHotShows(
@Param("today") LocalDate today,
Pageable pageable
);
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if totalSoldTicket field allows null and get its declaration
rg -nP 'private\s+(Integer|Long)\s+totalSoldTicket' --type=java -A2 -B2

# Check for @Index annotations on AmateurShow entity
rg -n '@Index|@Table\(' src/main/java/cc/backend/amateurShow/entity/AmateurShow.java -A5

# Also check the full AmateurShow entity file for context
echo "=== Full AmateurShow entity file ==="
find . -path "*/amateurShow/entity/AmateurShow.java" -type f | head -1 | xargs cat

Repository: SeeATheater/CC_Backend

Length of output: 6042


Add COALESCE to ORDER BY clause and create a database index for the query.

The totalSoldTicket field is nullable (Integer type with no NOT NULL constraint), but the query orders by it without explicit null handling. SQL databases sort nulls first or last (not as 0), which differs from the entity's business logic that treats null as zero in increaseSoldTicket() and decreaseSoldTicket(). Update the query to ORDER BY COALESCE(a.totalSoldTicket, 0) DESC, a.start ASC to match the expected behavior.

Additionally, create a database index on totalSoldTicket (or a composite index on totalSoldTicket, start) to optimize the ordering and filtering performance.

🤖 Prompt for AI Agents
In src/main/java/cc/backend/amateurShow/repository/AmateurShowRepository.java
around lines 69 to 78, the ORDER BY uses a.totalSoldTicket which is nullable and
should be treated as 0; change the JPQL to ORDER BY COALESCE(a.totalSoldTicket,
0) DESC, a.start ASC so nulls are treated as zero; additionally add a database
migration to create an index to optimize this query (either a single-column
index on total_sold_ticket or a composite index on (total_sold_ticket, start)
depending on your DB naming conventions) and ensure the migration is included in
your migrations folder and tested.

@sweatbuckets sweatbuckets merged commit e8ffa83 into develop Dec 31, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants