SPEC-000_통합 구현 기준

SPEC-000_통합 구현 기준

SPEC-000 통합 구현 기준

1. Metadata

  • Status: draft
  • Date: 2026-03-09
  • Owner: YSY
  • Source ADRs: ADR-000/010/020/030/040/050/060/070/080/090/100/110/120/130/140/150/160/170/180/190/200/210/220/230/240/250/260/270/280

2. Scope

이 문서는 현재 서비스 구현 기준(정책, UX, API, 데이터, 보안)을 단일 기준으로 정의한다.

3. 핵심 용어 및 상태 고정값

  1. slots.status: issued|closed
  2. reservations.status: hold|reserved|redeemed|expired|cancelled
  3. verification_method: none|location|qr
  4. payment_method: on_site|prepaid
  5. 시간 판정(만료/한도/제재)은 서버 UTC를 기준으로 처리한다.

4. 사용자/파트너 정책 기준

  1. 탐색/상세는 비로그인 접근을 허용한다.
  2. 상태 변경 액션(예약/취소/구독변경 등)에서만 로그인 인터셉트를 적용한다.
  3. 전화 인증(OTP) 완료 전에는 상태 변경 액션을 허용하지 않는다.
  4. Hold는 결제 진행 중 임시 점유로만 사용한다.
  5. Hold 기본 만료 90초, 최대 180초, 결제 재시도 기본 2회를 사용한다.
  6. prepaid 결제 성공 시 상태는 우선 reserved로 확정한다.
  7. verification_method=none이면 reserved -> redeemed를 즉시 수행한다. (prepaid/on_site 공통)
  8. verification_method=location이면 위치 검증 성공 시 redeemed로 전이한다.
  9. verification_method=qr이면 QR 검증 성공 시 redeemed로 전이한다.
  10. on_site+location 검증은 주기 검증이 아니라 사용/수령 이벤트 시점 검증으로 처리한다.
  11. 위치 검증 실패 시 만료 전까지 QR 폴백을 제공하고, 만료 시 expired로 종료한다.
  12. 취소는 cancel_reason 저장을 필수로 한다.
  13. 파트너 상태는 partner_registered|partner_active|partner_suspended 모델을 유지한다.
  14. 슬롯 발행 권한은 구독 활성 상태(partner_active)에서만 허용한다.
  15. 발행 제한은 플랜 한도 정책을 서버에서 강제한다.
  16. 반복 미이행(expired/cancelled)은 제재 정책과 연동한다.
  17. 선결제 분쟁은 발행자-사용자 직접 해결을 기본으로 하고 플랫폼은 근거 로그 제공을 담당한다.
  18. expired|cancelled 결과 응답은 refund=false를 기본 정책 플래그로 포함한다.
  19. 취소 요청은 cancel_reason 없이 처리할 수 없다.
  20. 취소 사유 기본값은 user_cancelled|partner_cancelled|system_cancelled로 제한한다.
  21. 만료 판정은 expires_at_utc로 수행하고 사용자 표시는 로컬 시간으로 변환한다.
  22. 구독 플랜 카탈로그와 발행 권한 파라미터(entitlement)는 ADR-270 기준으로 버전 관리한다.
  23. Add-on은 다중 선택 가능하며 basic에서 3개 이상 선택 시 plus 전환을 유도한다. pre_paid 권한은 prepaid_unlock 또는 상위 플랜 기본 권한에서만 활성화한다.
  24. 쿠폰 적용 시 유효 권한은 쿠폰 세그먼트가 우선하며, 종료 후 기본 구독 권한으로 자동 복귀한다.

5. UX 기준

UX 관련 단일 SoT는 본 섹션이며, ADR/SCENARIO/RUNBOOK은 아래 Rule ID를 참조만 한다.

5.1 UX Rule Catalog (SoT)

  1. UX-R-001: 진행형 플로우는 상단 단계(hold/결제/검증/완료)를 고정 노출한다.
  2. UX-R-002: 단계 화면은 Primary CTA 1개를 중심으로 구성한다.
  3. UX-R-003: 실패 화면은 기본 다음 행동 1개만 제시한다.
  4. UX-R-004: 결제/예약 확정 직후에는 reserved 상태와 다음 필수 단계를 먼저 안내한다.
  5. UX-R-005: verification_method=none은 즉시 완료 화면으로 연결한다.
  6. UX-R-006: location 검증은 이벤트 시점으로 처리하며 실패 시 만료 전 QR 폴백을 제공한다.
  7. UX-R-007: qr 검증 화면은 스캔 안내, 재시도 조건, 종료 조건을 명시한다.
  8. UX-R-008: 취소 확인 단계는 환불 없음 정책과 취소 결과(cancelled)를 확정 전 노출한다.
  9. UX-R-009: 취소/만료 결과 화면은 final_status, 처리 시각, refund=false, 다음 행동 CTA를 함께 제공한다.
  10. UX-R-010: 권한 거부(AUTH_TRANSITION_DENIED) 화면은 차단 사유와 복구 CTA를 함께 제공한다.
  11. UX-R-011: 시간 표시는 로컬 기준으로 일관되게 제공하고 판정 기준은 서버 UTC로 설명한다.
  12. UX-R-012: 멱등 재요청 시 동일 결과 화면을 재노출한다.
  13. UX-R-013: 선결제 분쟁 안내의 기본 경로는 발행자 직접 해결이며 플랫폼은 증적 안내를 보조한다.
  14. UX-R-014: 반복 미이행 가능 사용자에게 예약 시도 단계에서 경고/제재 안내를 제공한다.
  15. UX-R-015: 최초 실행 라우팅은 유지보수 -> 강제업데이트 -> 세션복원 -> 기본 탐색 순서를 따른다.
  16. UX-R-016: 최초 실행 빈 상태는 권한 미허용|오프라인|초기 데이터 없음으로 분기한다.
  17. UX-R-017: 앱 기본 진입 화면은 탐색 화면으로 고정한다.
  18. UX-R-018: 로그인 인터셉트 후 원래 액션으로 복귀하며 복귀 토큰 만료 시 안전 화면으로 복귀한다.
  19. UX-R-019: 탐색/상세의 수량/마감 표시는 동일 규칙으로 노출한다.
  20. UX-R-020: 빈 상태는 원인별(반경/필터/권한/오류)로 분기하고 즉시 다음 행동 CTA를 제공한다.
  21. UX-R-021: 관심상점/관심업종은 즉시 등록/해제 가능하며 예약 보장이 아님을 명시한다.
  22. UX-R-022: 예약 완료 직후 수량/상태 스냅샷을 즉시 반영한다.

