init: readme 작성 하네스 설계

This commit is contained in:
DongHyeonka
2026-07-24 13:26:18 +09:00
parent 7fb4217f7c
commit c708cbcf9a
317 changed files with 24223 additions and 1 deletions
@@ -0,0 +1,147 @@
# ca-tmpl — 경계를 실행 가능한 규칙으로 만드는 Spring Boot 템플릿
`ca-tmpl`은 Java 21과 Spring Boot 4.0.0을 기준으로 구성된 멀티 모듈 서비스 템플릿입니다. <!-- claim-id: C-STACK-001 -->
이 저장소의 초점은 기능 예제를 많이 제공하는 데 있지 않습니다. domain, application, adapter, bootstrap의 책임을 나누고, 그 경계가 기능 추가 과정에서 무너지지 않도록 Gradle과 ArchUnit 검증을 함께 제공하는 데 있습니다. <!-- claim-id: C-POSITION-001 -->
<!-- section-id: overview -->
## 템플릿 개요
19개 Gradle 모듈이 core, inbound adapter, outbound adapter, composition root, sample 역할로 선언되어 있습니다. <!-- claim-id: C-MODULE-COUNT-001 -->
다음 상황에 특히 잘 맞습니다.
- 새 Java 서비스에서 모듈 경계와 검증 기준을 함께 시작하려는 경우
- HTTP·메시징·캐시·영속성 같은 기술 세부사항을 유스케이스와 분리하려는 경우
- 예제 코드를 제거한 뒤에도 핵심 구조가 독립적으로 성립하는지 자동 검증하려는 경우
반대로 단일 모듈 CRUD 예제나 특정 조직의 운영 정책까지 완성된 배포판이 필요하다면, 이 템플릿의 범위보다 가벼운 시작점 또는 별도의 플랫폼 기준이 더 적합할 수 있습니다.
<!-- section-id: project-value -->
## 저장소가 강제하는 것, 도입자가 결정할 것
| 저장소가 실행 가능하게 강제하는 것 | 도입자가 서비스 맥락에 맞게 결정할 것 |
| --- | --- |
| 모든 선언 모듈을 의존성 정책에 포함하고 허용되지 않은 프로젝트 의존성을 실패시킵니다. <!-- claim-id: C-FORCED-DEPS-001 --> | 실제 도메인 경계와 bounded context |
| application 코드가 adapter·bootstrap·transport·persistence에 의존하지 못하도록 검사합니다. <!-- claim-id: C-FORCED-CODE-001 --> | 사용할 inbound·outbound adapter의 범위 |
| leaf module의 모든 dependency configuration을 STRICT lock mode로 검증합니다. <!-- claim-id: C-FORCED-LOCKS-001 --> | 배포 플랫폼, SLO, 용량과 장애 복구 정책 |
| 같은 핵심 테스트를 `sample-portfolio` 없이 컴파일·실행하는 경로를 제공합니다. <!-- claim-id: C-FORCED-SAMPLE-001 --> | 인증·인가, 데이터 보존, 외부 연동의 서비스별 정책 |
이 구분이 중요합니다. 템플릿은 “어떤 결정을 해야 하는가”와 경계를 지키는 장치를 제공하지만, 서비스 고유의 결정을 대신하지는 않습니다.
<!-- section-id: architecture -->
## 아키텍처와 코드 배치
<!-- visual-id: architecture-dependency-direction -->
다음 그림의 화살표는 런타임 호출 순서가 아니라 허용된 프로젝트 의존 방향을 요약합니다. <!-- claim-id: C-VISUAL-MEANING-001 -->
```mermaid
flowchart LR
Inbound[Inbound adapters<br/>web · gRPC · GraphQL · WebSocket]
Application[application-core<br/>use cases · ports]
Domain[domain-core<br/>business invariants]
Outbound[Outbound adapters<br/>persistence · messaging · cache · integrations]
Shared[shared-contract<br/>operational contracts]
Bootstrap[app-bootstrap<br/>composition root]
Inbound --> Application
Outbound --> Application
Application --> Domain
Inbound --> Shared
Outbound --> Shared
Application --> Shared
Bootstrap --> Inbound
Bootstrap --> Outbound
Bootstrap --> Application
Bootstrap --> Domain
Bootstrap --> Shared
```
| 모듈 그룹 | 코드 배치 기준 |
| --- | --- |
| `domain-core` | 외부 라이브러리 의존성 없이 비즈니스 불변식과 도메인 타입을 둡니다. <!-- claim-id: C-DOMAIN-001 --> |
| `application-core` | `domain-core``shared-contract`에 의존하며 유스케이스와 port를 둡니다. <!-- claim-id: C-APPLICATION-001 --> |
| `adapter:inbound:*` / `adapter:outbound:*` | 전송 계층 입력과 기술별 출력 구현을 core 바깥에 둡니다. <!-- claim-id: C-ADAPTERS-001 --> |
| `shared-contract` | 비즈니스 개념이 아닌 공용 운영 계약을 둡니다. <!-- claim-id: C-SHARED-001 --> |
| `app-bootstrap` | 선택한 core와 adapter를 조립하고 Spring Boot 진입점을 소유합니다. <!-- claim-id: C-BOOTSTRAP-MODULE-001 --> |
| `sample-portfolio` | 템플릿 사용법을 보여주는 참조 구현이며 일반 테스트의 fixture로만 연결됩니다. <!-- claim-id: C-SAMPLE-ROLE-001 --> |
Gradle의 `verifyCleanArchitectureDependencies`는 모듈 간 의존 방향을, `CleanArchitectureTest`는 application 패키지의 adapter·transport 접근과 같은 코드 수준 경계를 검사합니다. <!-- claim-id: C-TWO-LAYERS-001 -->
<!-- section-id: quick-start -->
## 빠른 시작
<!-- feature-developer-experience-contract: first-run success probe = GET /api/healthcheck -->
필요한 도구는 JDK 21과 실행 중인 Docker daemon입니다. 저장소의 도구 버전 파일은 Temurin 21.0.11+10을 지정하고, bootstrap preflight는 Docker CLI가 daemon에 연결되는지 확인합니다. <!-- claim-id: C-PREREQUISITES-001 -->
저장소 루트에서 다음을 실행합니다.
```bash
cd src
./gradlew bootstrap
```
`./gradlew bootstrap`은 전체 소스 컴파일, Docker 확인, 로컬 PostgreSQL과 앱 시작, sample 격리 계약, HTTP smoke check를 순서대로 실행합니다. <!-- claim-id: C-BOOTSTRAP-COMMAND-001 -->
성공 조건은 `http://localhost:8080/api/healthcheck`가 HTTP 200과 `status=UP`을 반환하는 것입니다. <!-- claim-id: C-HEALTH-001 -->
bootstrap은 Compose의 `app``db` 서비스를 백그라운드로 시작합니다. 작업을 마치면 저장소 루트에서 종료합니다. <!-- claim-id: C-BOOTSTRAP-SIDE-EFFECT-001 -->
```bash
cd ..
docker compose -f docker-compose.yml -f docker-compose.local.yml down
```
위 Compose 명령은 저장소에 선언된 base와 local 구성 파일을 함께 사용해 서비스를 종료합니다. <!-- claim-id: C-CLEANUP-001 -->
<!-- section-id: adoption -->
## 실제 프로젝트로 전환하기
한 번에 모든 이름과 모듈을 지우기보다, 각 단계에서 검증 가능한 상태를 유지하는 편이 안전합니다.
1. **식별자를 먼저 정합니다.** Gradle root name은 `ca-skeleton`, Java package root와 main class는 `dev.caskeleton` 아래에 선언되어 있으므로 서비스 이름과 namespace 정책에 맞게 함께 변경합니다. <!-- claim-id: C-IDENTITY-001 -->
2. **도메인과 유스케이스를 core에 세웁니다.** 비즈니스 불변식은 `domain-core`, 유스케이스와 port는 `application-core`에 둡니다.
3. **필요한 adapter만 선택합니다.** 전송 기술은 inbound, 데이터베이스·메시징·캐시·외부 연동은 outbound 모듈에서 선택하고 `app-bootstrap`에서 조립합니다.
4. **환경·운영 계약을 서비스 기준으로 확정합니다.** 환경 키 레지스트리와 Compose 기본값을 검토하되, 조직의 secret 관리·배포·관측 정책을 별도로 적용합니다.
5. **sample을 제거하고 독립성을 확인합니다.** `sample-portfolio`는 일반 테스트의 `sampleFixture`로만 연결되며 `sampleOffTest`는 샘플 없는 classpath에서 같은 핵심 테스트 corpus를 실행합니다. <!-- claim-id: C-ADOPT-SAMPLE-001 -->
도입 중 코드의 위치가 애매하면 “이 코드는 비즈니스 규칙인가, 유스케이스 조정인가, 기술 구현인가, 조립인가?”를 먼저 묻고 위 모듈 표에 배치하십시오. 새 모듈을 추가하면 Gradle 의존성 정책에도 명시적으로 등록해야 합니다. <!-- claim-id: C-NEW-MODULE-POLICY-001 -->
<!-- section-id: verification -->
## 검증 루프
작업 목적에 맞는 가장 작은 검증부터 실행하고, 변경을 공유하기 전 전체 계약으로 넓힙니다.
- 일반 테스트: `./gradlew test` <!-- claim-id: C-VERIFY-TEST-001 -->
- 모듈 의존 방향만 빠르게 확인: `./gradlew verifyCleanArchitectureDependencies` <!-- claim-id: C-VERIFY-ARCH-001 -->
- sample 제거 가능성 확인: `./gradlew :app-bootstrap:sampleOffTest` <!-- claim-id: C-VERIFY-SAMPLE-001 -->
- 전체 품질 계약: `./gradlew check` <!-- claim-id: C-VERIFY-CHECK-001 -->
```bash
cd src
./gradlew test
./gradlew verifyCleanArchitectureDependencies
./gradlew :app-bootstrap:sampleOffTest
./gradlew check
```
`check`는 테스트뿐 아니라 아키텍처 의존성, 환경 키, 산출물, 타입 배치, 취약점 예외, quarantine 만료, README 명령 검증을 집계합니다. <!-- claim-id: C-CHECK-SCOPE-001 -->
<!-- section-id: documentation -->
## 상세 문서 지도와 적용 한계
README는 판단과 첫 실행에 필요한 정보만 유지합니다. 세부 계약은 소유 위치에서 확인하십시오. <!-- claim-id: C-DOCS-STRATEGY-001 -->
- [빌드·실행·환경 설정](src/README.md)
- [도메인 모듈](src/domain-core/README.md) · [애플리케이션 모듈](src/application-core/README.md) · [composition root](src/app-bootstrap/README.md)
- [Web inbound adapter](src/adapter/inbound/web/README.md) · [JPA outbound adapter](src/adapter/outbound/persistence-jpa/README.md)
- [sample-portfolio 참조 구현](src/sample-portfolio/README.md)
- [환경 키 레지스트리](docs/registries/env-keys.yaml) · [runbook 템플릿](docs/runbooks/template.md)
도입 전에 다음 한계를 명시적으로 받아들이거나 보완해야 합니다.
- 여러 inbound·outbound adapter 모듈이 포함되어 있지만 실제 서비스가 채택할 범위와 배포 환경은 템플릿이 결정하지 않습니다. <!-- claim-id: C-LIMIT-CHOICES-001 -->
- 기본 로컬 실행 경로는 Docker와 PostgreSQL 16 Compose 서비스를 전제로 합니다. <!-- claim-id: C-LIMIT-LOCAL-001 -->
- 자동 검증은 저장소 내부의 구조·구성 계약을 지킵니다. 조직별 threat model, SLO, 부하 특성, 데이터 보존과 복구 목표는 별도의 설계·검증 대상입니다.
@@ -0,0 +1,147 @@
# ca-tmpl — 경계를 실행 가능한 규칙으로 만드는 Spring Boot 템플릿
`ca-tmpl`은 Java 21과 Spring Boot 4.0.0을 기준으로 구성된 멀티 모듈 서비스 템플릿입니다. <!-- claim-id: C-STACK-001 -->
이 저장소의 초점은 기능 예제를 많이 제공하는 데 있지 않습니다. domain, application, adapter, bootstrap의 책임을 나누고, 그 경계가 기능 추가 과정에서 무너지지 않도록 Gradle과 ArchUnit 검증을 함께 제공하는 데 있습니다. <!-- claim-id: C-POSITION-001 -->
<!-- section-id: overview -->
## 템플릿 개요
19개 Gradle 모듈이 core, inbound adapter, outbound adapter, composition root, sample 역할로 선언되어 있습니다. <!-- claim-id: C-MODULE-COUNT-001 -->
다음 상황에 특히 잘 맞습니다.
- 새 Java 서비스에서 모듈 경계와 검증 기준을 함께 시작하려는 경우
- HTTP·메시징·캐시·영속성 같은 기술 세부사항을 유스케이스와 분리하려는 경우
- 예제 코드를 제거한 뒤에도 핵심 구조가 독립적으로 성립하는지 자동 검증하려는 경우
반대로 단일 모듈 CRUD 예제나 특정 조직의 운영 정책까지 완성된 배포판이 필요하다면, 이 템플릿의 범위보다 가벼운 시작점 또는 별도의 플랫폼 기준이 더 적합할 수 있습니다.
<!-- section-id: project-value -->
## 저장소가 강제하는 것, 도입자가 결정할 것
| 저장소가 실행 가능하게 강제하는 것 | 도입자가 서비스 맥락에 맞게 결정할 것 |
| --- | --- |
| 모든 선언 모듈을 의존성 정책에 포함하고 허용되지 않은 프로젝트 의존성을 실패시킵니다. <!-- claim-id: C-FORCED-DEPS-001 --> | 실제 도메인 경계와 bounded context |
| application 코드가 adapter·bootstrap·transport·persistence에 의존하지 못하도록 검사합니다. <!-- claim-id: C-FORCED-CODE-001 --> | 사용할 inbound·outbound adapter의 범위 |
| leaf module의 모든 dependency configuration을 STRICT lock mode로 검증합니다. <!-- claim-id: C-FORCED-LOCKS-001 --> | 배포 플랫폼, SLO, 용량과 장애 복구 정책 |
| 같은 핵심 테스트를 `sample-portfolio` 없이 컴파일·실행하는 경로를 제공합니다. <!-- claim-id: C-FORCED-SAMPLE-001 --> | 인증·인가, 데이터 보존, 외부 연동의 서비스별 정책 |
이 구분이 중요합니다. 템플릿은 “어떤 결정을 해야 하는가”와 경계를 지키는 장치를 제공하지만, 서비스 고유의 결정을 대신하지는 않습니다.
<!-- section-id: architecture -->
## 아키텍처와 코드 배치
<!-- visual-id: architecture-dependency-direction -->
다음 그림의 화살표는 런타임 호출 순서가 아니라 허용된 프로젝트 의존 방향을 요약합니다. <!-- claim-id: C-VISUAL-MEANING-001 -->
```mermaid
flowchart LR
Inbound[Inbound adapters<br/>web · gRPC · GraphQL · WebSocket]
Application[application-core<br/>use cases · ports]
Domain[domain-core<br/>business invariants]
Outbound[Outbound adapters<br/>persistence · messaging · cache · integrations]
Shared[shared-contract<br/>operational contracts]
Bootstrap[app-bootstrap<br/>composition root]
Inbound --> Application
Outbound --> Application
Application --> Domain
Inbound --> Shared
Outbound --> Shared
Application --> Shared
Bootstrap --> Inbound
Bootstrap --> Outbound
Bootstrap --> Application
Bootstrap --> Domain
Bootstrap --> Shared
```
| 모듈 그룹 | 코드 배치 기준 |
| --- | --- |
| `domain-core` | 외부 라이브러리 의존성 없이 비즈니스 불변식과 도메인 타입을 둡니다. <!-- claim-id: C-DOMAIN-001 --> |
| `application-core` | `domain-core``shared-contract`에 의존하며 유스케이스와 port를 둡니다. <!-- claim-id: C-APPLICATION-001 --> |
| `adapter:inbound:*` / `adapter:outbound:*` | 전송 계층 입력과 기술별 출력 구현을 core 바깥에 둡니다. <!-- claim-id: C-ADAPTERS-001 --> |
| `shared-contract` | 비즈니스 개념이 아닌 공용 운영 계약을 둡니다. <!-- claim-id: C-SHARED-001 --> |
| `app-bootstrap` | 선택한 core와 adapter를 조립하고 Spring Boot 진입점을 소유합니다. <!-- claim-id: C-BOOTSTRAP-MODULE-001 --> |
| `sample-portfolio` | 템플릿 사용법을 보여주는 참조 구현이며 일반 테스트의 fixture로만 연결됩니다. <!-- claim-id: C-SAMPLE-ROLE-001 --> |
Gradle의 `verifyCleanArchitectureDependencies`는 모듈 간 의존 방향을, `CleanArchitectureTest`는 application 패키지의 adapter·transport 접근과 같은 코드 수준 경계를 검사합니다. <!-- claim-id: C-TWO-LAYERS-001 -->
<!-- section-id: quick-start -->
## 빠른 시작
<!-- feature-developer-experience-contract: first-run success probe = GET /api/healthcheck -->
필요한 도구는 JDK 21과 실행 중인 Docker daemon입니다. 저장소의 도구 버전 파일은 Temurin 21.0.11+10을 지정하고, bootstrap preflight는 Docker CLI가 daemon에 연결되는지 확인합니다. <!-- claim-id: C-PREREQUISITES-001 -->
저장소 루트에서 다음을 실행합니다.
```bash
cd src
./gradlew bootstrap
```
`./gradlew bootstrap`은 전체 소스 컴파일, Docker 확인, 로컬 PostgreSQL과 앱 시작, sample 격리 계약, HTTP smoke check를 순서대로 실행합니다. <!-- claim-id: C-BOOTSTRAP-COMMAND-001 -->
성공 조건은 `http://localhost:8080/api/healthcheck`가 HTTP 200과 `status=UP`을 반환하는 것입니다. <!-- claim-id: C-HEALTH-001 -->
bootstrap은 Compose의 `app``db` 서비스를 백그라운드로 시작합니다. 작업을 마치면 저장소 루트에서 종료합니다. <!-- claim-id: C-BOOTSTRAP-SIDE-EFFECT-001 -->
```bash
cd ..
docker compose -f docker-compose.yml -f docker-compose.local.yml down
```
위 Compose 명령은 저장소에 선언된 base와 local 구성 파일을 함께 사용해 서비스를 종료합니다. <!-- claim-id: C-CLEANUP-001 -->
<!-- section-id: adoption -->
## 실제 프로젝트로 전환하기
한 번에 모든 이름과 모듈을 지우기보다, 각 단계에서 검증 가능한 상태를 유지하는 편이 안전합니다.
1. **식별자를 먼저 정합니다.** Gradle root name은 `ca-skeleton`, Java package root와 main class는 `dev.caskeleton` 아래에 선언되어 있으므로 서비스 이름과 namespace 정책에 맞게 함께 변경합니다. <!-- claim-id: C-IDENTITY-001 -->
2. **도메인과 유스케이스를 core에 세웁니다.** 비즈니스 불변식은 `domain-core`, 유스케이스와 port는 `application-core`에 둡니다.
3. **필요한 adapter만 선택합니다.** 전송 기술은 inbound, 데이터베이스·메시징·캐시·외부 연동은 outbound 모듈에서 선택하고 `app-bootstrap`에서 조립합니다.
4. **환경·운영 계약을 서비스 기준으로 확정합니다.** 환경 키 레지스트리와 Compose 기본값을 검토하되, 조직의 secret 관리·배포·관측 정책을 별도로 적용합니다.
5. **sample을 제거하고 독립성을 확인합니다.** `sample-portfolio`는 일반 테스트의 `sampleFixture`로만 연결되며 `sampleOffTest`는 샘플 없는 classpath에서 같은 핵심 테스트 corpus를 실행합니다. <!-- claim-id: C-ADOPT-SAMPLE-001 -->
도입 중 코드의 위치가 애매하면 “이 코드는 비즈니스 규칙인가, 유스케이스 조정인가, 기술 구현인가, 조립인가?”를 먼저 묻고 위 모듈 표에 배치하십시오. 새 모듈을 추가하면 Gradle 의존성 정책에도 명시적으로 등록해야 합니다. <!-- claim-id: C-NEW-MODULE-POLICY-001 -->
<!-- section-id: verification -->
## 검증 루프
작업 목적에 맞는 가장 작은 검증부터 실행하고, 변경을 공유하기 전 전체 계약으로 넓힙니다.
- 일반 테스트: `./gradlew test` <!-- claim-id: C-VERIFY-TEST-001 -->
- 모듈 의존 방향만 빠르게 확인: `./gradlew verifyCleanArchitectureDependencies` <!-- claim-id: C-VERIFY-ARCH-001 -->
- sample 제거 가능성 확인: `./gradlew :app-bootstrap:sampleOffTest` <!-- claim-id: C-VERIFY-SAMPLE-001 -->
- 전체 품질 계약: `./gradlew check` <!-- claim-id: C-VERIFY-CHECK-001 -->
```bash
cd src
./gradlew test
./gradlew verifyCleanArchitectureDependencies
./gradlew :app-bootstrap:sampleOffTest
./gradlew check
```
`check`는 테스트뿐 아니라 아키텍처 의존성, 환경 키, 산출물, 타입 배치, 취약점 예외, quarantine 만료, README 명령 검증을 집계합니다. <!-- claim-id: C-CHECK-SCOPE-001 -->
<!-- section-id: documentation -->
## 상세 문서 지도와 적용 한계
README는 판단과 첫 실행에 필요한 정보만 유지합니다. 세부 계약은 소유 위치에서 확인하십시오. <!-- claim-id: C-DOCS-STRATEGY-001 -->
- [빌드·실행·환경 설정](src/README.md)
- [도메인 모듈](src/domain-core/README.md) · [애플리케이션 모듈](src/application-core/README.md) · [composition root](src/app-bootstrap/README.md)
- [Web inbound adapter](src/adapter/inbound/web/README.md) · [JPA outbound adapter](src/adapter/outbound/persistence-jpa/README.md)
- [sample-portfolio 참조 구현](src/sample-portfolio/README.md)
- [환경 키 레지스트리](docs/registries/env-keys.yaml) · [runbook 템플릿](docs/runbooks/template.md)
도입 전에 다음 한계를 명시적으로 받아들이거나 보완해야 합니다.
- 여러 inbound·outbound adapter 모듈이 포함되어 있지만 실제 서비스가 채택할 범위와 배포 환경은 템플릿이 결정하지 않습니다. <!-- claim-id: C-LIMIT-CHOICES-001 -->
- 기본 로컬 실행 경로는 Docker와 PostgreSQL 16 Compose 서비스를 전제로 합니다. <!-- claim-id: C-LIMIT-LOCAL-001 -->
- 자동 검증은 저장소 내부의 구조·구성 계약을 지킵니다. 조직별 threat model, SLO, 부하 특성, 데이터 보존과 복구 목표는 별도의 설계·검증 대상입니다.
@@ -0,0 +1,11 @@
--- README.md (current)
+++ README.md (candidate)
@@ -72,6 +72,8 @@
<!-- section-id: quick-start -->
## 빠른 시작
+<!-- feature-developer-experience-contract: first-run success probe = GET /api/healthcheck -->
+
필요한 도구는 JDK 21과 실행 중인 Docker daemon입니다. 저장소의 도구 버전 파일은 Temurin 21.0.11+10을 지정하고, bootstrap preflight는 Docker CLI가 daemon에 연결되는지 확인합니다. <!-- claim-id: C-PREREQUISITES-001 -->
저장소 루트에서 다음을 실행합니다.
@@ -0,0 +1,7 @@
schema-version: 1
mode: bootstrap
target-rel: README.md
generated-hash: sha256:e7958b9784569397ce5123206c4c80578373fd64c94900fef887ecafb8325c09
target-before-hash: sha256:5c39a893d2255c8df7798fcd62090490a345687c9637c683e4d9ad9aab70e1d6
repository-snapshot-hash: sha256:4d351050ecdfa25ea9e39b22c7c5bc0c686b60aa1f9fef7a02f86ae073151f1e
review-score: 96
@@ -0,0 +1,188 @@
schema-version: 1
claims:
- id: C-STACK-001
type: factual
statement: "`ca-tmpl`은 Java 21과 Spring Boot 4.0.0을 기준으로 구성된 멀티 모듈 서비스 템플릿입니다."
section: overview
sources: [{fact-id: F-STACK-001}, {fact-id: F-MODULES-001}]
status: supported
- id: C-POSITION-001
type: factual
statement: "이 저장소의 초점은 기능 예제를 많이 제공하는 데 있지 않습니다. domain, application, adapter, bootstrap의 책임을 나누고, 그 경계가 기능 추가 과정에서 무너지지 않도록 Gradle과 ArchUnit 검증을 함께 제공하는 데 있습니다."
section: overview
sources: [{fact-id: F-DEPENDENCY-POLICY-001}, {fact-id: F-CODE-BOUNDARY-001}]
status: supported
- id: C-MODULE-COUNT-001
type: factual
statement: "19개 Gradle 모듈이 core, inbound adapter, outbound adapter, composition root, sample 역할로 선언되어 있습니다."
section: overview
sources: [{fact-id: F-MODULES-001}]
status: supported
- id: C-FORCED-DEPS-001
type: factual
statement: "모든 선언 모듈을 의존성 정책에 포함하고 허용되지 않은 프로젝트 의존성을 실패시킵니다."
section: project-value
sources: [{fact-id: F-DEPENDENCY-POLICY-001}]
status: supported
- id: C-FORCED-CODE-001
type: factual
statement: "application 코드가 adapter·bootstrap·transport·persistence에 의존하지 못하도록 검사합니다."
section: project-value
sources: [{fact-id: F-CODE-BOUNDARY-001}]
status: supported
- id: C-FORCED-LOCKS-001
type: factual
statement: "leaf module의 모든 dependency configuration을 STRICT lock mode로 검증합니다."
section: project-value
sources: [{fact-id: F-LOCKS-001}]
status: supported
- id: C-FORCED-SAMPLE-001
type: factual
statement: "같은 핵심 테스트를 `sample-portfolio` 없이 컴파일·실행하는 경로를 제공합니다."
section: project-value
sources: [{fact-id: F-SAMPLE-001}]
status: supported
- id: C-VISUAL-MEANING-001
type: factual
statement: "다음 그림의 화살표는 런타임 호출 순서가 아니라 허용된 프로젝트 의존 방향을 요약합니다."
section: architecture
sources: [{fact-id: F-DEPENDENCY-POLICY-001}]
status: supported
- id: C-DOMAIN-001
type: factual
statement: "외부 라이브러리 의존성 없이 비즈니스 불변식과 도메인 타입을 둡니다."
section: architecture
sources: [{fact-id: F-CORE-001}]
status: supported
- id: C-APPLICATION-001
type: factual
statement: "`domain-core`와 `shared-contract`에 의존하며 유스케이스와 port를 둡니다."
section: architecture
sources: [{fact-id: F-CORE-001}]
status: supported
- id: C-ADAPTERS-001
type: factual
statement: "전송 계층 입력과 기술별 출력 구현을 core 바깥에 둡니다."
section: architecture
sources: [{fact-id: F-MODULES-001}, {fact-id: F-DEPENDENCY-POLICY-001}]
status: supported
- id: C-SHARED-001
type: factual
statement: "비즈니스 개념이 아닌 공용 운영 계약을 둡니다."
section: architecture
sources: [{fact-id: F-CORE-001}]
status: supported
- id: C-BOOTSTRAP-MODULE-001
type: factual
statement: "선택한 core와 adapter를 조립하고 Spring Boot 진입점을 소유합니다."
section: architecture
sources: [{fact-id: F-COMPOSITION-001}]
status: supported
- id: C-SAMPLE-ROLE-001
type: factual
statement: "템플릿 사용법을 보여주는 참조 구현이며 일반 테스트의 fixture로만 연결됩니다."
section: architecture
sources: [{fact-id: F-SAMPLE-001}]
status: supported
- id: C-TWO-LAYERS-001
type: factual
statement: "Gradle의 `verifyCleanArchitectureDependencies`는 모듈 간 의존 방향을, `CleanArchitectureTest`는 application 패키지의 adapter·transport 접근과 같은 코드 수준 경계를 검사합니다."
section: architecture
sources: [{fact-id: F-DEPENDENCY-POLICY-001}, {fact-id: F-CODE-BOUNDARY-001}]
status: supported
- id: C-PREREQUISITES-001
type: factual
statement: "필요한 도구는 JDK 21과 실행 중인 Docker daemon입니다. 저장소의 도구 버전 파일은 Temurin 21.0.11+10을 지정하고, bootstrap preflight는 Docker CLI가 daemon에 연결되는지 확인합니다."
section: quick-start
sources: [{fact-id: F-STACK-001}, {fact-id: F-BOOTSTRAP-001}]
status: supported
- id: C-BOOTSTRAP-COMMAND-001
type: factual
statement: "`./gradlew bootstrap`은 전체 소스 컴파일, Docker 확인, 로컬 PostgreSQL과 앱 시작, sample 격리 계약, HTTP smoke check를 순서대로 실행합니다."
section: quick-start
sources: [{fact-id: F-BOOTSTRAP-001}]
status: supported
- id: C-HEALTH-001
type: factual
statement: "성공 조건은 `http://localhost:8080/api/healthcheck`가 HTTP 200과 `status=UP`을 반환하는 것입니다."
section: quick-start
sources: [{fact-id: F-HEALTH-001}]
status: supported
- id: C-BOOTSTRAP-SIDE-EFFECT-001
type: factual
statement: "bootstrap은 Compose의 `app`과 `db` 서비스를 백그라운드로 시작합니다."
section: quick-start
sources: [{fact-id: F-BOOTSTRAP-001}, {fact-id: F-CONTAINER-001}]
status: supported
- id: C-CLEANUP-001
type: factual
statement: "위 Compose 명령은 저장소에 선언된 base와 local 구성 파일을 함께 사용해 서비스를 종료합니다."
section: quick-start
sources: [{fact-id: F-CONTAINER-001}]
status: supported
- id: C-IDENTITY-001
type: factual
statement: "Gradle root name은 `ca-skeleton`, Java package root와 main class는 `dev.caskeleton` 아래에 선언되어 있으므로 서비스 이름과 namespace 정책에 맞게 함께 변경합니다."
section: adoption
sources: [{fact-id: F-IDENTITY-001}]
status: supported
- id: C-ADOPT-SAMPLE-001
type: factual
statement: "`sample-portfolio`는 일반 테스트의 `sampleFixture`로만 연결되며 `sampleOffTest`는 샘플 없는 classpath에서 같은 핵심 테스트 corpus를 실행합니다."
section: adoption
sources: [{fact-id: F-SAMPLE-001}]
status: supported
- id: C-NEW-MODULE-POLICY-001
type: factual
statement: "새 모듈을 추가하면 Gradle 의존성 정책에도 명시적으로 등록해야 합니다."
section: adoption
sources: [{fact-id: F-DEPENDENCY-POLICY-001}]
status: supported
- id: C-VERIFY-TEST-001
type: factual
statement: "일반 테스트: `./gradlew test`"
section: verification
sources: [{fact-id: F-VERIFICATION-COMMANDS-001}]
status: supported
- id: C-VERIFY-ARCH-001
type: factual
statement: "모듈 의존 방향만 빠르게 확인: `./gradlew verifyCleanArchitectureDependencies`"
section: verification
sources: [{fact-id: F-VERIFICATION-COMMANDS-001}, {fact-id: F-DEPENDENCY-POLICY-001}]
status: supported
- id: C-VERIFY-SAMPLE-001
type: factual
statement: "sample 제거 가능성 확인: `./gradlew :app-bootstrap:sampleOffTest`"
section: verification
sources: [{fact-id: F-VERIFICATION-COMMANDS-001}, {fact-id: F-SAMPLE-001}]
status: supported
- id: C-VERIFY-CHECK-001
type: factual
statement: "전체 품질 계약: `./gradlew check`"
section: verification
sources: [{fact-id: F-VERIFICATION-COMMANDS-001}, {fact-id: F-CHECK-001}]
status: supported
- id: C-CHECK-SCOPE-001
type: factual
statement: "`check`는 테스트뿐 아니라 아키텍처 의존성, 환경 키, 산출물, 타입 배치, 취약점 예외, quarantine 만료, README 명령 검증을 집계합니다."
section: verification
sources: [{fact-id: F-CHECK-001}]
status: supported
- id: C-DOCS-STRATEGY-001
type: evaluative
statement: "README는 판단과 첫 실행에 필요한 정보만 유지합니다. 세부 계약은 소유 위치에서 확인하십시오."
section: documentation
sources: []
status: supported
- id: C-LIMIT-CHOICES-001
type: factual
statement: "여러 inbound·outbound adapter 모듈이 포함되어 있지만 실제 서비스가 채택할 범위와 배포 환경은 템플릿이 결정하지 않습니다."
section: documentation
sources: [{fact-id: F-TEMPLATE-LIMIT-001}]
status: supported
- id: C-LIMIT-LOCAL-001
type: factual
statement: "기본 로컬 실행 경로는 Docker와 PostgreSQL 16 Compose 서비스를 전제로 합니다."
section: documentation
sources: [{fact-id: F-BOOTSTRAP-001}, {fact-id: F-CONTAINER-001}]
status: supported
@@ -0,0 +1,50 @@
schema-version: 1
project-profile:
primary: project-template
secondary:
- backend-service
audiences:
primary:
- 신규 Spring Boot 서비스의 기준 구조를 정하는 백엔드·플랫폼 개발자
secondary:
- 아키텍처 규칙과 검증 체계를 평가하는 테크 리드
reader-outcomes:
- 템플릿이 제공하는 강제 규칙과 도입자가 결정할 영역을 구분한다.
- 로컬 부트스트랩을 실행하고 성공 조건과 정리 방법을 확인한다.
- 도메인·유스케이스·어댑터·조립 코드를 올바른 모듈에 배치한다.
- 샘플 제거 및 전체 품질 계약을 재현 가능한 명령으로 검증한다.
project-story:
value-proposition: 문서로만 권고하는 구조가 아니라 Gradle과 ArchUnit 규칙으로 의존 방향을 지속적으로 검증하는 Spring Boot 템플릿이다.
problem: 서비스 초기 구조는 빠르게 복사할 수 있어도 경계가 빌드에 강제되지 않으면 기능 추가 과정에서 쉽게 무너진다.
target-reader: 신규 Java 백엔드의 구조와 검증 기준을 함께 도입하려는 개발자
notable-traits:
- text: Java 21과 Spring Boot 4.0.0을 사용하는 19개 모듈 구성이다.
fact-ids: [F-STACK-001, F-MODULES-001]
- text: 모듈 의존 방향과 application 코드 경계를 실행 가능한 빌드·ArchUnit 규칙으로 검증한다.
fact-ids: [F-DEPENDENCY-POLICY-001, F-CODE-BOUNDARY-001]
- text: 로컬 부트스트랩은 컴파일부터 PostgreSQL·앱 시작과 HTTP 상태 확인까지 하나의 계약으로 묶는다.
fact-ids: [F-BOOTSTRAP-001, F-HEALTH-001]
- text: sample-portfolio를 테스트 fixture로 격리하고 샘플 없는 핵심 테스트 경로를 제공한다.
fact-ids: [F-SAMPLE-001]
maturity: 자동화된 구조·실행·검증 계약을 갖춘 참조 템플릿
limitations:
- 제공되는 adapter 가운데 실제 서비스가 채택할 범위는 도입자가 결정해야 한다.
- 로컬 실행 토폴로지는 Docker와 PostgreSQL을 전제로 한다.
- 조직별 보안·성능·가용성 요구사항은 템플릿의 내부 검증과 별도로 평가해야 한다.
narrative-variant: architecture-template
reader-journey:
- reader-question: 이 템플릿은 무엇이며 어떤 문제를 해결하는가?
section-id: overview
- reader-question: 일반적인 시작점과 비교해 무엇이 강제되는가?
section-id: project-value
- reader-question: 모듈은 어떤 방향으로 의존하고 코드는 어디에 놓는가?
section-id: architecture
- reader-question: 가장 짧은 로컬 실행 경로와 성공 신호는 무엇인가?
section-id: quick-start
- reader-question: 샘플을 실제 도메인으로 바꾸는 순서는 무엇인가?
section-id: adoption
- reader-question: 구조와 전체 품질 계약을 어떻게 다시 검증하는가?
section-id: verification
- reader-question: 세부 설정과 운영 계약은 어디에서 확인하는가?
section-id: documentation
@@ -0,0 +1,101 @@
schema-version: 1
sections:
- id: overview
title-guidance: 템플릿 개요
level: 2
purpose: 가치 제안, 대상 독자, 적합하거나 부적합한 사용 상황을 빠르게 판단시킨다.
required: true
content-strategy: inline
content-requirements:
- Java와 Spring Boot 기준 버전
- 권고가 아닌 실행 가능한 경계 검증이라는 차별점
- 참조 템플릿이라는 정직한 포지셔닝
visual-slot:
decision: exclude
reader-question: 이 프로젝트의 정체성을 이해하는 데 그림이 필요한가?
rationale: 짧은 가치 제안과 적합성 목록이 더 빠르고 정확하다.
- id: project-value
title-guidance: 제공 가치와 결정 영역
level: 2
purpose: 저장소가 자동으로 강제하는 것과 도입자가 선택할 것을 분리한다.
required: true
content-strategy: inline
content-requirements:
- 아키텍처·잠금·샘플 격리 계약
- 도메인·adapter·배포 정책은 도입자 책임임을 명시
visual-slot:
decision: exclude
reader-question: 강제 영역과 선택 영역을 어떻게 가장 빨리 비교하는가?
rationale: 두 열 비교표가 그림보다 직접적이고 접근성이 높다.
- id: architecture
title-guidance: 아키텍처와 코드 배치
level: 2
purpose: core, adapter, composition root의 관계와 코드 변경 위치를 설명한다.
required: true
content-strategy: inline
content-requirements:
- 의존 방향 Mermaid 다이어그램
- 모듈 그룹별 책임 표
- Gradle과 ArchUnit이 각각 검증하는 경계
visual-slot:
decision: include
reader-question: 여러 모듈 그룹이 어느 방향으로 의존하는가?
rationale: 다섯 구성요소의 의존 방향은 문장 나열보다 흐름도가 더 빨리 전달한다.
purpose: adapter와 composition root가 core 방향으로 의존한다는 구조를 한 화면에 보여준다.
- id: quick-start
title-guidance: 빠른 시작
level: 2
purpose: 사전 조건, 단일 bootstrap 명령, 부작용, 성공 신호와 정리 방법을 제공한다.
required: true
content-strategy: inline
content-requirements:
- JDK 21과 Docker
- bootstrap 실행 명령
- API health 성공 조건
- Compose 정리 명령
visual-slot:
decision: exclude
reader-question: 실행 절차를 이해하는 데 추가 시각 자료가 필요한가?
rationale: 짧은 명령 블록과 성공 조건이 가장 실행 가능하다.
- id: adoption
title-guidance: 실제 프로젝트로 전환하기
level: 2
purpose: 프로젝트 식별자, 도메인, adapter, 환경 정책, sample 제거 순서로 도입 경로를 안내한다.
required: true
content-strategy: inline
content-requirements:
- sample은 참조 구현이며 production 의존성이 아님
- sampleOffTest를 이용한 제거 검증
- 상세 문서를 중복하지 않는 단계별 전환 경로
visual-slot:
decision: exclude
reader-question: 도입 순서는 어떤 형태가 가장 행동하기 쉬운가?
rationale: 번호 목록과 검증 체크포인트가 진행 순서를 명확히 한다.
- id: verification
title-guidance: 검증 루프
level: 2
purpose: 빠른 테스트, 아키텍처 경계, 샘플 제거, 전체 check의 목적과 명령을 분리한다.
required: true
content-strategy: inline
content-requirements:
- test와 architecture 명령
- sampleOffTest 명령
- 전체 check가 집계하는 정책
visual-slot:
decision: exclude
reader-question: 검증 수준별 명령 선택에 그림이 필요한가?
rationale: 목적과 명령을 짝지은 표가 더 정확하다.
- id: documentation
title-guidance: 상세 문서 지도와 한계
level: 2
purpose: 빌드·모듈·환경·운영 문서로 이동시키고 템플릿의 적용 한계를 명시한다.
required: true
content-strategy: inline
content-requirements:
- src README와 대표 모듈 README 링크
- 환경 레지스트리와 runbook 링크
- 조직별 비기능 요구사항은 별도 검증이라는 한계
visual-slot:
decision: exclude
reader-question: 세부 문서 위치를 찾는 데 그림이 필요한가?
rationale: 목적별 링크 목록이 탐색과 유지보수에 적합하다.
@@ -0,0 +1,44 @@
schema-version: 1
target:
repository: /home/donghyeon/workspace/ca-tmpl
readme-path: README.md
mode: bootstrap
profile-override: project-template
project-intent:
purpose: ca-tmpl을 평가하고 실제 서비스의 출발점으로 채택하는 데 필요한 판단·실행·변경 경로를 제공한다.
positioning: 구현 목록이 아니라 아키텍처 경계를 빌드와 테스트로 강제하는 Spring Boot 프로젝트 템플릿의 진입 문서다.
maturity: 광범위한 자동화 계약을 갖춘 참조 템플릿이며, 개별 조직의 운영 적합성은 도입 과정에서 검증해야 한다.
audience:
primary:
- 신규 Spring Boot 서비스의 기준 구조를 정하는 백엔드·플랫폼 개발자
secondary:
- 아키텍처 규칙과 검증 체계를 평가하는 테크 리드
reader-actions:
- 30초 안에 템플릿의 차별점과 적합한 사용 상황을 판단한다.
- 로컬 부트스트랩을 실행하고 성공 신호를 확인한다.
- 변경할 코드를 올바른 모듈에 배치한다.
- sample-portfolio를 제거해도 핵심 계약이 유지되는지 검증한다.
- 상세 설정과 운영 문서의 위치를 찾는다.
content-policy:
language: ko
tone: technical-direct
target-length: medium
preserve-existing-copy: false
detail-docs-policy: summary-and-link
visual-policy:
mode: when-useful
max-visuals: 1
preferred-formats:
- mermaid
must-include:
- 강제되는 아키텍처 규칙과 도입자가 선택해야 하는 정책의 구분
- bootstrap이 수행하는 작업과 성공 신호
- sample-portfolio의 참조 구현 역할과 제거 검증 방법
- 모듈 의존 방향과 코드 배치 기준
- 템플릿의 한계와 도입 전 결정 항목
must-exclude:
- 전체 환경 변수 목록
- 공급망·릴리스 절차의 장황한 복제
- 모든 어댑터의 구현 세부사항
- 근거 없는 production-ready 주장
@@ -0,0 +1,360 @@
schema-version: 1
repository-snapshot-hash: sha256:4d351050ecdfa25ea9e39b22c7c5bc0c686b60aa1f9fef7a02f86ae073151f1e
project-name: ca-skeleton
languages:
- Java
frameworks:
- Spring Boot 4.0.0
- Gradle
facts:
- id: F-README-CONTRACT-001
category: readme-contract
key: required-literals
value:
- ./gradlew bootstrap
- GET /api/healthcheck
- feature-developer-experience-contract
assertion-type: observed
confidence: high
evidence:
- path: src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/contract/DeveloperExperienceContractTest.java
line-start: 52
line-end: 64
symbol: readmeCommandsAreVerifiedAndBootstrapIsTheFirstRunEntrypoint
source-kind: executable-test-contract
- id: F-IDENTITY-001
category: adoption
key: template-identifiers
value:
gradle-root-name: ca-skeleton
java-package-root: dev.caskeleton
main-class: dev.caskeleton.bootstrap.CaSkeletonApplication
assertion-type: observed
confidence: high
evidence:
- path: src/settings.gradle
line-start: 5
line-end: 5
source-kind: build-configuration
- path: src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/CaSkeletonApplication.java
line-start: 1
line-end: 20
symbol: CaSkeletonApplication
source-kind: implementation
- id: F-STACK-001
category: stack
key: runtime-and-framework
value:
java: 21
java-distribution: temurin-21.0.11+10
spring-boot: 4.0.0
assertion-type: observed
confidence: high
evidence:
- path: .tool-versions
line-start: 1
line-end: 1
source-kind: tool-version-configuration
- path: src/build.gradle
line-start: 5
line-end: 7
source-kind: build-configuration
- path: src/build.gradle
line-start: 103
line-end: 107
source-kind: build-configuration
- id: F-MODULES-001
category: architecture
key: declared-modules
value:
core: [domain-core, application-core, shared-contract]
inbound: [web, grpc, graphql, websocket]
outbound: [persistence-jpa, support, messaging, cache-redis, notification, objectstorage, fileserver, persistence-mongo, httpclient, identifier]
composition: [app-bootstrap]
sample: [sample-portfolio]
assertion-type: observed
confidence: high
evidence:
- path: src/settings.gradle
line-start: 5
line-end: 25
source-kind: build-configuration
- id: F-DEPENDENCY-POLICY-001
category: architecture
key: module-dependency-policy
value: Gradle의 verifyCleanArchitectureDependencies가 모든 선언 모듈을 정책에 포함시키고 허용되지 않은 프로젝트 의존성을 실패시킨다.
assertion-type: observed
confidence: high
evidence:
- path: src/build.gradle
line-start: 553
line-end: 615
symbol: verifyCleanArchitectureDependencies
source-kind: executable-build-rule
- id: F-CODE-BOUNDARY-001
category: architecture
key: code-boundary-policy
value: ArchUnit 규칙이 application 패키지의 adapter·bootstrap·transport·persistence 의존과 Spring @Transactional 사용을 금지한다.
assertion-type: observed
confidence: high
evidence:
- path: src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/architecture/CleanArchitectureTest.java
line-start: 197
line-end: 228
source-kind: executable-test-rule
- id: F-CORE-001
category: architecture
key: core-responsibilities
value:
domain-core: 외부 라이브러리 의존성이 없는 도메인 모듈
application-core: domain-core와 shared-contract를 의존하는 유스케이스 모듈
shared-contract: 비즈니스 개념을 두지 않는 공용 운영 계약 모듈
assertion-type: derived
confidence: high
evidence:
- path: src/domain-core/build.gradle
line-start: 1
line-end: 3
source-kind: build-configuration
- path: src/application-core/build.gradle
line-start: 1
line-end: 15
source-kind: build-configuration
- path: src/shared-contract/build.gradle
line-start: 1
line-end: 3
source-kind: build-configuration
- id: F-COMPOSITION-001
category: architecture
key: composition-root
value: app-bootstrap가 core, inbound web, 여러 outbound adapter, shared-contract를 조립하고 Spring Boot main class를 지정한다.
assertion-type: observed
confidence: high
evidence:
- path: src/app-bootstrap/build.gradle
line-start: 41
line-end: 58
source-kind: build-configuration
- path: src/app-bootstrap/build.gradle
line-start: 174
line-end: 176
source-kind: build-configuration
- id: F-SAMPLE-001
category: adoption
key: sample-removal-contract
value: sample-portfolio는 일반 테스트에서만 sampleFixture로 연결되며 sampleOffTest는 같은 핵심 테스트 스위트를 샘플 없이 컴파일하고 실행한다.
assertion-type: observed
confidence: high
evidence:
- path: src/app-bootstrap/build.gradle
line-start: 14
line-end: 38
source-kind: build-configuration
- path: src/app-bootstrap/build.gradle
line-start: 95
line-end: 100
source-kind: build-configuration
- path: src/app-bootstrap/build.gradle
line-start: 135
line-end: 147
symbol: sampleOffTest
source-kind: executable-build-rule
- id: F-BOOTSTRAP-001
category: command
key: local-bootstrap-contract
value: bootstrap은 전체 소스 컴파일, Docker daemon 확인, PostgreSQL 시작, 앱 빌드·시작, 샘플 격리 계약, HTTP smoke check를 순서대로 실행한다.
assertion-type: observed
confidence: high
evidence:
- path: src/build.gradle
line-start: 345
line-end: 435
symbol: bootstrap
source-kind: executable-build-rule
- id: F-HEALTH-001
category: endpoint
key: bootstrap-success-signal
value: bootstrap smoke check는 http://localhost:8080/api/healthcheck의 HTTP 200 응답과 status UP을 요구한다.
assertion-type: observed
confidence: high
evidence:
- path: src/build.gradle
line-start: 396
line-end: 426
symbol: bootstrapSmoke
source-kind: executable-build-rule
- path: src/adapter/inbound/web/src/main/java/dev/caskeleton/adapter/inbound/web/controller/HealthcheckController.java
line-start: 10
line-end: 17
symbol: HealthcheckController
source-kind: implementation
- id: F-CONTAINER-001
category: runtime
key: local-compose-topology
value: 로컬 Compose 구성은 app과 PostgreSQL 16 서비스를 연결하고 named volume에 데이터베이스 데이터를 보존한다.
assertion-type: observed
confidence: high
evidence:
- path: docker-compose.yml
line-start: 26
line-end: 80
source-kind: container-configuration
- path: docker-compose.local.yml
line-start: 15
line-end: 83
source-kind: container-configuration
- id: F-LOCKS-001
category: verification
key: dependency-lock-policy
value: 각 leaf module은 모든 구성을 STRICT 모드로 잠그며 잠금 상태 검증 태스크가 실제 dependency resolution을 수행한다.
assertion-type: observed
confidence: high
evidence:
- path: src/build.gradle
line-start: 109
line-end: 167
source-kind: executable-build-rule
- id: F-CHECK-001
category: verification
key: check-aggregation
value: 각 leaf module의 check는 아키텍처 의존성, 환경 키, 산출물, 타입 배치, 취약점 예외, 격리 테스트 만료, README 명령 검증을 포함한다.
assertion-type: observed
confidence: high
evidence:
- path: src/build.gradle
line-start: 273
line-end: 280
source-kind: executable-build-rule
- path: src/build.gradle
line-start: 437
line-end: 550
symbol: verifyReadmeCommands
source-kind: executable-build-rule
- id: F-VERIFICATION-COMMANDS-001
category: command
key: documented-verification-tasks
value:
- ./gradlew test
- ./gradlew verifyCleanArchitectureDependencies
- ./gradlew :app-bootstrap:sampleOffTest
- ./gradlew check
assertion-type: derived
confidence: high
evidence:
- path: src/build.gradle
line-start: 247
line-end: 280
source-kind: executable-build-rule
- path: src/build.gradle
line-start: 553
line-end: 615
symbol: verifyCleanArchitectureDependencies
source-kind: executable-build-rule
- path: src/app-bootstrap/build.gradle
line-start: 135
line-end: 147
symbol: sampleOffTest
source-kind: executable-build-rule
- id: F-DOCS-001
category: documentation
key: detailed-documentation
value: 빌드 루트, 핵심 모듈, inbound·outbound adapter에 각각 README가 있고 환경·운영 계약은 docs 아래 레지스트리와 runbook으로 분리되어 있다.
assertion-type: observed
confidence: high
evidence:
- path: src/README.md
source-kind: documentation-index
- path: src/domain-core/README.md
source-kind: module-documentation
- path: src/application-core/README.md
source-kind: module-documentation
- path: src/adapter/inbound/web/README.md
source-kind: module-documentation
- path: src/adapter/outbound/persistence-jpa/README.md
source-kind: module-documentation
- path: docs/registries/env-keys.yaml
source-kind: configuration-registry
- path: docs/runbooks/template.md
source-kind: runbook-template
- id: F-TEMPLATE-LIMIT-001
category: limitation
key: adoption-decisions
value: 템플릿은 여러 inbound·outbound adapter seam과 PostgreSQL 로컬 구성을 제공하지만 실제 서비스가 사용할 adapter와 배포 환경 선택은 도입자가 결정해야 한다.
assertion-type: derived
confidence: high
evidence:
- path: src/settings.gradle
line-start: 7
line-end: 25
source-kind: build-configuration
- path: docker-compose.local.yml
line-start: 15
line-end: 83
source-kind: container-configuration
commands:
- id: CMD-001
command: ./gradlew bootstrap
cwd: src
source:
path: src/build.gradle
line-start: 431
line-end: 435
verification:
status: static-verified
method: gradle-task-discovery
level: static
- id: CMD-002
command: docker compose -f docker-compose.yml -f docker-compose.local.yml down
cwd: .
source:
path: docker-compose.local.yml
line-start: 15
line-end: 83
verification:
status: static-verified
method: compose-file-discovery
level: static
- id: CMD-003
command: ./gradlew test
cwd: src
source:
path: src/build.gradle
line-start: 247
line-end: 251
verification:
status: static-verified
method: gradle-lifecycle-task
level: static
- id: CMD-004
command: ./gradlew :app-bootstrap:sampleOffTest
cwd: src
source:
path: src/app-bootstrap/build.gradle
line-start: 135
line-end: 147
verification:
status: static-verified
method: gradle-task-discovery
level: static
- id: CMD-005
command: ./gradlew verifyCleanArchitectureDependencies
cwd: src
source:
path: src/build.gradle
line-start: 553
line-end: 615
verification:
status: static-verified
method: gradle-task-discovery
level: static
- id: CMD-006
command: ./gradlew check
cwd: src
source:
path: src/build.gradle
line-start: 273
line-end: 280
verification:
status: static-verified
method: gradle-lifecycle-task
level: static
@@ -0,0 +1,7 @@
{
"git-sha": "dd20b5801b5ac2a9443b7e6c01f466b5ddc378e0",
"dirty": true,
"diff-hash": "sha256:4d351050ecdfa25ea9e39b22c7c5bc0c686b60aa1f9fef7a02f86ae073151f1e",
"scanned-at": null,
"file-count": 1163
}
@@ -0,0 +1,84 @@
schema-version: 1
verdict: PASS
score: 96
scores:
project-specificity:
score: 5
evidence:
- "overview: Java 21, Spring Boot 4.0.0, 19개 모듈과 Gradle·ArchUnit 경계를 저장소 근거로 특정한다."
- "project-value: STRICT dependency lock과 sampleOffTest처럼 ca-tmpl 고유의 계약을 전면에 둔다."
reader-journey:
score: 5
evidence:
- "overview → value → architecture → quick-start → adoption → verification → documentation 순서가 평가·실행·전환 흐름을 따른다."
- "각 상세 항목은 독자의 다음 행동인 실행, 코드 배치, sample 제거, 전체 검증으로 이어진다."
technical-explanation:
score: 4
evidence:
- "architecture: Gradle 모듈 정책과 ArchUnit 코드 정책을 구분하고 의존 방향을 Mermaid와 모듈 표로 설명한다."
- "중간 길이 정책에 맞춰 세부 운영 계약은 소유 문서로 넘기므로 README 자체는 의도적으로 개요 수준을 유지한다."
task-usability:
score: 5
evidence:
- "quick-start: prerequisite, 실행 위치, bootstrap 부작용, 성공 endpoint, Compose 종료 명령이 한 흐름에 있다."
- "verification: 일반 테스트·아키텍처·sample 제거·전체 계약을 목적별로 선택할 수 있다."
prose-clarity:
score: 5
evidence:
- "긴 기능 나열을 피하고 강제 영역/선택 영역 표와 짧은 도입 순서로 압축했다."
- "production-ready 같은 근거 없는 표현 없이 적용 한계와 별도 검증 책임을 명시한다."
visual-judgment:
score: 5
evidence:
- "architecture: 구성요소가 여섯 개인 의존 관계에만 Mermaid를 사용하고 런타임 호출도가 아님을 바로 설명한다."
- "나머지 섹션은 표·명령·목록이 더 적합하다는 outline 근거에 따라 추가 시각물을 배제했다."
hard-gates:
passed: true
failures: []
reader-simulations:
30-seconds:
outcome: PASS
evidence:
- "제목과 첫 두 문단에서 기술 기준, 템플릿의 차별점, 목적을 확인할 수 있다."
- "개요의 적합/비적합 문장으로 채택 후보인지 빠르게 판단할 수 있다."
5-minutes:
outcome: PASS
evidence:
- "강제/선택 표, 아키텍처, bootstrap, 성공 신호, 적용 한계가 첫 읽기 경로에 모두 있다."
contributor:
outcome: PASS
evidence:
- "모듈 표와 도입 5단계가 코드 배치 및 sample 교체 경로를 제공한다."
- "검증 명령과 목적별 상세 문서 링크가 다음 작업으로 연결된다."
findings:
- id: QR-003
severity: minor
category: repository-contract
section: quick-start
message: 저장소 테스트가 요구하는 README 호환성 literal 두 개가 최초 후보에서 누락됐다.
evidence:
- "sampleOffTest 실제 실행에서 DeveloperExperienceContractTest.java:62가 실패했다."
- "테스트가 요구하는 세 literal을 readme-contract fact로 추가하고 execution gate가 검사하도록 개선했다."
- "후보에 비가시적 호환성 marker를 추가해 독자용 문구를 왜곡하지 않았다."
route-to: FACTS_EXTRACTED
status: resolved
- id: QR-001
severity: minor
category: command-boundary
section: quick-start
message: bootstrap 내부 Docker preflight 설명이 직접 실행 명령처럼 추출될 수 있었다.
evidence:
- "첫 기술 게이트가 inline docker info를 repository-facts에 없는 문서 명령으로 차단했다."
- "수정 후 설명을 Docker CLI와 daemon 연결 확인이라는 서술로 바꾸고 재검증했다."
route-to: README_DRAFTED
status: resolved
- id: QR-002
severity: minor
category: architecture-clarity
section: overview
message: 초기 레이어 나열의 화살표가 의존 방향으로 오해될 여지가 있었다.
evidence:
- "초기 domain → application → adapter → bootstrap 표기를 중립적인 책임 목록으로 변경했다."
- "실제 의존 방향은 architecture Mermaid에서 별도로 명시한다."
route-to: README_DRAFTED
status: resolved
@@ -0,0 +1,15 @@
# ca-tmpl README quality review
Verdict: **PASS (96/100)**
The candidate is specific to ca-tmpl, follows an evaluation-to-adoption reader
journey, and keeps correctness separate from editorial scoring. Deterministic
checks passed for request, facts, outline conformance, claim provenance, visual
coherence, GitHub Markdown, documented commands, paths, and secret leakage.
The README deliberately stops at architecture and adoption guidance; detailed
environment and operational contracts remain linked to their owning documents.
Three minor issues found during real use—an inline command boundary, an
ambiguous layer arrow, and a repository-owned README literal contract—were
corrected before this PASS review. Required README literals are now represented
as evidence-backed facts and enforced by the execution gate.
@@ -0,0 +1,11 @@
{
"schema-version": 1,
"run-id": "20260717-quality-core-r2",
"repo-id": "ca-tmpl",
"mode": "bootstrap",
"target-repository": "/home/donghyeon/workspace/ca-tmpl",
"harness-version": "0.1.0",
"started-at": null,
"tool-adapter": "codex",
"input-hashes": {}
}
@@ -0,0 +1,307 @@
{
"schema-version": 1,
"mode": "bootstrap",
"current": "APPLIED",
"history": [
{
"state": "INITIALIZED"
},
{
"state": "INPUT_CAPTURED",
"gates": [
{
"name": "request",
"ok": true,
"warnings": [],
"data": null
}
]
},
{
"state": "REPOSITORY_SNAPSHOTTED",
"gates": [
{
"name": "snapshot",
"ok": true,
"warnings": [],
"data": {
"diff-hash": "sha256:4d351050ecdfa25ea9e39b22c7c5bc0c686b60aa1f9fef7a02f86ae073151f1e"
}
}
]
},
{
"state": "FACTS_EXTRACTED",
"gates": [
{
"name": "facts",
"ok": true,
"warnings": [],
"data": {
"fact_ids": [
"F-README-CONTRACT-001",
"F-IDENTITY-001",
"F-STACK-001",
"F-MODULES-001",
"F-DEPENDENCY-POLICY-001",
"F-CODE-BOUNDARY-001",
"F-CORE-001",
"F-COMPOSITION-001",
"F-SAMPLE-001",
"F-BOOTSTRAP-001",
"F-HEALTH-001",
"F-CONTAINER-001",
"F-LOCKS-001",
"F-CHECK-001",
"F-VERIFICATION-COMMANDS-001",
"F-DOCS-001",
"F-TEMPLATE-LIMIT-001"
]
}
}
]
},
{
"state": "PROJECT_PROFILED",
"gates": [
{
"name": "profile",
"ok": true,
"warnings": [],
"data": {
"profile": "project-template"
}
}
]
},
{
"state": "README_PLANNED",
"gates": [
{
"name": "brief",
"ok": true,
"warnings": [],
"data": null
},
{
"name": "outline",
"ok": true,
"warnings": [],
"data": {
"section_ids": [
"overview",
"project-value",
"architecture",
"quick-start",
"adoption",
"verification",
"documentation"
]
}
}
]
},
{
"state": "README_DRAFTED",
"gates": [
{
"name": "conformance",
"ok": true,
"warnings": [],
"data": {
"sections": [
"overview",
"project-value",
"architecture",
"quick-start",
"adoption",
"verification",
"documentation"
]
}
},
{
"name": "claim_map",
"ok": true,
"warnings": [],
"data": {
"claims": [
"C-STACK-001",
"C-POSITION-001",
"C-MODULE-COUNT-001",
"C-FORCED-DEPS-001",
"C-FORCED-CODE-001",
"C-FORCED-LOCKS-001",
"C-FORCED-SAMPLE-001",
"C-VISUAL-MEANING-001",
"C-DOMAIN-001",
"C-APPLICATION-001",
"C-ADAPTERS-001",
"C-SHARED-001",
"C-BOOTSTRAP-MODULE-001",
"C-SAMPLE-ROLE-001",
"C-TWO-LAYERS-001",
"C-PREREQUISITES-001",
"C-BOOTSTRAP-COMMAND-001",
"C-HEALTH-001",
"C-BOOTSTRAP-SIDE-EFFECT-001",
"C-CLEANUP-001",
"C-IDENTITY-001",
"C-ADOPT-SAMPLE-001",
"C-NEW-MODULE-POLICY-001",
"C-VERIFY-TEST-001",
"C-VERIFY-ARCH-001",
"C-VERIFY-SAMPLE-001",
"C-VERIFY-CHECK-001",
"C-CHECK-SCOPE-001",
"C-DOCS-STRATEGY-001",
"C-LIMIT-CHOICES-001",
"C-LIMIT-LOCAL-001"
]
}
}
]
},
{
"state": "VISUALS_PLANNED",
"gates": [
{
"name": "visual_plan",
"ok": true,
"warnings": [],
"data": {
"visuals": [
"architecture-dependency-direction"
]
}
}
]
},
{
"state": "STRUCTURALLY_VALIDATED",
"gates": [
{
"name": "github_markdown",
"ok": true,
"warnings": [],
"data": null
}
]
},
{
"state": "TECHNICALLY_VERIFIED",
"gates": [
{
"name": "verify",
"ok": true,
"warnings": [],
"data": {
"schema-version": 1,
"state": "PASS",
"verification-level": "static",
"execution-verified": false,
"checks": {
"commands": {
"total": 6,
"verified": 6,
"manual-required": 0,
"failed": 0
},
"paths": {
"total": 9,
"verified": 9,
"failed": 0
},
"anchors": {
"total": 0,
"verified": 0,
"failed": 0
},
"readme-contracts": {
"total": 3,
"verified": 3,
"failed": 0
}
},
"failures": [],
"limitations": []
}
},
{
"name": "secret_scan",
"ok": true,
"warnings": [],
"data": null
}
]
},
{
"state": "QUALITY_REVIEWED",
"gates": [
{
"name": "review",
"ok": true,
"warnings": [],
"data": {
"verdict": "PASS",
"score": 96,
"findings": [
{
"id": "QR-003",
"severity": "minor",
"category": "repository-contract",
"section": "quick-start",
"message": "저장소 테스트가 요구하는 README 호환성 literal 두 개가 최초 후보에서 누락됐다.",
"evidence": [
"sampleOffTest 실제 실행에서 DeveloperExperienceContractTest.java:62가 실패했다.",
"테스트가 요구하는 세 literal을 readme-contract fact로 추가하고 execution gate가 검사하도록 개선했다.",
"후보에 비가시적 호환성 marker를 추가해 독자용 문구를 왜곡하지 않았다."
],
"route-to": "FACTS_EXTRACTED",
"status": "resolved"
},
{
"id": "QR-001",
"severity": "minor",
"category": "command-boundary",
"section": "quick-start",
"message": "bootstrap 내부 Docker preflight 설명이 직접 실행 명령처럼 추출될 수 있었다.",
"evidence": [
"첫 기술 게이트가 inline docker info를 repository-facts에 없는 문서 명령으로 차단했다.",
"수정 후 설명을 Docker CLI와 daemon 연결 확인이라는 서술로 바꾸고 재검증했다."
],
"route-to": "README_DRAFTED",
"status": "resolved"
},
{
"id": "QR-002",
"severity": "minor",
"category": "architecture-clarity",
"section": "overview",
"message": "초기 레이어 나열의 화살표가 의존 방향으로 오해될 여지가 있었다.",
"evidence": [
"초기 domain → application → adapter → bootstrap 표기를 중립적인 책임 목록으로 변경했다.",
"실제 의존 방향은 architecture Mermaid에서 별도로 명시한다."
],
"route-to": "README_DRAFTED",
"status": "resolved"
}
]
}
}
]
},
{
"state": "READY_FOR_APPLY",
"gates": []
},
{
"state": "APPLIED",
"gates": []
}
],
"rework": {
"iterations": 0,
"findings": {}
}
}
@@ -0,0 +1,31 @@
{
"schema-version": 1,
"state": "PASS",
"verification-level": "static",
"execution-verified": false,
"checks": {
"commands": {
"total": 6,
"verified": 6,
"manual-required": 0,
"failed": 0
},
"paths": {
"total": 9,
"verified": 9,
"failed": 0
},
"anchors": {
"total": 0,
"verified": 0,
"failed": 0
},
"readme-contracts": {
"total": 3,
"verified": 3,
"failed": 0
}
},
"failures": [],
"limitations": []
}
@@ -0,0 +1,33 @@
schema-version: 1
visuals:
- id: architecture-dependency-direction
section: architecture
type: architecture-diagram
purpose: core, adapter, composition root 사이의 허용된 프로젝트 의존 방향을 한 화면에 설명한다.
placeholder-text: Mermaid flowchart로 inbound와 outbound가 application을 거쳐 domain 방향으로 의존하고 app-bootstrap이 조립하는 관계를 표시한다.
must-show:
- domain-core
- application-core
- inbound adapters
- outbound adapters
- app-bootstrap
- shared-contract
relationships:
- inbound adapters -> application-core
- outbound adapters -> application-core
- application-core -> domain-core
- app-bootstrap -> selected adapters and core
emphasize:
- 화살표는 런타임 호출이 아니라 프로젝트 의존 방향임
- core가 adapter를 알지 않음
avoid:
- 실제로 선언되지 않은 인프라 구성요소
- 모든 adapter가 app-bootstrap에 연결된다는 과장
- 장식용 아이콘과 색상 의존 의미
placement:
after-section-id: architecture
accessibility:
alt-text: inbound와 outbound adapter가 application-core와 domain-core 방향으로 의존하고 app-bootstrap이 선택 모듈을 조립하는 구조
production:
format: mermaid
status: embedded