[BE-44] 수집 cycle state-write 영속 계약 보완
작업 내용 (설계 의도)
변경 사항
병합된 BE-33에는 aggregate/JPA mapping만 있고 dispatcher가 필요한 prepare/save·active-source claim·terminal failure/budget·SLA cutoff gate 계약이 없다. TDD 20260730-확장-안전-공고수집-배치-tdd.md의 JobPostingCollectionCycleRepository 확장과 CollectionCycleStateWriteDomainService를 추가한다. 이 티켓은 BE-34가 UseCase에서 domain service만 호출하며 active 재검증, lease fencing, 동일 KST 재시도 금지 terminalization을 영속할 수 있게 하는 최소 선행 산출물이다.
CollectionSlaCutoffGate는 posting domain interface로만 정의한다. BE-43이 MySQL SLA header lock 구현체를 제공하고, BE-34는 이 contract만 소비한다. 이 티켓은 dispatcher orchestration·snapshot capture·operation API·config/scheduler wiring을 구현하지 않는다.
의존
- BE-33
- DB-01 cycle/SLA header schema
다이어그램
처리 흐름
sequenceDiagram participant D as StateWriteDomainService participant G as SlaCutoffGate participant R as CycleRepository D->>G: withDailyWriteGate(runDate) G->>R: save/claim/fail/exhaust R-->>D: fenced result
클래스 의존
flowchart LR StateWriteDomainService --> CollectionSlaCutoffGate StateWriteDomainService --> CycleRepository CycleRepositoryImpl -.-> CycleRepository SlaGateImpl -.-> CollectionSlaCutoffGate
테스트 케이스
- createIfAbsent와 save는 같은 source/KST 일자에 하나의 cycle만 유지한다.
- claimReady는 active jobSourceId 집합 밖 cycle을 lease하지 않는다.
- 다른 또는 만료 lease token의 apply/fail/exhaust write는 0건으로 거부된다.
- HTTP/lease failure는 gate 안에서 terminal FAILED로 저장되고 당일 claim 대상에서 제외된다.
- posting budget 초과는 gate 안에서 BUDGET_EXHAUSTED로 저장되고 source health failure를 만들지 않는다.
- 모든 cycle state write는
CollectionSlaCutoffGate를 거치며 BE-43 구현이 없는 경우 domain test는 fake gate로 검증한다.