ADR-DS-014_반복 미도착 제재 계산 규칙
## 1. ?? ??
- ADR ID: ADR-DS-014
- ??: 반복 미도착 제재 계산 규칙
- ??: Draft
- ?? ??: 2026-03-02
- ?? ??: Domain Architecture
- ?? ADR: ?? ??
- Supersedes: N/A
- Superseded By: N/A
2. ?? (Context)
? ?? ?? ?? ??/?? ?? ADR ?? ?? v2 ?? ???? ?? ??/?? ?? ?? ??. ?? ??/?? ?? ?? ??/?? ?? ?? ??.
상태: Draft
작성일: 2026-03-02
범위: 미도착(Expired) 집계, 제재 레벨 산정, 적용 기간, 해제 조건, 예약 생성/유효시간 override, 오탐 방지 규칙
1. 목적
이 문서는 다음을 고정한다.
어떤 이벤트가 “미도착”으로 집계되는가
어떤 기간을 기준으로 몇 회면 제재가 적용되는가
제재는 어떤 형태로 적용되는가(차단/유효시간 단축/수량 제한)
제재는 언제 해제되는가
오탐/중복 집계를 어떻게 방지하는가
2. 핵심 원칙
보증금은 사용하지 않는다. 제재는 신뢰 기반 제어다.
제재는 자동 적용되며 발행자 개입이 없다.
제재는 점진적이며 영구 차단을 기본으로 하지 않는다.
제재 집계는 서버 확정 EXPIRED만 사용한다.
제재는 사용자에게 사유와 해제 시각을 명확히 제공한다.
3. 집계 이벤트 정의 (No-show Event Definition)
3.1 NoShowCount 이벤트
다음 조건을 만족하는 reservation만 미도착으로 집계한다.
reservation.status == EXPIRED
expired 확정은 서버에서 수행됨(ADR-DS-010, ADR-DS-012)
redeemedAt == null
즉, 클라이언트가 “만료로 보인다”는 판단은 집계에 포함하지 않는다.
3.2 집계 제외
다음은 집계하지 않는다.
REDEEMED 상태였다가 이후 상태가 변경되는 경우(금지 전이)
- 사용자가 확보를 취소한 경우(
cancelled)는 미도착으로 집계하지 않는다(별도 이벤트)
- 사용자가 확보를 취소한 경우(
4. 관측 기간(윈도우) 정의
4.1 기본 관측 기간
WINDOW_DAYS = 7
4.2 집계 기준 시간
- reservation.expiresAt 기준으로 window에 포함되는지를 판단한다.
즉, 다음 조건을 만족하면 window 내 no-show다.
expiresAt BETWEEN (serverNow - WINDOW_DAYS) AND serverNow
AND status == EXPIRED5. 제재 레벨 정의
제재는 레벨 기반이다.
LEVEL 0: 제재 없음
LEVEL 1: 유효시간 단축 (15 → 10)
LEVEL 2: 일시 차단 (24시간 확보 불가)
LEVEL 3: 강화 차단 (72시간 확보 불가) (초기에는 optional)초기 MVP에서는 LEVEL 0~2까지만 사용해도 된다.
LEVEL 3는 운영 데이터 이후 활성화한다.
6. 레벨 산정 규칙 (Level Evaluation)
6.1 기준 값(v1)
- 최근 7일 EXPIRED 횟수에 따라 결정한다.
| 최근 7일 EXPIRED 횟수 | 제재 레벨 |
|---|---|
| 0~1 | 0 |
| 2 | 1 |
| 3 | 2 |
| 4 이상 | 3 (optional) |
6.2 계산 공식
expiredCount = COUNT(reservation)
WHERE userId = ?
AND status = EXPIRED
AND expiresAt BETWEEN (serverNow - 7d) AND serverNowlevel = f(expiredCount) according to table.
7. 제재 적용 형태 (Enforcement)
7.1 LEVEL 1: 유효시간 단축
reserveExpiresMinutesOverride = 10
activeUntil은 null 또는 “정책적으로 유지되는 기간”을 둘 수 있음
권장(v1):
activeUntil을 두지 않고, window 내 expiredCount가 2 이상인 동안만 override 적용
즉, 레벨은 재평가 결과로 자연스럽게 내려간다
7.2 LEVEL 2: 일시 차단
activeUntil = serverNow + 24h예약 생성(createReservation) 차단
실패 코드:
user_temporarily_blocked
7.3 LEVEL 3: 강화 차단 (optional)
activeUntil = serverNow + 72h
8. 제재 평가 트리거 (When to Evaluate)
평가는 다음 이벤트에서 수행한다.
- reservation이 서버에서 EXPIRED로 확정될 때
MVP 권장:
- EXPIRED 확정 로직(조회/사용확정 처리) 내에서 “확정 순간”에 평가 호출
9. 제재 레코드 모델 (Penalty Record)
9.1 필수 필드
userId
level (0..3)
reason = repeated_expired
activeUntil (nullable)
reserveExpiresMinutesOverride (nullable)
updatedAt
9.2 업데이트 규칙
평가 결과 level이 현재보다 높으면 즉시 상향
level이 낮아지는 경우는 window 재평가 결과에 따라 자동 하향
activeUntil이 존재하는 상태에서 상향 평가가 발생하면:
- activeUntil은 max(currentActiveUntil, newActiveUntil)
10. 해제 규칙 (Recovery)
10.1 LEVEL 2/3 해제
serverNow >= activeUntil 이면 차단 해제
해제 후에도 최근 7일 expiredCount에 따라 LEVEL 1 override는 남을 수 있다
10.2 LEVEL 1 해제
- 최근 7일 expiredCount가 1 이하로 내려가면 level 0으로 복귀
11. 오탐 및 중복 집계 방지
11.1 중복 expired 방지
reservationId 기준으로 expired 확정은 멱등 처리
이미 EXPIRED 상태면 재평가를 수행하더라도 expiredCount는 변하지 않는다(단순 재계산)
11.2 redeemed 이후 expired 방지
ADR-DS-010 금지 전이를 강제
redeemedAt이 존재하면 어떤 경로로도 expired로 바뀔 수 없다
12. 사용자 노출 규칙
앱/웹에서 제재가 적용되면 반드시 다음을 보여준다.
제한 사유(반복 미도착)
적용 내용(예: 확보 유효시간 10분 / 24시간 제한)
해제 시각(activeUntil이 있는 경우)
비난/징벌 표현 금지.
13. 표준 실패 코드
예약 생성(createReservation) 시:
user_temporarily_blocked (until 포함)
reserve_expiry_shortened (성공 + 안내 필요)
reserve_limit_reached (동시 확보 제한)
14. 필수 테스트 케이스
T1: 최근 7일 expiredCount=2 → LEVEL 1 적용, expiresAt=+10분
T2: expiredCount=3 → LEVEL 2 적용, 24시간 차단
T3: activeUntil 경과 후 차단 해제
T4: 7일 경과로 expiredCount 감소 → LEVEL 1 해제
T5: 동일 reservation 재만료 처리(중복) 시 집계/레벨 불변
15. 미결 항목
LEVEL 3 활성화 여부(초기엔 비활성 권장)
기간/횟수 기준 튜닝(운영 데이터 기반)
업종별 가중치 적용 여부(초기엔 금지)
“의도적 악용” 탐지(초기엔 금지, 단순 규칙만)
Template v2 Addendum
In Scope
- Core domain rules (state/time/quantity/penalty/integrity/retention)
Out of Scope
- Payment settlement, PG integration, UI behavior
Boundaries
- Domain ADR defines policy. Implementation details belong to Tech ADR and code.
Source of Truth (SoT)
- State model: ADR-DS-010; Time/expiry: ADR-DS-012; Quantity/concurrency: ADR-DS-064.
Validation
- Detect state/constraint violations via tests and batch checks.
- Recovery and reprocessing must be idempotent.
Revisit Conditions
- KPI threshold breach (reservation failure, expiry ratio, payment confirmation failure)
- External dependency change (PG, regulation, location API)