--- kind: CONCEPT slug: messaging-reliability-api-c01 title: Outbox 하나로는 부족하다는 것을 타입이 직접 말한다 topic: state-machines-and-ownership project: clean-architecture-backend-template status: 게시 전 sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 rootTreeNode: concept:messaging-reliability-api-c01 evidenceCapturedOn: 2026-09-01 assets: - key: messaging-reliability-api-c01 file: ../../../final/evidence/rendered/messaging-reliability-api-c01.svg - key: messaging-reliability-api-c01-diagram file: ../../../final/assets/diagrams/messaging-reliability-api-c01.svg evidence: - ../../../final/evidence/raw/messaging-reliability-api-c01.txt source: - 원본 분석 절은 analysis/messaging/messaging-reliability-api.md#L51 이다. module: messaging-reliability-api --- # Outbox 하나로는 부족하다는 것을 타입이 직접 말한다 이 leaf는 effectively-once 처리의 계약을 소유한다. 구현이 없고 13개 중 인터페이스 5개, record 5개, enum 3개다. ## 관계 - **계약만 담는 leaf도 계약의 거절 조건은 자기 레인에서 검증한다** 같은 분석 리프에서 끌어낸 규칙이다. - **record의 `equals`를 좁히면 이유를 적는다** 같은 분석 리프에서 끌어낸 규칙이다. - **호출 컨텍스트가 계약이면 그 컨텍스트를 검증할 수단을 함께 정한다** 같은 분석 리프에서 끌어낸 규칙이다. ## 본문 이 leaf는 **effectively-once 처리의 계약**을 소유한다. 구현이 없다 — 13개 중 인터페이스 5개, record 5개, enum 3개이고 실행 가능한 로직은 record 생성자 검증과 `isExpired`/`expiredAt` 술어 정도다. 벤더 의존성 0, 저장소 기술 중립이다. ## 이 리프가 담는 세 메커니즘 :::evidence key="messaging-reliability-api-c01-diagram" alt="리프 경계 안에 Outbox 와 Inbox 와 Claim Check 세 상자가 나란히 들어 있는 구조" caption="이 리프가 담는 세 메커니즘" zoom="false" ::: **Outbox** — dual-write 문제의 답. **Inbox** — 소비 측 중복 제거. **Claim Check** — 브로커 밖 payload 참조. ## OutboxRecord 참조 위치 :::evidence key="messaging-reliability-api-c01" alt="코드베이스에서 OutboxRecord 를 검색한 출력 10줄. 이 기록이 세는 참조가 그 출력에 그대로 보인다." caption="OutboxRecord 코드베이스 검색 — 10줄 · exit 0" zoom="true" ::: ## 타입이 자기 한계를 직접 말한다 셋의 관계를 `OutboxRecord`가 명시한다. **Outbox 하나로는 부족하다는 것을 타입의 javadoc이 직접 말한다.** 이 저장소에서 반복되는 "보장을 과대 진술하지 않는다"의 예다.