4. Reservation·Session·DayPass·BonusCredit

예약 + 세션 + 보상권. 5A 예약, 2D 정책 정책 반영.

Reservation

Purpose: 회원 1예약 = 카디오 30분 슬롯 + 방 60분 슬롯 + 멘토 30분 블록 묶음. Related PRDs: 👤 예약 · 🏢 예약 시스템 Lifecycle: 회원 예약 → 매칭 → 체크인 → 세션 진행 → 완료 (또는 취소/노쇼)

Fields

Field Type Required Default Description
id String cuid() PK
memberId String - FK
sessionId String - FK → Session (1:1)
storeId String - FK (denorm)
cardioSlotId String - FK → CardioSlot
roomSlotId String - FK → RoomSlot
mentorBlockId String? - null FK → MentorBlock (자동 매칭 대기 시 null)
mentorId String? - null FK → Mentor (FK lookup 편의)
mentorTier MentorTier verified 진행 당시 멘토 등급
startAt DateTime - 카디오 시작 시각
matchingMode MatchingMode manual manual / auto
autoMatchedAt DateTime? - null 24h 거절 카운트다운 기준
pointsCharged Int? - null Pro 인증 매칭 시 차감 포인트
isFixed Boolean false 고정 슬롯 자동 예약 여부
status ReservationStatus confirmed confirmed/rejected/cancelled/no-show/completed
createdAt DateTime now()  
cancelledAt DateTime? - null  
cancelReason String? - null  

Validation

  • (cardioSlotId, roomSlotId, mentorBlockId) 모두 status=available 또는 매칭 가능 상태에서 동시 점유
  • startAt = cardioSlot.startAt
  • roomSlot.startAt = startAt + 30min
  • mentorBlock.startAt = roomSlot.startAt + 30min (방 60분 중 후반 30분)
  • isFixed=true → memberId의 FixedSlot 매칭

State Transitions

stateDiagram-v2
    [*] --> confirmed: 예약 생성
    confirmed --> rejected: 자동 매칭 24h 거절
    confirmed --> cancelled: 변경/취소
    confirmed --> no-show: T+15 미체크인
    confirmed --> completed: 세션 완료
    cancelled --> [*]
    rejected --> confirmed: 재매칭 성공

Indexes

  • [memberId, startAt] — 회원 예약 리스트
  • [mentorId, startAt] — 멘토 일정
  • [startAt, status] — 오늘 진행 예약 조회
  • [storeId, startAt] — 지점별 운영

Common Queries

  • 회원 다음 예약: WHERE memberId=? AND status='confirmed' AND startAt > NOW()
  • 매칭 거절 가능 (24h 내): WHERE memberId=? AND matchingMode='auto' AND autoMatchedAt > NOW() - 24h AND status='confirmed'
  • 노쇼 처리: cron WHERE status='confirmed' AND startAt < NOW() - 15min AND checkedInAt IS NULL → no-show

Edge Cases

  • 동시성 (두 회원 같은 슬롯 시도): DB row lock
  • 매칭 후 회원 거절 → 다른 멘토 자동 매칭 → 또 거절 (반복) 시 수동 모드 권유
  • 변경 시 슬롯 swap: 트랜잭션으로 처리
  • 취소 시점에 따른 룰: CancellationLog 기록 (별도)

Session

Purpose: 실제 세션 진행 단위. Reservation 1:1. Related PRDs: 🏢 세션 시스템 Lifecycle: booked → checked-in → in-progress → completed (또는 no-show / cancelled)

Fields

Field Type Required Default Description
id String cuid() PK
reservationId String - FK (1:1)
memberId String - denorm
mentorId String? - null denorm (자동 매칭 대기 시 null)
storeId String - denorm
startAt DateTime - 세션 시작 (카디오 시작)
checkedInAt DateTime? - null 회원 체크인 시각
startedAt DateTime? - null 카디오 시작
mentorEnteredAt DateTime? - null 멘토 방 입장 (T+30)
completedAt DateTime? - null 세션 종료
cancelledAt DateTime? - null  
status SessionStatus booked booked/checked-in/in-progress/completed/no-show/cancelled

