Skip to content

Develop - #63

Merged
jaebeom79 merged 30 commits into
mainfrom
develop
May 14, 2026
Merged

Develop#63
jaebeom79 merged 30 commits into
mainfrom
develop

Conversation

@silkair

@silkair silkair commented May 14, 2026

Copy link
Copy Markdown
Contributor

📢 기능 설명

필요시 실행결과 스크린샷 첨부

연결된 issue

연결된 issue를 자동을 닫기 위해 아래 {이슈넘버}를 입력해주세요.

close #{이슈넘버}

✅ 체크리스트

  • PR 제목 규칙 잘 지켰는가?
  • 추가/수정사항을 설명하였는가?
  • 이슈넘버를 적었는가?

johe00123 and others added 30 commits May 11, 2026 17:58
- @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 추가
- 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 : 챗봇 예약 쿠폰 설정 추가

@gemini-code-assist gemini-code-assist 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.

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.

Comment on lines +92 to +95
Reservation saved = createReservationCore(
currentUserId, availableRemain.get().getId(), member, couponId);

StoreRemain storeRemain = saved.getStoreRemain();

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.

high

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.*;

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.

medium

이미 com.catchtable.notification.event 패키지의 개별 클래스들이 상단(7~11행)에서 명시적으로 임포트되어 있으므로, 와일드카드 임포트(.*)는 중복이며 불필요합니다. 이를 제거하여 임포트 섹션을 깔끔하게 유지하는 것이 좋습니다.

+ "한국어로 친절하게 답변해.";
private String buildSystemPrompt() {
return "너는 'CatchEat(캐치잇)'이라는 레스토랑 예약 플랫폼의 AI 비서야. "
+ "오늘 날짜는 " + java.time.LocalDate.now() + "이야. "

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.

medium

java.time.LocalDate.now()를 직접 사용하면 시스템 타임존에 의존하게 되어 환경별로 결과가 달라질 수 있고 테스트 시 시간을 제어하기 어렵습니다. SchedulerConfig에 정의된 Clock 빈을 주입받아 LocalDate.now(clock)을 사용하는 방식을 권장합니다.

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()))

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.

medium

LocalDateTime.now() 대신 주입된 Clock 빈을 사용하여 LocalDateTime.now(clock)으로 변경하는 것이 좋습니다. 프로젝트 내 다른 스케줄러 로직들과 시간 기준을 통일하여 일관성을 유지하고 테스트 가능성을 높일 수 있습니다.

@jaebeom79
jaebeom79 merged commit d5a2216 into main May 14, 2026
1 check 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.

3 participants