[BE-01] partner 도메인 모델 (Partner·PartnerApiKey·Repository·Gateway interface)
작업 내용 (설계 의도)
변경 사항
근거 TDD: ../TDD.md “시스템 역할 경계”·“인터페이스 시그니처”·“상태 전이 표”. 후행 티켓 전부가 import하는 partner 도메인 공통 계약을 한 티켓으로 확립한다(연관 병목 묶음).
domain/partner/entity/Partner.kt— Rich Domain. 필드private var,private constructor+create(name, linkedUserId)·reconstitute(...).status: PartnerStatus,linkedUserId: Long. 메서드suspend()·activate()·validateActive()(SUSPENDED면 예외). 시간은 캡슐화 메서드 내부ZonedDateTime.now().domain/partner/entity/PartnerApiKey.kt— Rich Domain.keyHash·status: ApiKeyStatus·revokedAt·lastUsedAt. 메서드revoke()·recordUsage()·isActive().create(partnerId, keyHash)·reconstitute(...).domain/partner/entity/PartnerStatus.kt·ApiKeyStatus.kt— enum, 상태 전이는 enum 내부canTransitTo()캡슐화.domain/partner/exception/*—PartnerSuspendedException(403)·PartnerApiKeyInactiveException(401)·PartnerNotFoundException(404) 등.domain/partner/repository/PartnerRepository.kt·PartnerApiKeyRepository.kt— interface(시그니처는 TDD 확정).domain/partner/gateway/ApiKeyGenerator.kt— interfacegenerateRandomPart()·hash()·matches().
의존
- 없음 (선행 wave)
다이어그램
클래스 의존
flowchart LR Partner["Partner (Entity)"] Key["PartnerApiKey (Entity)"] Repo["PartnerRepository (interface)"] KeyRepo["PartnerApiKeyRepository (interface)"] Gen["ApiKeyGenerator (interface)"] Partner --> Repo Key --> KeyRepo Key --> Gen
테스트 케이스
- ACTIVE Partner에 suspend()를 호출하면 상태가 SUSPENDED로 전이된다.
- SUSPENDED Partner에 activate()를 호출하면 ACTIVE로 전이된다.
- SUSPENDED Partner에 validateActive()를 호출하면 PartnerSuspendedException을 던진다.
- ACTIVE PartnerApiKey에 revoke()를 호출하면 status=REVOKED·revokedAt이 채워진다.
- 이미 REVOKED된 키에 revoke()를 재호출해도 상태가 변하지 않는다(멱등).
- recordUsage() 호출 시 lastUsedAt이 이전 값보다 뒤 시각으로 갱신된다.
- Partner.create는 status=ACTIVE로 생성한다.