feat: 설계 문서 추가

This commit is contained in:
DongHyeonka
2026-08-13 21:09:52 +09:00
parent 0a6dd0e419
commit 3b5aee50e3
33 changed files with 45861 additions and 0 deletions
@@ -0,0 +1,5 @@
e0703a77df8aac482823491d4f6ee43af1eace6287444a6006adb1e4f268e15c docs/superpowers/specs/2026-08-10-messaging-platform-design.md
4ad5d445f74bede368c75d482fd2adcf61ff1c2dbe93f918a4719bb1de1f7eee docs/superpowers/plans/2026-08-10-messaging-platform-implementation-plan.md
f1f8289d07a8f70c0b113349c4e14671b049c14f25d7e28f28ac71b4677960bd VALIDATION.md
3fc835294e07588cf0c854a6182e3d2fc02903aca29eae5f6f951a58524b81eb validate_messaging_docs.py
592a7cebd442da3bbc7cf822a7bacc492c412b9b84f82ea90c0d867a12f03b90 README.md
+55
View File
@@ -0,0 +1,55 @@
# Messaging Platform Superpowers Package
이 패키지는 `Java/Spring Messaging 플랫폼 심층 리서치`를 구현 기준으로 변환한 설계서와 구현 계획서다.
## 포함 파일
```text
docs/superpowers/specs/2026-08-10-messaging-platform-design.md
docs/superpowers/plans/2026-08-10-messaging-platform-implementation-plan.md
VALIDATION.md
validate_messaging_docs.py
MANIFEST.sha256
```
## 설계 경계
- 자체 `messaging-core`가 공개 계약을 소유한다.
- Kafka 4.2+/4.3.x와 RabbitMQ 4.3.x는 Stable Adapter다.
- Kafka Share Group, Pulsar 4.0 LTS·4.2, NATS JetStream 2.14.x는 Experimental Adapter다.
- 공통 `EXACTLY_ONCE` 또는 전역 순서 옵션을 제공하지 않는다.
- publish 결과는 `CONFIRMED`, `REJECTED`, `AMBIGUOUS`와 broker evidence로 표현한다.
- M1 Typed, M2 Advanced, M3 Native Capability, M4 Admin Plane을 분리한다.
- retry·DLQ·redrive에서 logical `messageId`를 유지한다.
- DLQ publish 확인 전에 source message를 settlement하지 않는다.
- Transactional Outbox, Inbox, Idempotent Consumer, Claim Check를 Reliability 모듈로 분리한다.
## 구현 가정
실제 Backend Skeleton 저장소가 입력에 포함되지 않았기 때문에 계획은 다음 기준을 사용한다.
- Java 21
- Gradle Kotlin DSL
- root package: `io.backend.skeleton.messaging`
- module root: `modules/messaging`
- PostgreSQL 16, Flyway, Spring JDBC/JPA
- JUnit 5, AssertJ, ArchUnit, Testcontainers, Toxiproxy
- Spring Framework 6.2 공통 호환선과 Spring 7.0 호환성 job
실제 저장소 구조가 다르면 파일 경로와 dependency catalog만 매핑한다. 공개 계약, 모듈 의존 방향, 신뢰성 상태 모델과 검증 기준은 그대로 유지한다.
## 문서 검증
패키지 루트에서 다음 명령을 실행한다.
```bash
./validate_messaging_docs.py \
docs/superpowers/specs/2026-08-10-messaging-platform-design.md \
docs/superpowers/plans/2026-08-10-messaging-platform-implementation-plan.md
```
`VALIDATION.md`는 문서 구조, Task 1~44 연속성, TDD 단계, 필수 설계 계약, placeholder, 중복 파일 경로를 확인한 정적 검증 결과다.
## 검증 한계
현재 검증은 설계·계획 문서에 대한 정적 검증이다. 실제 저장소가 제공되지 않아 Gradle compile, broker 통합 테스트, chaos test, 성능 인증은 실행하지 않았다. 구현 계획의 각 Task가 해당 실행 검증을 추가하도록 구성되어 있다.
+432
View File
@@ -0,0 +1,432 @@
# Messaging Superpowers 문서 정적 검증
- 설계서: `messaging-platform-design.md` — 2,608행, 74,649 bytes
- 계획서: `messaging-platform-implementation-plan.md` — 5,056행, 200,320 bytes
- Task 수: 44
- Create 경로 수: 356
- 검증 항목 수: 422
## 결과: PASS
- PASS: 설계서가 2,000행 이상이다
- PASS: 구현 계획서가 4,000행 이상이다
- PASS: 설계서 Markdown 코드 블록이 균형을 이룬다
- PASS: 계획서 Markdown 코드 블록이 균형을 이룬다
- PASS: 설계서에 unresolved todo marker가 없다
- PASS: 계획서에 unresolved todo marker가 없다
- PASS: 설계서에 unresolved tbd marker가 없다
- PASS: 계획서에 unresolved tbd marker가 없다
- PASS: 설계서에 unresolved fix marker가 없다
- PASS: 계획서에 unresolved fix marker가 없다
- PASS: 설계서에 placeholder ADR number가 없다
- PASS: 계획서에 placeholder ADR number가 없다
- PASS: 설계서에 wildcard build path가 없다
- PASS: 계획서에 wildcard build path가 없다
- PASS: 설계서에 deferred implementation phrase가 없다
- PASS: 계획서에 deferred implementation phrase가 없다
- PASS: 설계서가 필수 항목 'M1 Typed Messaging API'을 포함한다
- PASS: 설계서가 필수 항목 'M2 Advanced API'을 포함한다
- PASS: 설계서가 필수 항목 'M3 Native Capability'을 포함한다
- PASS: 설계서가 필수 항목 'M4 Admin Plane'을 포함한다
- PASS: 설계서가 필수 항목 'PublishCompletion'을 포함한다
- PASS: 설계서가 필수 항목 'AMBIGUOUS'을 포함한다
- PASS: 설계서가 필수 항목 'MessageEnvelope'을 포함한다
- PASS: 설계서가 필수 항목 'DeliveryGuarantee'을 포함한다
- PASS: 설계서가 필수 항목 'OrderingScope'을 포함한다
- PASS: 설계서가 필수 항목 'Retry Policy Engine'을 포함한다
- PASS: 설계서가 필수 항목 'DLQ·Parking·Redrive'을 포함한다
- PASS: 설계서가 필수 항목 'Kafka Stable Adapter'을 포함한다
- PASS: 설계서가 필수 항목 'RabbitMQ Stable Adapter'을 포함한다
- PASS: 설계서가 필수 항목 'Transactional Outbox'을 포함한다
- PASS: 설계서가 필수 항목 'Inbox와 Idempotent Consumer'을 포함한다
- PASS: 설계서가 필수 항목 'Claim Check'을 포함한다
- PASS: 설계서가 필수 항목 'Pulsar Experimental Adapter'을 포함한다
- PASS: 설계서가 필수 항목 'NATS JetStream Experimental Adapter'을 포함한다
- PASS: 설계서가 필수 항목 'Spring Cloud Stream Bridge'을 포함한다
- PASS: 설계서가 필수 항목 'Security'을 포함한다
- PASS: 설계서가 필수 항목 'Observability'을 포함한다
- PASS: 설계서가 필수 항목 '호환성 인증 매트릭스'을 포함한다
- PASS: 설계서가 필수 항목 '비지원 범위'을 포함한다
- PASS: 설계서가 필수 항목 '완료 정의'을 포함한다
- PASS: 공통 DeliveryGuarantee가 두 가지 보장만 선언한다
- PASS: 공통 DeliveryGuarantee enum에 EXACTLY_ONCE를 선언하지 않는다
- PASS: 공통 OrderingScope enum에 GLOBAL을 선언하지 않는다
- PASS: DLQ confirm 후 source settlement 순서를 명시한다
- PASS: retry와 reliability에서 동일 message ID를 유지한다
- PASS: Task 번호가 1부터 44까지 연속이다
- PASS: Task 1가 '**Files:**'을 포함한다
- PASS: Task 1가 '**Interfaces:**'을 포함한다
- PASS: Task 1가 'Step 1'을 포함한다
- PASS: Task 1가 'Step 2'을 포함한다
- PASS: Task 1가 'Step 3'을 포함한다
- PASS: Task 1가 'Step 4'을 포함한다
- PASS: Task 1가 'Step 5'을 포함한다
- PASS: Task 1가 'git commit -m'을 포함한다
- PASS: Task 2가 '**Files:**'을 포함한다
- PASS: Task 2가 '**Interfaces:**'을 포함한다
- PASS: Task 2가 'Step 1'을 포함한다
- PASS: Task 2가 'Step 2'을 포함한다
- PASS: Task 2가 'Step 3'을 포함한다
- PASS: Task 2가 'Step 4'을 포함한다
- PASS: Task 2가 'Step 5'을 포함한다
- PASS: Task 2가 'git commit -m'을 포함한다
- PASS: Task 3가 '**Files:**'을 포함한다
- PASS: Task 3가 '**Interfaces:**'을 포함한다
- PASS: Task 3가 'Step 1'을 포함한다
- PASS: Task 3가 'Step 2'을 포함한다
- PASS: Task 3가 'Step 3'을 포함한다
- PASS: Task 3가 'Step 4'을 포함한다
- PASS: Task 3가 'Step 5'을 포함한다
- PASS: Task 3가 'git commit -m'을 포함한다
- PASS: Task 4가 '**Files:**'을 포함한다
- PASS: Task 4가 '**Interfaces:**'을 포함한다
- PASS: Task 4가 'Step 1'을 포함한다
- PASS: Task 4가 'Step 2'을 포함한다
- PASS: Task 4가 'Step 3'을 포함한다
- PASS: Task 4가 'Step 4'을 포함한다
- PASS: Task 4가 'Step 5'을 포함한다
- PASS: Task 4가 'git commit -m'을 포함한다
- PASS: Task 5가 '**Files:**'을 포함한다
- PASS: Task 5가 '**Interfaces:**'을 포함한다
- PASS: Task 5가 'Step 1'을 포함한다
- PASS: Task 5가 'Step 2'을 포함한다
- PASS: Task 5가 'Step 3'을 포함한다
- PASS: Task 5가 'Step 4'을 포함한다
- PASS: Task 5가 'Step 5'을 포함한다
- PASS: Task 5가 'git commit -m'을 포함한다
- PASS: Task 6가 '**Files:**'을 포함한다
- PASS: Task 6가 '**Interfaces:**'을 포함한다
- PASS: Task 6가 'Step 1'을 포함한다
- PASS: Task 6가 'Step 2'을 포함한다
- PASS: Task 6가 'Step 3'을 포함한다
- PASS: Task 6가 'Step 4'을 포함한다
- PASS: Task 6가 'Step 5'을 포함한다
- PASS: Task 6가 'git commit -m'을 포함한다
- PASS: Task 7가 '**Files:**'을 포함한다
- PASS: Task 7가 '**Interfaces:**'을 포함한다
- PASS: Task 7가 'Step 1'을 포함한다
- PASS: Task 7가 'Step 2'을 포함한다
- PASS: Task 7가 'Step 3'을 포함한다
- PASS: Task 7가 'Step 4'을 포함한다
- PASS: Task 7가 'Step 5'을 포함한다
- PASS: Task 7가 'git commit -m'을 포함한다
- PASS: Task 8가 '**Files:**'을 포함한다
- PASS: Task 8가 '**Interfaces:**'을 포함한다
- PASS: Task 8가 'Step 1'을 포함한다
- PASS: Task 8가 'Step 2'을 포함한다
- PASS: Task 8가 'Step 3'을 포함한다
- PASS: Task 8가 'Step 4'을 포함한다
- PASS: Task 8가 'Step 5'을 포함한다
- PASS: Task 8가 'git commit -m'을 포함한다
- PASS: Task 9가 '**Files:**'을 포함한다
- PASS: Task 9가 '**Interfaces:**'을 포함한다
- PASS: Task 9가 'Step 1'을 포함한다
- PASS: Task 9가 'Step 2'을 포함한다
- PASS: Task 9가 'Step 3'을 포함한다
- PASS: Task 9가 'Step 4'을 포함한다
- PASS: Task 9가 'Step 5'을 포함한다
- PASS: Task 9가 'git commit -m'을 포함한다
- PASS: Task 10가 '**Files:**'을 포함한다
- PASS: Task 10가 '**Interfaces:**'을 포함한다
- PASS: Task 10가 'Step 1'을 포함한다
- PASS: Task 10가 'Step 2'을 포함한다
- PASS: Task 10가 'Step 3'을 포함한다
- PASS: Task 10가 'Step 4'을 포함한다
- PASS: Task 10가 'Step 5'을 포함한다
- PASS: Task 10가 'git commit -m'을 포함한다
- PASS: Task 11가 '**Files:**'을 포함한다
- PASS: Task 11가 '**Interfaces:**'을 포함한다
- PASS: Task 11가 'Step 1'을 포함한다
- PASS: Task 11가 'Step 2'을 포함한다
- PASS: Task 11가 'Step 3'을 포함한다
- PASS: Task 11가 'Step 4'을 포함한다
- PASS: Task 11가 'Step 5'을 포함한다
- PASS: Task 11가 'git commit -m'을 포함한다
- PASS: Task 12가 '**Files:**'을 포함한다
- PASS: Task 12가 '**Interfaces:**'을 포함한다
- PASS: Task 12가 'Step 1'을 포함한다
- PASS: Task 12가 'Step 2'을 포함한다
- PASS: Task 12가 'Step 3'을 포함한다
- PASS: Task 12가 'Step 4'을 포함한다
- PASS: Task 12가 'Step 5'을 포함한다
- PASS: Task 12가 'git commit -m'을 포함한다
- PASS: Task 13가 '**Files:**'을 포함한다
- PASS: Task 13가 '**Interfaces:**'을 포함한다
- PASS: Task 13가 'Step 1'을 포함한다
- PASS: Task 13가 'Step 2'을 포함한다
- PASS: Task 13가 'Step 3'을 포함한다
- PASS: Task 13가 'Step 4'을 포함한다
- PASS: Task 13가 'Step 5'을 포함한다
- PASS: Task 13가 'git commit -m'을 포함한다
- PASS: Task 14가 '**Files:**'을 포함한다
- PASS: Task 14가 '**Interfaces:**'을 포함한다
- PASS: Task 14가 'Step 1'을 포함한다
- PASS: Task 14가 'Step 2'을 포함한다
- PASS: Task 14가 'Step 3'을 포함한다
- PASS: Task 14가 'Step 4'을 포함한다
- PASS: Task 14가 'Step 5'을 포함한다
- PASS: Task 14가 'git commit -m'을 포함한다
- PASS: Task 15가 '**Files:**'을 포함한다
- PASS: Task 15가 '**Interfaces:**'을 포함한다
- PASS: Task 15가 'Step 1'을 포함한다
- PASS: Task 15가 'Step 2'을 포함한다
- PASS: Task 15가 'Step 3'을 포함한다
- PASS: Task 15가 'Step 4'을 포함한다
- PASS: Task 15가 'Step 5'을 포함한다
- PASS: Task 15가 'git commit -m'을 포함한다
- PASS: Task 16가 '**Files:**'을 포함한다
- PASS: Task 16가 '**Interfaces:**'을 포함한다
- PASS: Task 16가 'Step 1'을 포함한다
- PASS: Task 16가 'Step 2'을 포함한다
- PASS: Task 16가 'Step 3'을 포함한다
- PASS: Task 16가 'Step 4'을 포함한다
- PASS: Task 16가 'Step 5'을 포함한다
- PASS: Task 16가 'git commit -m'을 포함한다
- PASS: Task 17가 '**Files:**'을 포함한다
- PASS: Task 17가 '**Interfaces:**'을 포함한다
- PASS: Task 17가 'Step 1'을 포함한다
- PASS: Task 17가 'Step 2'을 포함한다
- PASS: Task 17가 'Step 3'을 포함한다
- PASS: Task 17가 'Step 4'을 포함한다
- PASS: Task 17가 'Step 5'을 포함한다
- PASS: Task 17가 'git commit -m'을 포함한다
- PASS: Task 18가 '**Files:**'을 포함한다
- PASS: Task 18가 '**Interfaces:**'을 포함한다
- PASS: Task 18가 'Step 1'을 포함한다
- PASS: Task 18가 'Step 2'을 포함한다
- PASS: Task 18가 'Step 3'을 포함한다
- PASS: Task 18가 'Step 4'을 포함한다
- PASS: Task 18가 'Step 5'을 포함한다
- PASS: Task 18가 'git commit -m'을 포함한다
- PASS: Task 19가 '**Files:**'을 포함한다
- PASS: Task 19가 '**Interfaces:**'을 포함한다
- PASS: Task 19가 'Step 1'을 포함한다
- PASS: Task 19가 'Step 2'을 포함한다
- PASS: Task 19가 'Step 3'을 포함한다
- PASS: Task 19가 'Step 4'을 포함한다
- PASS: Task 19가 'Step 5'을 포함한다
- PASS: Task 19가 'git commit -m'을 포함한다
- PASS: Task 20가 '**Files:**'을 포함한다
- PASS: Task 20가 '**Interfaces:**'을 포함한다
- PASS: Task 20가 'Step 1'을 포함한다
- PASS: Task 20가 'Step 2'을 포함한다
- PASS: Task 20가 'Step 3'을 포함한다
- PASS: Task 20가 'Step 4'을 포함한다
- PASS: Task 20가 'Step 5'을 포함한다
- PASS: Task 20가 'git commit -m'을 포함한다
- PASS: Task 21가 '**Files:**'을 포함한다
- PASS: Task 21가 '**Interfaces:**'을 포함한다
- PASS: Task 21가 'Step 1'을 포함한다
- PASS: Task 21가 'Step 2'을 포함한다
- PASS: Task 21가 'Step 3'을 포함한다
- PASS: Task 21가 'Step 4'을 포함한다
- PASS: Task 21가 'Step 5'을 포함한다
- PASS: Task 21가 'git commit -m'을 포함한다
- PASS: Task 22가 '**Files:**'을 포함한다
- PASS: Task 22가 '**Interfaces:**'을 포함한다
- PASS: Task 22가 'Step 1'을 포함한다
- PASS: Task 22가 'Step 2'을 포함한다
- PASS: Task 22가 'Step 3'을 포함한다
- PASS: Task 22가 'Step 4'을 포함한다
- PASS: Task 22가 'Step 5'을 포함한다
- PASS: Task 22가 'git commit -m'을 포함한다
- PASS: Task 23가 '**Files:**'을 포함한다
- PASS: Task 23가 '**Interfaces:**'을 포함한다
- PASS: Task 23가 'Step 1'을 포함한다
- PASS: Task 23가 'Step 2'을 포함한다
- PASS: Task 23가 'Step 3'을 포함한다
- PASS: Task 23가 'Step 4'을 포함한다
- PASS: Task 23가 'Step 5'을 포함한다
- PASS: Task 23가 'git commit -m'을 포함한다
- PASS: Task 24가 '**Files:**'을 포함한다
- PASS: Task 24가 '**Interfaces:**'을 포함한다
- PASS: Task 24가 'Step 1'을 포함한다
- PASS: Task 24가 'Step 2'을 포함한다
- PASS: Task 24가 'Step 3'을 포함한다
- PASS: Task 24가 'Step 4'을 포함한다
- PASS: Task 24가 'Step 5'을 포함한다
- PASS: Task 24가 'git commit -m'을 포함한다
- PASS: Task 25가 '**Files:**'을 포함한다
- PASS: Task 25가 '**Interfaces:**'을 포함한다
- PASS: Task 25가 'Step 1'을 포함한다
- PASS: Task 25가 'Step 2'을 포함한다
- PASS: Task 25가 'Step 3'을 포함한다
- PASS: Task 25가 'Step 4'을 포함한다
- PASS: Task 25가 'Step 5'을 포함한다
- PASS: Task 25가 'git commit -m'을 포함한다
- PASS: Task 26가 '**Files:**'을 포함한다
- PASS: Task 26가 '**Interfaces:**'을 포함한다
- PASS: Task 26가 'Step 1'을 포함한다
- PASS: Task 26가 'Step 2'을 포함한다
- PASS: Task 26가 'Step 3'을 포함한다
- PASS: Task 26가 'Step 4'을 포함한다
- PASS: Task 26가 'Step 5'을 포함한다
- PASS: Task 26가 'git commit -m'을 포함한다
- PASS: Task 27가 '**Files:**'을 포함한다
- PASS: Task 27가 '**Interfaces:**'을 포함한다
- PASS: Task 27가 'Step 1'을 포함한다
- PASS: Task 27가 'Step 2'을 포함한다
- PASS: Task 27가 'Step 3'을 포함한다
- PASS: Task 27가 'Step 4'을 포함한다
- PASS: Task 27가 'Step 5'을 포함한다
- PASS: Task 27가 'git commit -m'을 포함한다
- PASS: Task 28가 '**Files:**'을 포함한다
- PASS: Task 28가 '**Interfaces:**'을 포함한다
- PASS: Task 28가 'Step 1'을 포함한다
- PASS: Task 28가 'Step 2'을 포함한다
- PASS: Task 28가 'Step 3'을 포함한다
- PASS: Task 28가 'Step 4'을 포함한다
- PASS: Task 28가 'Step 5'을 포함한다
- PASS: Task 28가 'git commit -m'을 포함한다
- PASS: Task 29가 '**Files:**'을 포함한다
- PASS: Task 29가 '**Interfaces:**'을 포함한다
- PASS: Task 29가 'Step 1'을 포함한다
- PASS: Task 29가 'Step 2'을 포함한다
- PASS: Task 29가 'Step 3'을 포함한다
- PASS: Task 29가 'Step 4'을 포함한다
- PASS: Task 29가 'Step 5'을 포함한다
- PASS: Task 29가 'git commit -m'을 포함한다
- PASS: Task 30가 '**Files:**'을 포함한다
- PASS: Task 30가 '**Interfaces:**'을 포함한다
- PASS: Task 30가 'Step 1'을 포함한다
- PASS: Task 30가 'Step 2'을 포함한다
- PASS: Task 30가 'Step 3'을 포함한다
- PASS: Task 30가 'Step 4'을 포함한다
- PASS: Task 30가 'Step 5'을 포함한다
- PASS: Task 30가 'git commit -m'을 포함한다
- PASS: Task 31가 '**Files:**'을 포함한다
- PASS: Task 31가 '**Interfaces:**'을 포함한다
- PASS: Task 31가 'Step 1'을 포함한다
- PASS: Task 31가 'Step 2'을 포함한다
- PASS: Task 31가 'Step 3'을 포함한다
- PASS: Task 31가 'Step 4'을 포함한다
- PASS: Task 31가 'Step 5'을 포함한다
- PASS: Task 31가 'git commit -m'을 포함한다
- PASS: Task 32가 '**Files:**'을 포함한다
- PASS: Task 32가 '**Interfaces:**'을 포함한다
- PASS: Task 32가 'Step 1'을 포함한다
- PASS: Task 32가 'Step 2'을 포함한다
- PASS: Task 32가 'Step 3'을 포함한다
- PASS: Task 32가 'Step 4'을 포함한다
- PASS: Task 32가 'Step 5'을 포함한다
- PASS: Task 32가 'git commit -m'을 포함한다
- PASS: Task 33가 '**Files:**'을 포함한다
- PASS: Task 33가 '**Interfaces:**'을 포함한다
- PASS: Task 33가 'Step 1'을 포함한다
- PASS: Task 33가 'Step 2'을 포함한다
- PASS: Task 33가 'Step 3'을 포함한다
- PASS: Task 33가 'Step 4'을 포함한다
- PASS: Task 33가 'Step 5'을 포함한다
- PASS: Task 33가 'git commit -m'을 포함한다
- PASS: Task 34가 '**Files:**'을 포함한다
- PASS: Task 34가 '**Interfaces:**'을 포함한다
- PASS: Task 34가 'Step 1'을 포함한다
- PASS: Task 34가 'Step 2'을 포함한다
- PASS: Task 34가 'Step 3'을 포함한다
- PASS: Task 34가 'Step 4'을 포함한다
- PASS: Task 34가 'Step 5'을 포함한다
- PASS: Task 34가 'git commit -m'을 포함한다
- PASS: Task 35가 '**Files:**'을 포함한다
- PASS: Task 35가 '**Interfaces:**'을 포함한다
- PASS: Task 35가 'Step 1'을 포함한다
- PASS: Task 35가 'Step 2'을 포함한다
- PASS: Task 35가 'Step 3'을 포함한다
- PASS: Task 35가 'Step 4'을 포함한다
- PASS: Task 35가 'Step 5'을 포함한다
- PASS: Task 35가 'git commit -m'을 포함한다
- PASS: Task 36가 '**Files:**'을 포함한다
- PASS: Task 36가 '**Interfaces:**'을 포함한다
- PASS: Task 36가 'Step 1'을 포함한다
- PASS: Task 36가 'Step 2'을 포함한다
- PASS: Task 36가 'Step 3'을 포함한다
- PASS: Task 36가 'Step 4'을 포함한다
- PASS: Task 36가 'Step 5'을 포함한다
- PASS: Task 36가 'git commit -m'을 포함한다
- PASS: Task 37가 '**Files:**'을 포함한다
- PASS: Task 37가 '**Interfaces:**'을 포함한다
- PASS: Task 37가 'Step 1'을 포함한다
- PASS: Task 37가 'Step 2'을 포함한다
- PASS: Task 37가 'Step 3'을 포함한다
- PASS: Task 37가 'Step 4'을 포함한다
- PASS: Task 37가 'Step 5'을 포함한다
- PASS: Task 37가 'git commit -m'을 포함한다
- PASS: Task 38가 '**Files:**'을 포함한다
- PASS: Task 38가 '**Interfaces:**'을 포함한다
- PASS: Task 38가 'Step 1'을 포함한다
- PASS: Task 38가 'Step 2'을 포함한다
- PASS: Task 38가 'Step 3'을 포함한다
- PASS: Task 38가 'Step 4'을 포함한다
- PASS: Task 38가 'Step 5'을 포함한다
- PASS: Task 38가 'git commit -m'을 포함한다
- PASS: Task 39가 '**Files:**'을 포함한다
- PASS: Task 39가 '**Interfaces:**'을 포함한다
- PASS: Task 39가 'Step 1'을 포함한다
- PASS: Task 39가 'Step 2'을 포함한다
- PASS: Task 39가 'Step 3'을 포함한다
- PASS: Task 39가 'Step 4'을 포함한다
- PASS: Task 39가 'Step 5'을 포함한다
- PASS: Task 39가 'git commit -m'을 포함한다
- PASS: Task 40가 '**Files:**'을 포함한다
- PASS: Task 40가 '**Interfaces:**'을 포함한다
- PASS: Task 40가 'Step 1'을 포함한다
- PASS: Task 40가 'Step 2'을 포함한다
- PASS: Task 40가 'Step 3'을 포함한다
- PASS: Task 40가 'Step 4'을 포함한다
- PASS: Task 40가 'Step 5'을 포함한다
- PASS: Task 40가 'git commit -m'을 포함한다
- PASS: Task 41가 '**Files:**'을 포함한다
- PASS: Task 41가 '**Interfaces:**'을 포함한다
- PASS: Task 41가 'Step 1'을 포함한다
- PASS: Task 41가 'Step 2'을 포함한다
- PASS: Task 41가 'Step 3'을 포함한다
- PASS: Task 41가 'Step 4'을 포함한다
- PASS: Task 41가 'Step 5'을 포함한다
- PASS: Task 41가 'git commit -m'을 포함한다
- PASS: Task 42가 '**Files:**'을 포함한다
- PASS: Task 42가 '**Interfaces:**'을 포함한다
- PASS: Task 42가 'Step 1'을 포함한다
- PASS: Task 42가 'Step 2'을 포함한다
- PASS: Task 42가 'Step 3'을 포함한다
- PASS: Task 42가 'Step 4'을 포함한다
- PASS: Task 42가 'Step 5'을 포함한다
- PASS: Task 42가 'git commit -m'을 포함한다
- PASS: Task 43가 '**Files:**'을 포함한다
- PASS: Task 43가 '**Interfaces:**'을 포함한다
- PASS: Task 43가 'Step 1'을 포함한다
- PASS: Task 43가 'Step 2'을 포함한다
- PASS: Task 43가 'Step 3'을 포함한다
- PASS: Task 43가 'Step 4'을 포함한다
- PASS: Task 43가 'Step 5'을 포함한다
- PASS: Task 43가 'git commit -m'을 포함한다
- PASS: Task 44가 '**Files:**'을 포함한다
- PASS: Task 44가 '**Interfaces:**'을 포함한다
- PASS: Task 44가 'Step 1'을 포함한다
- PASS: Task 44가 'Step 2'을 포함한다
- PASS: Task 44가 'Step 3'을 포함한다
- PASS: Task 44가 'Step 4'을 포함한다
- PASS: Task 44가 'Step 5'을 포함한다
- PASS: Task 44가 'git commit -m'을 포함한다
- PASS: 중복된 Create 파일 경로가 없다
- PASS: Create 파일 경로에 wildcard가 없다
- PASS: 계획서가 필수 작업 'Kafka Producer Adapter와 Publish Evidence'을 포함한다
- PASS: 계획서가 필수 작업 'Kafka Consumer Group, Partition Coordinator'을 포함한다
- PASS: 계획서가 필수 작업 'Kafka Native Transaction Capability'을 포함한다
- PASS: 계획서가 필수 작업 'Kafka Share Group Experimental Adapter'을 포함한다
- PASS: 계획서가 필수 작업 'Rabbit Publisher Confirm·Return Evidence Adapter'을 포함한다
- PASS: 계획서가 필수 작업 'Rabbit Consumer Manual ACK'을 포함한다
- PASS: 계획서가 필수 작업 'Transactional Outbox Repository'을 포함한다
- PASS: 계획서가 필수 작업 'Inbox Transactional Idempotent Consumer'을 포함한다
- PASS: 계획서가 필수 작업 'Debezium Outbox Event Router'을 포함한다
- PASS: 계획서가 필수 작업 'Pulsar Experimental Adapter'을 포함한다
- PASS: 계획서가 필수 작업 'NATS JetStream Experimental Adapter'을 포함한다
- PASS: 계획서가 필수 작업 'Spring Cloud Stream Optional Bridge'을 포함한다
- PASS: 계획서가 필수 작업 'Global Backpressure'을 포함한다
- PASS: 계획서가 필수 작업 'Cross-broker 장애·보안·Reliability Contract Suite'을 포함한다
- PASS: 계획서가 필수 작업 '성능 인증, Compatibility Matrix'을 포함한다
- PASS: 계획서가 필수 작업 '지원 문서, Runbook, ADR, Release Gate'을 포함한다
- PASS: 계획서가 message identity 보존을 명시한다
- PASS: 계획서가 DLQ 실패 시 source ACK 금지를 명시한다
- PASS: 계획서가 credential 분리를 명시한다
- PASS: Stable chaos aggregate task가 계획에 존재한다
- PASS: performance aggregate task가 계획에 존재한다
- PASS: compatibility aggregate task가 계획에 존재한다
+164
View File
@@ -0,0 +1,164 @@
#!/usr/bin/env python3
from __future__ import annotations
import re
import sys
from collections import Counter
from pathlib import Path
DESIGN = Path(sys.argv[1]) if len(sys.argv) > 1 else Path("messaging-platform-design.md")
PLAN = Path(sys.argv[2]) if len(sys.argv) > 2 else Path("messaging-platform-implementation-plan.md")
errors: list[str] = []
checks: list[str] = []
def require(condition: bool, message: str) -> None:
if condition:
checks.append(message)
else:
errors.append(message)
def balanced_fences(text: str) -> bool:
return len(re.findall(r"^```", text, re.MULTILINE)) % 2 == 0
def line_count(text: str) -> int:
return len(text.splitlines())
design = DESIGN.read_text(encoding="utf-8")
plan = PLAN.read_text(encoding="utf-8")
require(line_count(design) >= 2_000, "설계서가 2,000행 이상이다")
require(line_count(plan) >= 4_000, "구현 계획서가 4,000행 이상이다")
require(balanced_fences(design), "설계서 Markdown 코드 블록이 균형을 이룬다")
require(balanced_fences(plan), "계획서 Markdown 코드 블록이 균형을 이룬다")
placeholder_patterns = {
"unresolved todo marker": r"\bT[O]DO\b",
"unresolved tbd marker": r"\bT[B]D\b",
"unresolved fix marker": r"\bF[I]XME\b",
"placeholder ADR number": r"ADR-X{2,}",
"wildcard build path": r"modules/messaging/\*/build\.gradle\.kts",
"deferred implementation phrase": r"implement\s+later|fill\s+in\s+details|similar\s+to\s+Task",
}
for name, pattern in placeholder_patterns.items():
require(not re.search(pattern, design, re.IGNORECASE), f"설계서에 {name}가 없다")
require(not re.search(pattern, plan, re.IGNORECASE), f"계획서에 {name}가 없다")
required_design_terms = [
"M1 Typed Messaging API",
"M2 Advanced API",
"M3 Native Capability",
"M4 Admin Plane",
"PublishCompletion",
"AMBIGUOUS",
"MessageEnvelope",
"DeliveryGuarantee",
"OrderingScope",
"Retry Policy Engine",
"DLQ·Parking·Redrive",
"Kafka Stable Adapter",
"RabbitMQ Stable Adapter",
"Transactional Outbox",
"Inbox와 Idempotent Consumer",
"Claim Check",
"Pulsar Experimental Adapter",
"NATS JetStream Experimental Adapter",
"Spring Cloud Stream Bridge",
"Security",
"Observability",
"호환성 인증 매트릭스",
"비지원 범위",
"완료 정의",
]
for term in required_design_terms:
require(term in design, f"설계서가 필수 항목 '{term}'을 포함한다")
require("AT_MOST_ONCE,\n AT_LEAST_ONCE" in design, "공통 DeliveryGuarantee가 두 가지 보장만 선언한다")
delivery_match = re.search(r"public enum DeliveryGuarantee \{(?P<body>.*?)\n\}", design, re.DOTALL)
ordering_match = re.search(r"public enum OrderingScope \{(?P<body>.*?)\n\}", design, re.DOTALL)
require(delivery_match is not None and "EXACTLY_ONCE" not in delivery_match.group("body"), "공통 DeliveryGuarantee enum에 EXACTLY_ONCE를 선언하지 않는다")
require(ordering_match is not None and "GLOBAL" not in ordering_match.group("body"), "공통 OrderingScope enum에 GLOBAL을 선언하지 않는다")
require("DLQ broker confirmation 확인\n→ source settlement" in design, "DLQ confirm 후 source settlement 순서를 명시한다")
require("같은 `messageId`" in design, "retry와 reliability에서 동일 message ID를 유지한다")
# Plan task structure.
task_numbers = [int(value) for value in re.findall(r"^### Task (\d+):", plan, re.MULTILINE)]
require(task_numbers == list(range(1, 45)), "Task 번호가 1부터 44까지 연속이다")
for task_number in task_numbers:
start = plan.index(f"### Task {task_number}:")
end = (
plan.index(f"### Task {task_number + 1}:", start)
if task_number < 44
else plan.index("## 3. Plan Self-Review Checklist", start)
)
section = plan[start:end]
for required in (
"**Files:**",
"**Interfaces:**",
"Step 1",
"Step 2",
"Step 3",
"Step 4",
"Step 5",
"git commit -m",
):
require(required in section, f"Task {task_number}'{required}'을 포함한다")
create_paths = re.findall(r"^- Create: `([^`]+)`", plan, re.MULTILINE)
duplicates = [path for path, count in Counter(create_paths).items() if count > 1]
require(not duplicates, "중복된 Create 파일 경로가 없다")
require(all("*" not in path for path in create_paths), "Create 파일 경로에 wildcard가 없다")
required_plan_terms = [
"Kafka Producer Adapter와 Publish Evidence",
"Kafka Consumer Group, Partition Coordinator",
"Kafka Native Transaction Capability",
"Kafka Share Group Experimental Adapter",
"Rabbit Publisher Confirm·Return Evidence Adapter",
"Rabbit Consumer Manual ACK",
"Transactional Outbox Repository",
"Inbox Transactional Idempotent Consumer",
"Debezium Outbox Event Router",
"Pulsar Experimental Adapter",
"NATS JetStream Experimental Adapter",
"Spring Cloud Stream Optional Bridge",
"Global Backpressure",
"Cross-broker 장애·보안·Reliability Contract Suite",
"성능 인증, Compatibility Matrix",
"지원 문서, Runbook, ADR, Release Gate",
]
for term in required_plan_terms:
require(term in plan, f"계획서가 필수 작업 '{term}'을 포함한다")
require("messageId`를 유지" in plan or "message ID를 유지" in plan, "계획서가 message identity 보존을 명시한다")
require("source를 ACK하지 않는다" in plan or "source ACK하지 않는다" in plan, "계획서가 DLQ 실패 시 source ACK 금지를 명시한다")
require("producer, consumer, admin credential" in plan, "계획서가 credential 분리를 명시한다")
require("messagingStableChaos" in plan, "Stable chaos aggregate task가 계획에 존재한다")
require("messagingPerformance" in plan, "performance aggregate task가 계획에 존재한다")
require("messagingCompatibility" in plan, "compatibility aggregate task가 계획에 존재한다")
print("# Messaging Superpowers 문서 정적 검증")
print()
print(f"- 설계서: `{DESIGN}` — {line_count(design):,}행, {len(design.encode('utf-8')):,} bytes")
print(f"- 계획서: `{PLAN}` — {line_count(plan):,}행, {len(plan.encode('utf-8')):,} bytes")
print(f"- Task 수: {len(task_numbers)}")
print(f"- Create 경로 수: {len(create_paths)}")
print(f"- 검증 항목 수: {len(checks) + len(errors)}")
print()
if errors:
print("## 결과: FAIL")
print()
for error in errors:
print(f"- FAIL: {error}")
sys.exit(1)
print("## 결과: PASS")
print()
for check in checks:
print(f"- PASS: {check}")