슬롯 수량 및 동시성 SoT 통합

슬롯 수량 및 동시성 SoT 통합

ADR-020 슬롯 수량 및 동시성 SoT 통합

1. Metadata

  • ADR ID: ADR-020
  • Status: draft
  • Date: 2026-03-09
  • Owner: YSY

2. Domain Decision

슬롯 가용 수량 계산의 SoT를 서버로 고정한다.

  1. 가용 수량 계산: total_quantity - active_hold - active_reserved
  2. active_hold: reservation_holds.status='active' and expires_at > now()
  3. active_reserved: reservations.status='reserved' and (expires_at is null or expires_at > now())
  4. 가용 수량은 0 미만으로 내려가지 않도록 greatest(..., 0) 적용
  5. 앱은 계산 결과를 표시만 하고 자체 계산으로 확정하지 않는다.

3. Product Decision

  • 해당 없음

4. UX Decision

  1. 가용 수량/마감 상태를 탐색과 상세에서 동일하게 표기한다.
  2. Hold로 인한 일시 품절 가능성을 문구로 안내한다.
  3. 사용자 예약 가능 여부를 버튼 상태로 명확히 표시한다.
  4. 첫 예약 완료 직후 상세/탐색 수량을 서버 스냅샷 기준으로 즉시 갱신한다.

5. Tech Decision

  1. 수량 계산 SoT는 DB 함수/쿼리로 고정한다.
  2. 경합 구간은 트랜잭션/락 전략으로 보호한다.
  3. 클라이언트 계산값은 최종 판단에 사용하지 않는다.

6. Ops Decision

  • 해당 없음

7. Implementation Contract (Optional)

7.1 API Contract

  • 수량 조회 응답은 available_quantity, active_hold_count, active_reserved_count, snapshot_at_utc를 포함한다.
  • 상태 변경 전 서버 재계산 결과를 기준으로 최종 허용 여부를 판정한다.
  • 상태 변경 성공 응답은 post_action_quantity_snapshot을 포함해 UI 즉시 동기화를 지원한다.

7.2 Data Contract

  • 가용 수량은 total_quantity - active_hold - active_reserved 공식으로만 계산한다.
  • 계산 기준 시각은 서버 UTC now()로 고정한다.

7.3 Error/Observability Contract

  • 수량 판정 실패는 CAPACITY_CALCULATION_FAILED 코드로 반환한다.
  • 경합으로 인한 거부는 CAPACITY_CONFLICT 코드로 분리 기록한다.

7.4 Test/Acceptance Contract

  • 동시 요청 경합에서도 가용 수량은 음수가 되지 않아야 한다.
  • 동일 슬롯의 탐색/상세 가용 표시가 일치해야 한다.
  • 첫 예약 완료 후 1회 새로고침 내에 수량 스냅샷이 반영되어야 한다.

8. Validation

  • Domain/Product/UX/Tech/Ops 결정이 충돌하지 않는다.
  • 구현 기준은 SPEC과 정합성을 유지한다.
  • 운영 절차는 RUNBOOK으로 연결된다.