Skip to content

Feature/redis booth reservation - #45

Closed
suho-98 wants to merge 8 commits into
devfrom
feature/redis-booth-reservation
Closed

suho-98 wants to merge 8 commits into
devfrom
feature/redis-booth-reservation

Conversation

@suho-98

@suho-98 suho-98 commented Aug 9, 2026 •

Copy link
Copy Markdown
Collaborator

📄 작업 내용

무엇을, 왜 변경했는지 설명해주세요.

🔗 관련 이슈

Closes #

☑️ 체크리스트

  • 로컬에서 정상 동작 확인
  • 테스트 작성 및 통과
  • 불필요한 로그/주석/커밋 정리

📸 스크린샷 (UI 변경 시)

💬 리뷰어에게

Summary by CodeRabbit

  • 새로운 기능
    • 행사별 모바일 안내에서 부스 검색, 상세 정보, 평점·관심 여부·예약 가능 여부를 확인할 수 있습니다.
    • 부스 예약 시 좌석을 임시 선점해 중복 예약을 방지합니다.
    • 교환 코드로 부스 체크인할 수 있습니다.
    • 부스 후기를 작성하고 평균 평점, 후기 목록, 키워드 검색을 이용할 수 있습니다.
    • 실시간 혼잡도 기반 부스 추천과 지도 혼잡도 정보를 제공합니다.
    • 예약 취소 후 빈자리 알림을 받을 수 있습니다.

suho-98 added 3 commits August 8, 2026 21:18
…eature/booth-reservation

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
# Conflicts:
#	BE/src/main/java/com/min/edu/booth/repository/BoothRepository.java
@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

부스 예약에 Redis 슬롯 선점을 적용하고 체크인, 후기, 모바일 안내, 추천 부스, 지도 혼잡도 API를 추가했다. QR 스캔 저장소와 빈자리 알림 처리도 확장했다.

Changes

부스 예약 및 체크인

