10. Audit — PolicyEvent·CancellationLog

정책 트리거·취소 감사 로그. 환불·노쇼·보상 추적 + 분쟁 대응.

PolicyEvent

Purpose: 모든 정책 액션의 감사 로그 (환불·일시정지·노쇼·보상·등급 변경 등). Related PRDs: 🏢 멤버십 시스템 · 🏢 멘토 등급 · 🏢 예약 Lifecycle: 시스템 또는 admin 액션 → 기록 (append-only)

Fields

Field Type Required Default Description
id String cuid() PK
memberId String? - null 회원 관련
mentorId String? - null 멘토 관련
storeId String? - null 지점 관련
type String - refund/pause/cancel/no_show/compensation/tier_change
subType String? - null 세부 분류 (“member_no_show”, “mentor_no_show” 등)
payload Json - 액션 컨텍스트 (금액·시간·사유 등)
triggeredBy String - “system” / “member_xxx” / “admin_xxx”
createdAt DateTime now()  

payload Json 예시

// 환불
{
  "paymentId": "pay_xxx",
  "refundAmount": 240000,
  "usedCredits": 2,
  "reason": "중도해지"
}

// 회원 노쇼
{
  "reservationId": "res_xxx",
  "sessionId": "ses_xxx",
  "creditCharged": 1
}

// 본사·멘토 노쇼
{
  "reservationId": "res_xxx",
  "compensationCredits": 1,
  "mentorTierImpact": "verified"  // 등급 영향
}

// 일시정지
{
  "membershipId": "mem_xxx",
  "pauseStartedAt": "...",
  "pauseEndAt": "...",
  "pauseDays": 31
}

Validation

  • type enum strict
  • triggeredBy 형식: “system” “member_{id}” “admin_{id}”
  • append-only — 수정 ❌

Indexes

  • [memberId, createdAt] — 회원 정책 이력
  • [mentorId, createdAt] — 멘토 이력
  • [type, createdAt] — 분석
  • [storeId, createdAt] — 지점 운영 데이터

Common Queries

  • 회원 환불 이력: WHERE memberId=? AND type='refund' ORDER BY createdAt DESC
  • 일별 노쇼 수: WHERE type='no_show' AND DATE(createdAt) = ?
  • 멘토 noshow 누적: WHERE mentorId=? AND type='no_show' AND subType='mentor_no_show'

Edge Cases

  • 시스템 자동 트리거 (cron 노쇼 처리) vs admin 수동 → triggeredBy로 구분
  • 분쟁 시 evidence: 이 테이블이 truth source

CancellationLog

Purpose: 예약 취소 상세 로그 (48h/6h 룰 적용 결과 추적). Related PRDs: 🏢 예약 · 👤 예약 Lifecycle: 취소 시 기록 (append-only)

Fields

Field Type Required Default Description
id String cuid() PK
reservationId String - FK
sessionStartAt DateTime - 세션 예정 시각 (denorm)
cancelledBy String - “member” / “mentor” / “system” / “admin”
cancelledById String - id (member id, mentor id, admin id)
cancelledAt DateTime now() 취소 시각
hoursBeforeSession Decimal(5,2) - 세션 시작까지 남은 시간 (음수면 사후)
category String - before_48h / 48h_to_6h / within_6h / mentor_no_show / member_no_show
creditCharged Int 0 차감 회차 (0 또는 1)
dayPassIssued Boolean false 48h-6h 시 true
dayPassId String? - null 발급된 DayPass
bonusCreditIssued Int 0 보상 회차
bonusCreditId String? - null 발급된 BonusCredit
penaltyOnMentor Boolean false 멘토 등급 패널티 적용
mentorPayoutDeduction Int 0 멘토 정산 차감 (6h 이내 멘토 취소)
reason String? - null 취소 사유 텍스트

Validation

  • category 결정 (자동): hoursBeforeSession >= 48 → before_48h / 6-48 → 48h_to_6h / 0-6 → within_6h / 음수 = no_show
  • cancelledBy enum
  • dayPassIssued=true → category=’48h_to_6h’ AND cancelledBy=’member’
  • bonusCreditIssued > 0 → cancelledBy=’mentor’ OR ‘system’

Indexes

  • reservationId (unique)
  • [cancelledBy, cancelledAt] — 누가 자주 취소하는지
  • [category, cancelledAt] — 카테고리별 패턴 분석

Common Queries

  • 회원 6h 이내 취소 빈도: WHERE cancelledBy='member' AND cancelledById=? AND category='within_6h'
  • 멘토 6h 이내 취소: WHERE cancelledBy='mentor' AND cancelledById=? AND category='within_6h' → 등급 평가 입력
  • 일별 노쇼 vs 취소 비율: GROUP BY category, DATE(cancelledAt)

Edge Cases

  • 회원 노쇼는 별도 트리거 (T+15 cron) — category=’member_no_show’, cancelledBy=’system’
  • admin 강제 취소 (운영 사유): cancelledBy=’admin’, creditCharged=0, bonusCreditIssued=가변
  • 양측 동시 취소 (race condition): 먼저 들어온 것 기준 처리

통합 Audit 흐름 예시

시나리오: 회원 6h 이내 취소

1. 회원이 6h 이내 취소 클릭
2. UI 강한 경고 → 확정
3. 시스템:
   a) CancellationLog 추가 (category=within_6h, creditCharged=1)
   b) PolicyEvent 추가 (type=cancel, subType=member_within_6h)
   c) Membership.creditsRemaining -= 1
   d) MentorPayout는 정상 (멘토 보호)
   e) Reservation.status='cancelled'
4. 회원 알림 (회차 차감 안내)

시나리오: 멘토 노쇼

1. T+15 cron: Reservation.status='confirmed' AND no checkedInAt AND mentor not entered
2. 시스템:
   a) CancellationLog (category=mentor_no_show, penaltyOnMentor=true)
   b) PolicyEvent (type=no_show, subType=mentor)
   c) BonusCredit 발급 → bonusCreditIssued=1
   d) MentorPayout deduction +20,000 (회당)
   e) Mentor tier 평가 입력 (averageRating 보정·등급 검토 트리거)
   f) Reservation.status='no_show'
   g) Session.status='no_show'
3. 회원 알림 (보상 회차 안내), 멘토 알림 (패널티 안내)

📘 사용 PRD

🏢 모든 플랫폼 PRD · 🏢 예약 시스템 · 🏢 멤버십 시스템 · 🏢 멘토 등급


2026-05-13 초안 — PolicyEvent·CancellationLog 상세 + 통합 흐름 예시