[BE-01] LimitedDrop 도메인 모델·상태·Repository·오버셀 이벤트 계약
작업 내용 (설계 의도)
변경 사항
goods 도메인에 한정판 회차 Aggregate Root를 신설한다(근거 TDD: ../TDD.md “도메인 바운디드 컨텍스트 경계 판단”, ADR-002). 후행 티켓(BE-03 도메인 서비스, BE-05 영속화, BE-06 DTO)이 import하는 공통 도메인 계약을 한 wave에서 확립한다.
LimitedDrop(Entity, Rich Domain Model): private 생성자 +create()/reconstitute()팩토리. 필드private var. 대상 productId·openAt·closeAt·limitedQuantity·perUserLimit·status(ZonedDateTime 사용).validatePurchasable():now<openAt이면 TooEarly 예외(openAt 포함),now≥closeAt이면 Closed 예외, status가 SOLD_OUT이면 SoldOut 예외. 시각은 메서드 내부ZonedDateTime.now()로 해결(시간 인자 금지).open()·markSoldOut()·close()상태 전이 —LimitedDropStatus.canTransitTo()캡슐화.LimitedDropStatusenum: SCHEDULED/OPEN/SOLD_OUT/CLOSED +canTransitTo(next).LimitedDropRepositoryinterface(domain):save·findById·findOpenByProductId.LimitedDropOversoldEvent(domain event):dropId·productId·감지 수량.source=oversell·severity=critical태그(⑥ 연계). AggregateRoot domainEvents에 적재.- 예외:
LimitedDropTooEarlyException(openAt 보유),LimitedDropSoldOutException,LimitedDropClosedException,LimitedDropNotFoundException.
의존
- 없음 (선행 병목)
다이어그램
클래스 의존
flowchart LR LimitedDrop --> LimitedDropStatus LimitedDrop --> LimitedDropOversoldEvent LimitedDropRepository -.->|반환| LimitedDrop LimitedDrop --> AggregateRoot["common.AggregateRoot"]
테스트 케이스
- openAt 이전 구매 검증 시 TooEarly 예외가 openAt을 담아 던져진다
- openAt 이후·closeAt 이전·재고 있음이면 validatePurchasable이 통과한다
- SOLD_OUT 상태에서 validatePurchasable은 SoldOut 예외를 던진다
- closeAt 이후 validatePurchasable은 Closed 예외를 던진다
- SCHEDULED→OPEN→SOLD_OUT→CLOSED 전이는 허용되고 CLOSED→OPEN은 canTransitTo가 거부한다
- create는 openAt<closeAt·limitedQuantity>0·perUserLimit>0을 검증하고 위반 시 예외를 던진다
- reconstitute는 검증 없이 필드를 복원한다