Layer / File(s) Summary
Redis 예약 선점과 빈자리 알림
BE/src/main/java/com/min/edu/booth/controller/BoothReservationController.java, BE/src/main/java/com/min/edu/booth/service/*Reservation*.java, BE/src/main/java/com/min/edu/booth/service/RedisReservationService.java, BE/src/main/java/com/min/edu/booth/event/*, BE/src/main/java/com/min/edu/interest/*
예약 생성 전에 Redis 슬롯을 5분 동안 선점한다. 예약 취소 후 커밋 이벤트로 빈자리 알림을 생성한다.
체크인 검증과 QR 스캔 기록
BE/src/main/java/com/min/edu/booth/controller/BoothCheckInController.java, BE/src/main/java/com/min/edu/booth/service/BoothCheckInService.java, BE/src/main/java/com/min/edu/booth/repository/BoothReservationRepository.java, BE/src/main/java/com/min/edu/booth/repository/BoothQrScanRepository.java, BE/src/main/java/com/min/edu/booth/dto/BoothCheckInRequest.java
교환 코드와 예약의 소유권, 행사, 상태, 만료 여부를 검증한다. 체크인 상태와 QR 스캔 기록을 갱신한다.

후기 기능

Layer / File(s) Summary
부스 후기 API와 평점 조회
BE/src/main/java/com/min/edu/booth/controller/BoothReviewController.java, BE/src/main/java/com/min/edu/booth/service/BoothReviewService.java, BE/src/main/java/com/min/edu/booth/repository/BoothReviewRepository.java, BE/src/main/java/com/min/edu/booth/domain/BoothReview.java, BE/src/main/java/com/min/edu/booth/dto/*Review*.java, BE/src/main/java/com/min/edu/booth/dto/BoothAverageRatingResponse.java, BE/src/main/resources/db/migration/V14__Add_updated_at_to_booth_reviews.sql
후기 생성, 평균 평점 조회, 부스별·회원별 목록 조회, 검색, 수정, 삭제를 제공한다. 평점과 댓글 수정 시각을 저장한다.

모바일 안내 및 혼잡도

Layer / File(s) Summary
모바일 안내 조회
BE/src/main/java/com/min/edu/booth/controller/MobileGuideController.java, BE/src/main/java/com/min/edu/booth/service/MobileGuideService.java, BE/src/main/java/com/min/edu/booth/repository/BoothRepository.java, BE/src/main/java/com/min/edu/booth/repository/BoothReviewRepository.java, BE/src/main/java/com/min/edu/booth/repository/BoothInterestRepository.java, BE/src/main/java/com/min/edu/booth/repository/BoothReservationSlotRepository.java, BE/src/main/java/com/min/edu/booth/dto/MobileGuide*.java
이벤트 안내 메인, 키워드 기반 부스 검색, 부스 상세 조회를 제공한다. 응답에 평점, 리뷰 수, 관심 여부, 예약 가능 여부를 포함한다.
추천 부스와 지도 혼잡도 조회
BE/src/main/java/com/min/edu/booth/controller/BoothRecommendationController.java, BE/src/main/java/com/min/edu/booth/controller/VenueMapCongestionController.java, BE/src/main/java/com/min/edu/booth/service/BoothRecommendationService.java, BE/src/main/java/com/min/edu/booth/service/VenueMapCongestionService.java, BE/src/main/java/com/min/edu/booth/repository/BoothQrScanRepository.java, BE/src/main/java/com/min/edu/booth/dto/RecommendedBoothsResponse.java, BE/src/main/java/com/min/edu/booth/dto/VenueMapWithCongestionResponseDto.java
최근 10분의 비중복 QR 스캔을 집계한다. 상위 3개 혼잡 부스를 제외한 추천 목록을 생성한다. 지도 마커에 혼잡도 수치, 단계, 색상을 추가한다.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant BoothReservationController
  participant BoothReservationWithRedisService
  participant RedisReservationService
  participant BoothReservationRepository
  BoothReservationController->>BoothReservationWithRedisService: 예약 생성 요청
  BoothReservationWithRedisService->>RedisReservationService: 슬롯 임시 선점
  BoothReservationWithRedisService->>BoothReservationRepository: 예약 저장
  BoothReservationWithRedisService->>RedisReservationService: 실패 시 선점 해제
Loading
sequenceDiagram
  participant BoothCheckInController
  participant BoothCheckInService
  participant BoothReservationRepository
  participant BoothQrScanRepository
  BoothCheckInController->>BoothCheckInService: 체크인 요청
  BoothCheckInService->>BoothReservationRepository: 예약 잠금 조회
  BoothCheckInService->>BoothQrScanRepository: 중복 확인 및 스캔 저장
  BoothCheckInService-->>BoothCheckInController: 응답 반환
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning 작업 내용, 관련 이슈, 체크리스트 결과, 리뷰어 안내가 모두 템플릿 기본 문구로 남아 있어 설명이 불완전합니다. 구현 내용과 변경 이유를 작성하고, 관련 이슈 번호와 체크리스트 결과를 갱신하세요. UI 변경이 있으면 스크린샷도 추가하세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 73.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed 제목은 Redis 기반 부스 예약 기능이라는 주요 변경 사항을 명확하게 요약합니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/redis-booth-reservation

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 14

🧹 Nitpick comments (3)
BE/src/main/java/com/min/edu/booth/service/BoothRecommendationService.java (1)

54-76: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

같은 쿼리를 두 번 실행하고, 1000건을 메모리로 끌어옵니다.

54행 쿼리는 36-37행과 조건이 같고 정렬도 같습니다. 즉 54행 결과의 상위 3건이 곧 congestedBooths입니다. 별도 조회 없이 한 번만 조회하고 앞의 CONGESTION_THRESHOLD개를 혼잡 부스로, 그 다음부터 pageable.getPageSize()개를 추천 부스로 나누면 됩니다. 1000이라는 매직넘버도 사라집니다. 현재 구조는 부스가 1000개를 넘으면 조용히 잘리는 문제도 있습니다.

♻️ 리팩터 제안
-        Pageable congestedPageable = PageRequest.of(0, CONGESTION_THRESHOLD);
-        var congestedPage = qrScanRepository.findPopularBooths(since, congestedPageable);
+        int fetchSize = CONGESTION_THRESHOLD + Math.max(pageable.getPageSize(), 1);
+        var popularPage = qrScanRepository.findPopularBooths(since, PageRequest.of(0, fetchSize));
+        List<Object[]> rows = popularPage.getContent();

그 뒤 rows의 앞 CONGESTION_THRESHOLD건으로 congestedBooths를 만들고, 나머지로 recommendedBooths를 채우면 54-76행 루프와 congestedBoothIds 집합이 모두 필요 없습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@BE/src/main/java/com/min/edu/booth/service/BoothRecommendationService.java`
around lines 54 - 76, Update BoothRecommendationService to execute the
popular-booth query only once, reusing its rows for both congestion filtering
and recommendations. Use the existing CONGESTION_THRESHOLD to treat the first
threshold-ranked rows as congested, then build recommendations from subsequent
rows up to pageable.getPageSize(); remove the separate congestedBoothIds lookup,
the 1000-row limit, and the associated filtering loop.

Source: Path instructions

BE/src/main/java/com/min/edu/booth/service/VenueMapCongestionService.java (2)

127-147: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

혼잡도 수준을 enum으로 묶는 편이 안전합니다.

determineCongestionLevel이 문자열을 반환하고 getColorByLevel이 그 문자열을 다시 분기합니다. 오타가 나면 컴파일 시점에 잡히지 않고 145행의 회색 기본값으로 조용히 넘어갑니다. 임계값 20, 10도 상수 없이 박혀 있습니다.

CongestionLevel enum에 임계값과 색상 코드를 함께 두면 두 메서드가 하나로 줄어듭니다. 참고로 VenueMapWithCongestionResponseDto.java:33의 주석은 "노랑"이라고 되어 있지만 실제 MEDIUM 색상은 #FFA500(주황)입니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@BE/src/main/java/com/min/edu/booth/service/VenueMapCongestionService.java`
around lines 127 - 147, Replace the string-based determineCongestionLevel and
getColorByLevel flow with a CongestionLevel enum that owns each level’s
threshold and color code. Update the congestion calculation to return the enum
and expose its color directly, using enum constants instead of magic values 20
and 10; preserve HIGH, MEDIUM, and LOW behavior and the existing `#FFA500` MEDIUM
color.

74-87: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

평면도 수만큼 쿼리가 반복됩니다.

buildVenueMapWithCongestion은 평면도 하나마다 findByVenueMapId와 findByIdIn을 호출합니다. 평면도가 N개면 쿼리가 2N번 발생합니다. 층이 많은 행사에서는 응답 시간이 늘어납니다.

venueMapId 목록으로 위치를 한 번에 조회하고 venueMapId 기준으로 그룹핑한 뒤, 전체 boothId로 부스를 한 번만 조회하는 방식을 권장합니다. 또한 boothIds가 비어 있으면 findByIdIn 호출을 건너뛰도록 가드를 추가해주세요.

♻️ 가드 추가 예시
-        Map<Long, Booth> boothMap = boothRepository.findByIdIn(boothIds).stream()
-                .collect(Collectors.toMap(Booth::getId, booth -> booth));
+        Map<Long, Booth> boothMap = boothIds.isEmpty()
+                ? Map.of()
+                : boothRepository.findByIdIn(boothIds).stream()
+                        .collect(Collectors.toMap(Booth::getId, booth -> booth));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@BE/src/main/java/com/min/edu/booth/service/VenueMapCongestionService.java`
around lines 74 - 87, Update buildVenueMapWithCongestion to batch-load all
BoothMapPosition records using the venueMapId collection, group them by
venueMapId, and fetch all booths once from the combined boothIds. Add a guard so
boothRepository.findByIdIn is skipped when boothIds is empty, then use the
grouped positions and shared boothMap when building each map’s markers.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@BE/src/main/java/com/min/edu/booth/controller/BoothCheckInController.java`:
- Around line 26-29: BoothCheckInController의 checkIn 메서드에서 `@RequestBody`
BoothCheckInRequest 매개변수에 `@Valid를` 적용하여 exchangeCode의 `@NotBlank` 검증이 서비스 호출 전에
실행되도록 수정하세요.

In `@BE/src/main/java/com/min/edu/booth/controller/BoothReviewController.java`:
- Around line 47-53: Update the public getBoothReviews flow and
BoothReviewResponse so responses no longer expose the internal memberId. Replace
it with the existing public author-information representation, and update the
service/mapper construction paths consistently while preserving the endpoint’s
behavior for unauthenticated users.

In `@BE/src/main/java/com/min/edu/booth/service/BoothCheckInService.java`:
- Around line 42-59: Update BoothCheckInService’s exchange-code validation to
verify holderMemberId matches the authenticated member and ExchangeCode.eventId
matches the target Booth.eventId before changing code state. Preserve each code
type’s existing holder rules, and reject mismatched member or event ownership
through the established validation exception path.

In `@BE/src/main/java/com/min/edu/booth/service/BoothRecommendationService.java`:
- Around line 71-75: Update the pagination flow in BoothRecommendationService to
honor both pageable.getPageNumber() and pageable.getPageSize(), so each
requested page returns its correct slice instead of always returning the first
page. Prefer passing the Pageable through to the repository query for
database-level pagination; if pagination is not intended, replace the
controller’s Pageable parameter with an explicit size request parameter.
- Around line 32-54: Update BoothQrScanRepository.findPopularBooths by adding an
event-scoped query that filters QR scans by eventId, then replace the calls in
BoothRecommendationService.getRecommendedBooths
(BE/src/main/java/com/min/edu/booth/service/BoothRecommendationService.java:32-54)
to pass the method’s eventId. Add eventId to
VenueMapCongestionService.getCongestionMap and switch its calls to the new query
(BE/src/main/java/com/min/edu/booth/service/VenueMapCongestionService.java:56-65),
preserving the existing pagination and congestion calculations.
- Around line 95-115: Update the recommendation response flow in
BoothRecommendationService so it handles an empty recommendedBooths collection
before formatting the message. Return an appropriate congestion message without
the recommended-booth phrase when no recommendations exist, while preserving the
existing formatted response for non-empty recommendations.

In `@BE/src/main/java/com/min/edu/booth/service/BoothReservationService.java`:
- Around line 113-116: BoothReservationService의 예약 취소 흐름에서
vacancyNotificationService.notifyVacancy 호출을 기존 트랜잭션 밖으로 분리하세요. 커밋 후 이벤트 또는
outbox를 통해 알림 생성을 비동기 처리하고, 알림 이벤트에는 재처리 시 중복을 방지할 수 있는 고정 식별자를 포함하세요.

In
`@BE/src/main/java/com/min/edu/booth/service/BoothReservationWithRedisService.java`:
- Around line 48-60: Update the slot validation in
BoothReservationWithRedisService to reject reservations unless slot.getStatus()
is OPEN, and reject requests where request.getPartySize() exceeds
slot.getCapacity() - slot.getReservedCount(). Preserve the existing booth
ownership validation and use the established invalid-input error for both
failures.
- Around line 73-91: 예약 확정 후 Redis 임시 선점 키가 남지 않도록
BoothReservationWithRedisService의 DB 저장 흐름과 BoothReservationController의 Redis
처리를 하나의 예약 서비스 흐름으로 통합하세요.
BE/src/main/java/com/min/edu/booth/service/BoothReservationWithRedisService.java:73-91에서는
DB 트랜잭션이 성공적으로 커밋된 뒤 슬롯별 선점 키를 해제하고,
BE/src/main/java/com/min/edu/booth/controller/BoothReservationController.java:31-46에서는
중복 Redis 처리를 제거한 뒤 통합된 서비스 메서드만 호출하도록 변경하세요.

In `@BE/src/main/java/com/min/edu/booth/service/BoothReviewService.java`:
- Around line 31-46: Wrap the BoothReviewRepository.saveAndFlush call in the
review-creation flow with handling for DataIntegrityViolationException, and
convert that exception to the same duplicate-review BusinessException used by
the existing findByMemberIdAndBoothId check. Preserve the current review fields
and normal successful-save behavior.

In `@BE/src/main/java/com/min/edu/booth/service/MobileGuideService.java`:
- Around line 125-128: Update hasAvailableSlots(Long boothId) to determine
availability from the actual reservation-slot state instead of always returning
true. Reuse the same Redis reservation and reservation-storage checks used by
the booking flow so exhausted booths are reported as unavailable and the guide
screen matches booking results.
- Around line 89-122: Refactor the MobileGuideService guide-list conversion so
toGuideBoothListResponse does not query repositories per booth. Collect all
booth IDs in getGuideMain and searchBooths, batch-fetch grouped average ratings
and review counts, and when memberId is present batch-fetch interested booth
IDs; map these results by booth ID and pass the preloaded values into response
construction, preserving null averages, zero counts, and false interest
defaults.

In `@BE/src/main/java/com/min/edu/booth/service/RedisReservationService.java`:
- Around line 53-59: Update RedisReservationService.releaseSlot to accept
memberId and atomically compare the Redis key’s stored owner with that memberId
before deleting it. Use a Redis Lua compare-and-delete operation so releaseSlot
cannot remove a newer member’s reservation after TTL expiry; update its callers
to pass the reservation owner.

In `@BE/src/main/java/com/min/edu/booth/service/VenueMapCongestionService.java`:
- Around line 56-65: Update getCongestionMap and the related qrScanRepository
query to filter QR-scan aggregation by the current event, then remove the fixed
PageRequest.of(0, 1000) limit in favor of Pageable.unpaged() or a query
constrained to the required booth IDs. Ensure the service passes the event
context into the repository call and eliminate the 1000 magic number rather than
relying on truncated results.

---

Nitpick comments:
In `@BE/src/main/java/com/min/edu/booth/service/BoothRecommendationService.java`:
- Around line 54-76: Update BoothRecommendationService to execute the
popular-booth query only once, reusing its rows for both congestion filtering
and recommendations. Use the existing CONGESTION_THRESHOLD to treat the first
threshold-ranked rows as congested, then build recommendations from subsequent
rows up to pageable.getPageSize(); remove the separate congestedBoothIds lookup,
the 1000-row limit, and the associated filtering loop.

In `@BE/src/main/java/com/min/edu/booth/service/VenueMapCongestionService.java`:
- Around line 127-147: Replace the string-based determineCongestionLevel and
getColorByLevel flow with a CongestionLevel enum that owns each level’s
threshold and color code. Update the congestion calculation to return the enum
and expose its color directly, using enum constants instead of magic values 20
and 10; preserve HIGH, MEDIUM, and LOW behavior and the existing `#FFA500` MEDIUM
color.
- Around line 74-87: Update buildVenueMapWithCongestion to batch-load all
BoothMapPosition records using the venueMapId collection, group them by
venueMapId, and fetch all booths once from the combined boothIds. Add a guard so
boothRepository.findByIdIn is skipped when boothIds is empty, then use the
grouped positions and shared boothMap when building each map’s markers.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d76c7171-e293-4700-a933-fc0edb940fcf

📥 Commits

Reviewing files that changed from the base of the PR and between ac631ce and d3d3077.

📒 Files selected for processing (29)
  • BE/src/main/java/com/min/edu/booth/controller/BoothCheckInController.java
  • BE/src/main/java/com/min/edu/booth/controller/BoothRecommendationController.java
  • BE/src/main/java/com/min/edu/booth/controller/BoothReservationController.java
  • BE/src/main/java/com/min/edu/booth/controller/BoothReviewController.java
  • BE/src/main/java/com/min/edu/booth/controller/MobileGuideController.java
  • BE/src/main/java/com/min/edu/booth/controller/VenueMapCongestionController.java
  • BE/src/main/java/com/min/edu/booth/dto/BoothAverageRatingResponse.java
  • BE/src/main/java/com/min/edu/booth/dto/BoothCheckInRequest.java
  • BE/src/main/java/com/min/edu/booth/dto/BoothReviewResponse.java
  • BE/src/main/java/com/min/edu/booth/dto/CreateBoothReviewRequest.java
  • BE/src/main/java/com/min/edu/booth/dto/MobileGuideBoothDetailResponse.java
  • BE/src/main/java/com/min/edu/booth/dto/MobileGuideBoothListResponse.java
  • BE/src/main/java/com/min/edu/booth/dto/MobileGuideMainResponse.java
  • BE/src/main/java/com/min/edu/booth/dto/RecommendedBoothsResponse.java
  • BE/src/main/java/com/min/edu/booth/dto/VenueMapWithCongestionResponseDto.java
  • BE/src/main/java/com/min/edu/booth/repository/BoothQrScanRepository.java
  • BE/src/main/java/com/min/edu/booth/repository/BoothRepository.java
  • BE/src/main/java/com/min/edu/booth/repository/BoothReservationRepository.java
  • BE/src/main/java/com/min/edu/booth/repository/BoothReviewRepository.java
  • BE/src/main/java/com/min/edu/booth/service/BoothCheckInService.java
  • BE/src/main/java/com/min/edu/booth/service/BoothRecommendationService.java
  • BE/src/main/java/com/min/edu/booth/service/BoothReservationService.java
  • BE/src/main/java/com/min/edu/booth/service/BoothReservationWithRedisService.java
  • BE/src/main/java/com/min/edu/booth/service/BoothReviewService.java
  • BE/src/main/java/com/min/edu/booth/service/BoothVacancyNotificationService.java
  • BE/src/main/java/com/min/edu/booth/service/MobileGuideService.java
  • BE/src/main/java/com/min/edu/booth/service/RedisReservationService.java
  • BE/src/main/java/com/min/edu/booth/service/VenueMapCongestionService.java
  • BE/src/main/java/com/min/edu/interest/repository/BoothInterestRepository.java

Comment thread BE/src/main/java/com/min/edu/booth/controller/BoothCheckInController.java Outdated
Comment thread BE/src/main/java/com/min/edu/booth/service/BoothCheckInService.java Outdated
Comment thread BE/src/main/java/com/min/edu/booth/service/BoothRecommendationService.java Outdated
Comment thread BE/src/main/java/com/min/edu/booth/service/BoothRecommendationService.java Outdated
Comment thread BE/src/main/java/com/min/edu/booth/service/BoothReviewService.java Outdated
Comment thread BE/src/main/java/com/min/edu/booth/service/MobileGuideService.java Outdated
Comment thread BE/src/main/java/com/min/edu/booth/service/MobileGuideService.java Outdated
Comment thread BE/src/main/java/com/min/edu/booth/service/VenueMapCongestionService.java Outdated
…roller.java

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
BE/src/main/java/com/min/edu/booth/controller/BoothCheckInController.java (1)

29-34: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

check-in 엔드포인트에 인증 규칙을 추가하세요.

POST /booths/{boothId}/check-in에 일치하는 인증 규칙이 없어 anyRequest().permitAll()이 적용됩니다. 비인증 요청의 principal이 null이면 principal.getMemberId()에서 NullPointerException이 발생합니다. 해당 경로에 .authenticated()를 추가하고 비인증 요청이 401을 반환하는 통합 테스트를 작성하세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@BE/src/main/java/com/min/edu/booth/controller/BoothCheckInController.java`
around lines 29 - 34, Update the security configuration for POST
/booths/{boothId}/check-in to require authentication before invoking
BoothCheckInController.checkIn, preventing unauthenticated requests from
reaching principal.getMemberId(). Add an integration test verifying that an
unauthenticated request to this endpoint returns 401.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@BE/src/main/java/com/min/edu/booth/controller/BoothCheckInController.java`:
- Around line 27-29: Remove the literal backticks surrounding the annotations in
the BoothCheckInController method parameters, leaving them as standard Java
annotations: `@PathVariable`, `@RequestBody` `@Valid`, and `@AuthenticationPrincipal`.

---

Outside diff comments:
In `@BE/src/main/java/com/min/edu/booth/controller/BoothCheckInController.java`:
- Around line 29-34: Update the security configuration for POST
/booths/{boothId}/check-in to require authentication before invoking
BoothCheckInController.checkIn, preventing unauthenticated requests from
reaching principal.getMemberId(). Add an integration test verifying that an
unauthenticated request to this endpoint returns 401.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5134fa94-de6b-44b7-851c-a5b632cd8803

📥 Commits

Reviewing files that changed from the base of the PR and between d3d3077 and 27132ed.

📒 Files selected for processing (1)
  • BE/src/main/java/com/min/edu/booth/controller/BoothCheckInController.java

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (1)
BE/src/main/java/com/min/edu/booth/service/MobileGuideService.java (1)

76-88: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

현재 부스 집합으로 관심 부스 조회를 제한하세요.

findBoothIdsByMemberId(memberId)는 회원의 모든 관심 부스 ID를 조회합니다. 따라서 다른 행사와 현재 검색 페이지에 포함되지 않은 부스까지 매 요청마다 조회하고 메모리에 적재합니다. memberId와 현재 boothIds를 함께 조건으로 사용하는 IN 조회를 BoothInterestRepository에 추가하세요. 두 위치 모두 반환된 Set<Long>으로 현재처럼 관심 여부를 계산하세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@BE/src/main/java/com/min/edu/booth/service/MobileGuideService.java` around
lines 76 - 88, Update both interest lookup sites in
BE/src/main/java/com/min/edu/booth/service/MobileGuideService.java (lines 76-88
and 150-161) to call a new BoothInterestRepository IN-query using memberId and
the current boothIds, then continue calculating interestMap from the returned
Set<Long> as currently implemented. Add the repository method that restricts
results to the provided booth ID collection.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@BE/src/main/java/com/min/edu/booth/controller/BoothReservationController.java`:
- Around line 54-60: Update BoothReservationController.cancelReservation to pass
the path boothId into reservationService.cancelReservation, then validate the
loaded reservation’s boothId against that path value and reject mismatches as a
business-logic error; preserve the existing member ownership check.

In `@BE/src/main/java/com/min/edu/booth/controller/BoothReviewController.java`:
- Around line 70-91: BoothReviewController에 BoothReviewService.updateReview를
호출하는 후기 수정 `@PutMapping` 엔드포인트를 추가하세요. 경로에서 boothId와 reviewId를 받고, 요청 본문과
principal.getMemberId()를 서비스에 전달하며 수정 결과를 적절한 ResponseEntity로 반환하세요.
updateReview 내부에서는 findByIdAndBoothId를 사용해 후기와 부스 소속을 함께 검증하도록 확인하세요.

In `@BE/src/main/java/com/min/edu/booth/event/BoothVacancyEventListener.java`:
- Around line 25-32: BoothVacancyEventListener.java 25-32에서는 커밋 후 알림 처리를 별도 빈의
트랜잭션으로 위임하도록 변경하고, 동기 처리를 유지한다면 BoothVacancyNotificationService의
notifyVacancyWithIdempotency를 Propagation.REQUIRES_NEW로 실행하세요.
BoothVacancyNotificationService.java 27-28에서는 매번 UUID.randomUUID()를 생성하지 말고 회원별
동일한 이벤트 식별자를 사용해 재처리 시 중복 알림을 방지하세요. 저장 커밋과 재처리 중복 방지를 통합 테스트로 검증하세요.

In `@BE/src/main/java/com/min/edu/booth/repository/BoothReviewRepository.java`:
- Line 19: Update BoothReviewRepository.findAverageRatingByBoothId to use an
explicit JPQL AVG query over BoothReview.rating filtered by boothId, and bind
the method parameter with `@Param`("boothId") while preserving the
Optional<Double> return type.

In `@BE/src/main/java/com/min/edu/booth/service/BoothReservationService.java`:
- Around line 96-129: Update BoothReservationService.cancelReservation to accept
only reservationId and memberId, matching BoothReservationController’s call;
remove the external boothId parameter, derive the booth ID from
reservation.getBoothId(), and use that value for Booth lookup and
BoothVacancyEvent publication.
- Around line 50-84:
BE/src/main/java/com/min/edu/booth/service/BoothReservationService.java:50-84의
예약 생성 로직에서 슬롯 조회·검사·증가를 행 잠금 또는 원자적 조건부 갱신으로 묶고, reservedCount에 partySize를 반영해
capacity를 초과하지 않도록 하세요; 중복 예약은 DB 유니크 제약으로도 보장하세요. 같은 파일 97-116의 취소 로직에서는 예약 상태
전이와 슬롯 인원 복원을 동일한 잠금 또는 조건부 갱신으로 원자화해 동일 예약의 동시 취소가 한 번만 반영되도록 하세요.

In
`@BE/src/main/java/com/min/edu/booth/service/BoothReservationWithRedisService.java`:
- Around line 128-141: Update BoothReservationWithRedisService.cancelReservation
to publish a BoothVacancyEvent after the slot reservation count is restored and
persisted, using the existing event publisher and AFTER_COMMIT listener path so
the cancellation API triggers vacancy notifications.
- Around line 101-109: BoothReservationWithRedisService의 예약 처리에서 saveAndFlush 직후
수행하는 releaseSlot 호출을 제거하고, 선점 성공 직후 TransactionSynchronizationManager 동기화를
등록하세요. 등록한 동기화의 afterCompletion에서 커밋 성공과 롤백을 구분하지 않고 boothId,
request.getSlotId(), memberId로 releaseSlot을 호출하도록 하며, 성공 경로와 catch 블록의 직접 해제 호출은
삭제하세요.

In `@BE/src/main/java/com/min/edu/interest/service/BoothInterestService.java`:
- Around line 21-28: BoothInterest 등록 흐름에서 memberId와 boothId 조합이 원자적으로 upsert되도록
변경하세요. BoothInterestService의 조회 후 생성 및 saveAndFlush 방식 대신 기존 DB upsert를 복원하거나,
동시 삽입으로 발생한 고유 제약 충돌을 멱등적 성공으로 처리하세요. 또한 BoothInterest 엔티티와 데이터베이스에 (memberId,
boothId) 고유 제약이 보장되도록 반영하세요.

---

Nitpick comments:
In `@BE/src/main/java/com/min/edu/booth/service/MobileGuideService.java`:
- Around line 76-88: Update both interest lookup sites in
BE/src/main/java/com/min/edu/booth/service/MobileGuideService.java (lines 76-88
and 150-161) to call a new BoothInterestRepository IN-query using memberId and
the current boothIds, then continue calculating interestMap from the returned
Set<Long> as currently implemented. Add the repository method that restricts
results to the provided booth ID collection.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3bbd9bff-a46d-4a56-8601-4cd93882ccfd

📥 Commits

Reviewing files that changed from the base of the PR and between 27132ed and c7f6bf0.

📒 Files selected for processing (24)
  • BE/src/main/java/com/min/edu/booth/controller/BoothCheckInController.java
  • BE/src/main/java/com/min/edu/booth/controller/BoothReservationController.java
  • BE/src/main/java/com/min/edu/booth/controller/BoothReviewController.java
  • BE/src/main/java/com/min/edu/booth/controller/MobileGuideController.java
  • BE/src/main/java/com/min/edu/booth/domain/BoothReview.java
  • BE/src/main/java/com/min/edu/booth/event/BoothVacancyEvent.java
  • BE/src/main/java/com/min/edu/booth/event/BoothVacancyEventListener.java
  • BE/src/main/java/com/min/edu/booth/repository/BoothQrScanRepository.java
  • BE/src/main/java/com/min/edu/booth/repository/BoothRepository.java
  • BE/src/main/java/com/min/edu/booth/repository/BoothReservationSlotRepository.java
  • BE/src/main/java/com/min/edu/booth/repository/BoothReviewRepository.java
  • BE/src/main/java/com/min/edu/booth/service/BoothCheckInService.java
  • BE/src/main/java/com/min/edu/booth/service/BoothRecommendationService.java
  • BE/src/main/java/com/min/edu/booth/service/BoothReservationService.java
  • BE/src/main/java/com/min/edu/booth/service/BoothReservationWithRedisService.java
  • BE/src/main/java/com/min/edu/booth/service/BoothReviewService.java
  • BE/src/main/java/com/min/edu/booth/service/BoothVacancyNotificationService.java
  • BE/src/main/java/com/min/edu/booth/service/MobileGuideService.java
  • BE/src/main/java/com/min/edu/booth/service/RedisReservationService.java
  • BE/src/main/java/com/min/edu/booth/service/VenueMapCongestionService.java
  • BE/src/main/java/com/min/edu/interest/dto/InterestBoothResponse.java
  • BE/src/main/java/com/min/edu/interest/repository/BoothInterestRepository.java
  • BE/src/main/java/com/min/edu/interest/service/BoothInterestService.java
  • BE/src/main/resources/db/migration/V14__Add_updated_at_to_booth_reviews.sql
🚧 Files skipped from review as they are similar to previous changes (3)
  • BE/src/main/java/com/min/edu/booth/service/VenueMapCongestionService.java
  • BE/src/main/java/com/min/edu/booth/repository/BoothRepository.java
  • BE/src/main/java/com/min/edu/booth/service/BoothRecommendationService.java

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.

1 participant