Conversation
- @EnableScheduling 활성화 위한 SchedulerConfig 신설 - Clock Bean을 Asia/Seoul로 등록 (코드 레벨 타임존 보장) - Dockerfile에 ENV TZ=Asia/Seoul 추가 (JVM 기본 타임존)
- CouponTemplate.expiredAt 경과한 UNUSED 쿠폰을 5분 주기로 EXPIRED 전환 - JPQL bulk UPDATE 사용 (서브쿼리 패턴으로 JOIN 우회)
- 예약 시각 30분 경과한 CONFIRMED 예약을 10분 주기로 NOSHOW 전환 - 동시성 방어: 처리 직전 status=CONFIRMED 재확인으로 race 방지 - 트리거(Scheduler)와 비즈니스 로직(Service) 분리
- 발송 시점: 예약 30분 전 → 1시간 전 변경 - 발송 채널: EmailService 직접 호출 → 이벤트 + 리스너 패턴 - 다른 예약 알림(확정/취소/변경/방문)과 동일 패턴으로 통일
- PATCH /api/v1/reservations/{id}/visit 전용 엔드포인트 신설
- markAsVisited 서비스 메서드 추가 (CONFIRMED → VISITED 전환)
- 본인 예약 검증 + CONFIRMED 상태 검증 포함
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
- ALREADY_CANCELED는 VISITED/NOSHOW 상태에도 노출되어 사용자 혼란 유발 할 수 있음. - 방문 확정 전용 NOT_VISITABLE_STATUS 에러 코드 신설 - 제미나이 코드 리뷰 피드백 반영
feat: 사용자 방문 확정 API 추가
…e-clone/backend into feat/#50-chatbot-agent
- LocalTime 기반 비교는 자정 넘어가면 wrap around로 윈도우 깨짐 - LocalDateTime 기반 (날짜+시간) 범위 비교로 변경 - findReminderTargets 시그니처: (date, from, to) -> (fromDate, fromTime, toDate, toTime) - 코드 리뷰 피드백 반영
- JPQL UPDATE 도 path expression(c.couponTemplate.expiredAt) 사용 가능 - Hibernate가 암시적 조인을 자동 처리하므로 서브쿼리 불필요 - 가독성 향상 (코드 리뷰 피드백 반영)
- 개별 UPDATE N회 -> 단일 벌크 UPDATE 1회로 성능 개선 - updatedAt 도 쿼리에서 직접 갱신 (@PreUpdate 미호출 대응) - 동시성 가드를 WHERE 절로 이동 (DB 레벨 보장) - 코드 리뷰 피드백 반영
feat : 챗봇 기능 db 접속 구현(예약 생성 에이전트)
…into feat/#52-scheduler # Conflicts: # Dockerfile
Feat/#52 scheduler
feat : 챗봇 예약 쿠폰 설정 추가
There was a problem hiding this comment.
Code Review
This pull request enhances the chatbot and reservation systems by introducing AI-driven tools for reservations and coupon management, implementing automated schedulers for cleaning up pending reservations and no-shows, and transitioning store review statistics to an asynchronous event-driven model. Review feedback identifies a critical issue where AI-created reservations are not correctly transitioned to a confirmed state, risking automatic deletion by the cleanup scheduler. Additionally, the reviewer recommends improving testability and consistency by utilizing the project's Clock bean for time-based logic and maintaining cleaner code by removing redundant wildcard imports.
| Reservation saved = createReservationCore( | ||
| currentUserId, availableRemain.get().getId(), member, couponId); | ||
|
|
||
| StoreRemain storeRemain = saved.getStoreRemain(); |
There was a problem hiding this comment.
createReservationCore 메서드는 예약 상태를 PENDING으로 생성합니다. 하지만 AI 예약 도구(createReservationFromAi)는 사용자에게 예약이 완료되었다고 응답하며 ReservationConfirmedEvent를 발행하고 있습니다. 이대로 두면 ReservationCleanupScheduler에 의해 5분 뒤에 결제 미완료로 간주되어 예약이 자동 취소될 수 있습니다. AI를 통한 예약을 즉시 확정하려면 상태를 CONFIRMED로 변경하는 로직을 추가해야 합니다.
Reservation saved = createReservationCore(
currentUserId, availableRemain.get().getId(), member, couponId);
saved.changeStatus(ReservationStatus.CONFIRMED);
StoreRemain storeRemain = saved.getStoreRemain();| import com.catchtable.notification.event.ReservationConfirmedEvent; | ||
| import com.catchtable.notification.event.ReservationVisitedEvent; | ||
| import com.catchtable.notification.event.VacancyEvent; | ||
| import com.catchtable.notification.event.*; |
| + "한국어로 친절하게 답변해."; | ||
| private String buildSystemPrompt() { | ||
| return "너는 'CatchEat(캐치잇)'이라는 레스토랑 예약 플랫폼의 AI 비서야. " | ||
| + "오늘 날짜는 " + java.time.LocalDate.now() + "이야. " |
| log.info("AI Tool 호출: getAvailableCouponsForAi, userId={}", userId); | ||
|
|
||
| List<Coupon> availableCoupons = couponRepository.findAllByUserId(userId).stream() | ||
| .filter(coupon -> coupon.getStatus() == CouponStatus.UNUSED && coupon.getCouponTemplate().getExpiredAt().isAfter(LocalDateTime.now())) |
📢 기능 설명
필요시 실행결과 스크린샷 첨부
연결된 issue
연결된 issue를 자동을 닫기 위해 아래 {이슈넘버}를 입력해주세요.
close #{이슈넘버}
✅ 체크리스트