[BE-02] DropReservationStore 게이트웨이 계약 (입장 게이트 + 완충)

작업 내용 (설계 의도)

변경 사항

Redis 입장 게이트(FR-8) + 완충(FR-7) + 1인 한도(FR-6) + 멱등을 감추는 domain gateway 계약을 신설한다(근거 TDD: ../TDD.md “인터페이스 시그니처”, ADR-001·ADR-003). SeatLockStore(domain gateway) 선례를 따른다. BE-03(도메인 서비스)·BE-04(구현체)가 이 계약을 공유한다. 파일 집합이 BE-01과 겹치지 않아 같은 wave 병렬 안전.

  • DropReservationStore(interface, domain/goods/gateway): seedIfAbsent(dropId, initialQuantity, ttl)·reserve(dropId, userId, quantity, perUserLimit, idempotencyKey): ReservationResult·confirmSuccess(...)·cancel(...)·remaining(dropId): Int?.
  • ReservationResult(sealed interface): Admitted·AlreadyReserved·SoldOut·Throttled·PerUserLimitExceeded(limit).
  • 계약 의미 주석: reserve는 원자 판정(FR-8 소진 거부 먼저 → FR-7 완충 permit 획득), Admitted 시 permit 보유. confirmSuccess=성공(DECR 유지, permit 반납), cancel=실패(DECR·1인 카운트 복원, permit 반납).
  • Redis 상세(키·TTL·Lua)는 이 티켓 범위 아님 — private-redis-implementer 후속. 이 티켓은 순수 interface·sealed 타입만.

의존

  • 없음 (선행 병목)

다이어그램

클래스 의존

flowchart LR
    DropReservationStore -.->|반환| ReservationResult
    ReservationResult --> Admitted
    ReservationResult --> SoldOut
    ReservationResult --> Throttled
    ReservationResult --> PerUserLimitExceeded
    ReservationResult --> AlreadyReserved

테스트 케이스

  • ReservationResult sealed의 5개 분기(Admitted/AlreadyReserved/SoldOut/Throttled/PerUserLimitExceeded)가 when 전수 분기로 처리된다
  • PerUserLimitExceeded는 한도값(limit)을 노출한다
  • DropReservationStore interface가 domain 레이어에 위치하고 infrastructure를 import하지 않는다 (컴파일·패키지 검증)