6. API 계약 기준

  1. 상태 변경 API는 idempotency_key를 필수로 받는다.
  2. 권한 밖 전이는 표준 실패 코드로 거부한다.
  3. 전이 실패 시 부분 반영 없이 원자적으로 롤백한다.
  4. 성공 응답은 최종 상태 스냅샷을 반환한다.
  5. 에러 응답은 domain_coderetryable을 포함한다.
  6. 정책 오류와 시스템 오류를 구분해 반환한다.
  7. 취소/만료 결과 응답은 refund, cancel_reason(해당 시), final_status를 포함한다.
  8. 취소 요청 권한 부족은 AUTH_TRANSITION_DENIED로 반환한다.
  9. 취소 사유 누락은 CANCEL_REASON_REQUIRED로 반환한다.
  10. 시간 관련 응답은 server_time_utc, expires_at_utc를 함께 반환한다.

6.1 상태 전이 명령 표준

CommandActorPreconditionsResult
Hold 생성user인증 완료, 활성 hold 중복 없음, 수량/한도 충족hold 생성
결제 확정(prepaid)system/payment유효 hold, 결제 성공reserved 확정
예약 확정(on_site)user/system유효 hold, on_site 정책 충족reserved 확정
자동 완료(none)systemreserved + verification_method=noneredeemed
위치 검증 완료partner/systemreserved + verification_method=locationredeemed
QR 검증 완료partner/systemreserved + verification_method=qrredeemed
위치 검증 실패partner/systemreserved + verification_method=location + 미만료fallback=qr 안내
예약 취소user/systemreserved, cancel_reason 존재, 권한 검증 통과cancelled, refund=false
결제 실패/타임아웃system/payment유효 holdexpired 또는 cancelled
만료 처리scheduler/system`holdreserved` 만료시각 초과
첫 예약 완료 응답system상태 확정 성공final_status, next_actions, post_action_quantity_snapshot 반환

7. 데이터 기준

  1. 핵심 엔터티는 slots, reservations, reservation_holds, penalties, audit_logs, user_favorite_store, user_interest_category, partner_pg_config로 고정한다.
  2. 가용 수량 SoT: total_quantity - active_hold - active_reserved.
  3. 가용 수량 하한은 0으로 고정한다.
  4. 동일 사용자+슬롯의 활성 hold 중복 생성은 금지한다.
  5. 관심상점 유니크 키: (user_id, store_id).
  6. 관심업종 유니크 키: (user_id, category_id).
  7. hold-reservation 참조 무결성을 강제한다.
  8. 불변조건 위반 시 데이터 변경을 중단하고 오류를 반환한다.
  9. 개인정보/거래/감사 데이터의 보존 정책을 분리 적용한다.
  10. 삭제 요청은 삭제 배치와 익명화 배치를 분리해 재실행 가능하게 처리한다.
  11. cancelled 레코드는 cancel_reason, cancelled_at_utc를 필수로 저장한다.
  12. expired|cancelled 레코드는 환불 정책 플래그(refund=false)를 함께 저장한다.
  13. 시간 표시용 로컬 값은 파생 필드로만 사용하고 판정 필드는 UTC를 사용한다.

8. 보안 및 감사 기준

  1. 권한 검증은 RLS + RPC 이중 경계로 적용한다.
  2. 역할별 상태 전이 허용 목록은 서버에서 강제한다.
  3. 클라이언트 권한 체크는 UX 보조이며 보안 근거로 사용하지 않는다.
  4. 시크릿 원문 저장을 금지하고 참조키만 저장한다.
  5. 핵심 상태 전이/권한 변경/수동 조치/제재는 감사로그에 동일 포맷으로 기록한다.
  6. 감사로그 최소 필드는 actor, target, action, timestamp, result_code로 고정한다.
  7. 중요 오류 코드는 알람/온콜 기준으로 운영한다.

9. Validation

  • 본 문서의 상태/전이/권한 규칙이 ADR-010~260과 충돌하지 않는다.
  • API/DB/UX 구현이 본 문서 기준과 일치한다.
  • 실패 코드, 감사로그, 보존/삭제 처리 경로가 운영 점검 가능하다.
  • 정책 파라미터(Hold TTL, 재시도, 발행 제한)가 서버 설정으로 일원화되어 있다.