Validation

  • reservationId unique (1:1)
  • 시간 흐름: startAt < checkedInAt < mentorEnteredAt < completedAt

State Transitions

stateDiagram-v2
    [*] --> booked: Reservation 확정
    booked --> checked_in: QR 체크인
    checked_in --> in_progress: 카디오 시작
    in_progress --> completed: 세션 끝
    booked --> no_show: T+15 미체크인
    booked --> cancelled: 회원 취소

Indexes

  • [startAt, status] — 오늘 세션 조회
  • [memberId, startAt] — 회원 히스토리
  • [mentorId, startAt] — 멘토 일정·이력

Common Queries

  • 오늘 진행 세션: WHERE DATE(startAt) = TODAY AND status IN ('checked_in','in_progress')
  • 회원 누적 세션: WHERE memberId=? AND status='completed'

Edge Cases

  • 회원 미체크인 + 멘토 도착 = 멘토 대기 상태 (T+15에 노쇼 판정)
  • 세션 중 부상 → 강제 종료 (completed + record에 사유 메모)

DayPass (당일 예약권)

Purpose: 48h-6h 취소 시 발급되는 당일 예약권 (당일 23:59 만료). Related PRDs: 👤 예약·취소 · 👤 멤버십 Lifecycle: 발급 → 사용 (또는 만료)

Fields

Field Type Required Default Description
id String cuid() PK
memberId String - FK
issuedAt DateTime now() 발급 시각
expiresAt DateTime - 발급일 23:59
reason String - “late_cancel_48_to_6”
sourceReservationId String - 발급 근거 예약
used Boolean false  
usedAt DateTime? - null  
usedReservationId String? - null 사용된 예약

Validation

  • expiresAt = DATE(issuedAt) + 23:59
  • used=true 시 usedAt, usedReservationId 필수

Indexes

  • [memberId, used, expiresAt] — 활성 당일 예약권 조회

Common Queries

  • 회원 활성 당일권: WHERE memberId=? AND used=false AND expiresAt > NOW()

Edge Cases

  • 발급 후 회원이 그날 안 옴 → 만료 (used=false 유지, 자동 archive)
  • 발급 후 즉시 사용 시도 → OK
  • 동시 여러 장 보유 시 → FIFO 사용

BonusCredit (보상 회차)

Purpose: Pro 인증 예약 → 일반 멘토 변경 시 발급되는 추가 1회권. 멘토 노쇼 보상도 같은 모델. Related PRDs: 👤 멤버십 · 🏢 예약 시스템 Lifecycle: 발급 → 사용 (또는 만료, 30일)

Fields

Field Type Required Default Description
id String cuid() PK
memberId String - FK
issuedAt DateTime now()  
expiresAt DateTime - issuedAt + 30일
reason String - “pro_mentor_swap” / “mentor_no_show”
sourceReservationId String - 발급 근거
used Boolean false  
usedAt DateTime? - null  
usedReservationId String? - null  

Validation

  • reason enum
  • expiresAt > issuedAt

Indexes

  • [memberId, used, expiresAt] — 활성 보상권

Common Queries

  • 회원 활성 보상권: WHERE memberId=? AND used=false AND expiresAt > NOW()

Edge Cases

  • 보상권 만료 (30일 미사용) → 자동 archive
  • 회원 탈퇴 시 → 미사용 보상권 무효화 (환불 ❌)

📘 사용 PRD

👤 세션 진행 · 👤 예약 · 💪 세션 진행 · 💪 슬롯 · 🏢 세션 시스템 · 🏢 예약 시스템


2026-05-13 초안 — Reservation·Session·DayPass·BonusCredit 상세 명세