# ca-tmpl — 경계를 실행 가능한 규칙으로 만드는 Spring Boot 템플릿 `ca-tmpl`은 Java 21과 Spring Boot 4.0.0을 기준으로 구성된 멀티 모듈 서비스 템플릿입니다. 이 저장소의 초점은 기능 예제를 많이 제공하는 데 있지 않습니다. domain, application, adapter, bootstrap의 책임을 나누고, 그 경계가 기능 추가 과정에서 무너지지 않도록 Gradle과 ArchUnit 검증을 함께 제공하는 데 있습니다. ## 템플릿 개요 19개 Gradle 모듈이 core, inbound adapter, outbound adapter, composition root, sample 역할로 선언되어 있습니다. 다음 상황에 특히 잘 맞습니다. - 새 Java 서비스에서 모듈 경계와 검증 기준을 함께 시작하려는 경우 - HTTP·메시징·캐시·영속성 같은 기술 세부사항을 유스케이스와 분리하려는 경우 - 예제 코드를 제거한 뒤에도 핵심 구조가 독립적으로 성립하는지 자동 검증하려는 경우 반대로 단일 모듈 CRUD 예제나 특정 조직의 운영 정책까지 완성된 배포판이 필요하다면, 이 템플릿의 범위보다 가벼운 시작점 또는 별도의 플랫폼 기준이 더 적합할 수 있습니다. ## 저장소가 강제하는 것, 도입자가 결정할 것 | 저장소가 실행 가능하게 강제하는 것 | 도입자가 서비스 맥락에 맞게 결정할 것 | | --- | --- | | 모든 선언 모듈을 의존성 정책에 포함하고 허용되지 않은 프로젝트 의존성을 실패시킵니다. | 실제 도메인 경계와 bounded context | | application 코드가 adapter·bootstrap·transport·persistence에 의존하지 못하도록 검사합니다. | 사용할 inbound·outbound adapter의 범위 | | leaf module의 모든 dependency configuration을 STRICT lock mode로 검증합니다. | 배포 플랫폼, SLO, 용량과 장애 복구 정책 | | 같은 핵심 테스트를 `sample-portfolio` 없이 컴파일·실행하는 경로를 제공합니다. | 인증·인가, 데이터 보존, 외부 연동의 서비스별 정책 | 이 구분이 중요합니다. 템플릿은 “어떤 결정을 해야 하는가”와 경계를 지키는 장치를 제공하지만, 서비스 고유의 결정을 대신하지는 않습니다. ## 아키텍처와 코드 배치 다음 그림의 화살표는 런타임 호출 순서가 아니라 허용된 프로젝트 의존 방향을 요약합니다. ```mermaid flowchart LR Inbound[Inbound adapters
web · gRPC · GraphQL · WebSocket] Application[application-core
use cases · ports] Domain[domain-core
business invariants] Outbound[Outbound adapters
persistence · messaging · cache · integrations] Shared[shared-contract
operational contracts] Bootstrap[app-bootstrap
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` | 외부 라이브러리 의존성 없이 비즈니스 불변식과 도메인 타입을 둡니다. | | `application-core` | `domain-core`와 `shared-contract`에 의존하며 유스케이스와 port를 둡니다. | | `adapter:inbound:*` / `adapter:outbound:*` | 전송 계층 입력과 기술별 출력 구현을 core 바깥에 둡니다. | | `shared-contract` | 비즈니스 개념이 아닌 공용 운영 계약을 둡니다. | | `app-bootstrap` | 선택한 core와 adapter를 조립하고 Spring Boot 진입점을 소유합니다. | | `sample-portfolio` | 템플릿 사용법을 보여주는 참조 구현이며 일반 테스트의 fixture로만 연결됩니다. | Gradle의 `verifyCleanArchitectureDependencies`는 모듈 간 의존 방향을, `CleanArchitectureTest`는 application 패키지의 adapter·transport 접근과 같은 코드 수준 경계를 검사합니다. ## 빠른 시작 필요한 도구는 JDK 21과 실행 중인 Docker daemon입니다. 저장소의 도구 버전 파일은 Temurin 21.0.11+10을 지정하고, bootstrap preflight는 Docker CLI가 daemon에 연결되는지 확인합니다. 저장소 루트에서 다음을 실행합니다. ```bash cd src ./gradlew bootstrap ``` `./gradlew bootstrap`은 전체 소스 컴파일, Docker 확인, 로컬 PostgreSQL과 앱 시작, sample 격리 계약, HTTP smoke check를 순서대로 실행합니다. 성공 조건은 `http://localhost:8080/api/healthcheck`가 HTTP 200과 `status=UP`을 반환하는 것입니다. bootstrap은 Compose의 `app`과 `db` 서비스를 백그라운드로 시작합니다. 작업을 마치면 저장소 루트에서 종료합니다. ```bash cd .. docker compose -f docker-compose.yml -f docker-compose.local.yml down ``` 위 Compose 명령은 저장소에 선언된 base와 local 구성 파일을 함께 사용해 서비스를 종료합니다. ## 실제 프로젝트로 전환하기 한 번에 모든 이름과 모듈을 지우기보다, 각 단계에서 검증 가능한 상태를 유지하는 편이 안전합니다. 1. **식별자를 먼저 정합니다.** Gradle root name은 `ca-skeleton`, Java package root와 main class는 `dev.caskeleton` 아래에 선언되어 있으므로 서비스 이름과 namespace 정책에 맞게 함께 변경합니다. 2. **도메인과 유스케이스를 core에 세웁니다.** 비즈니스 불변식은 `domain-core`, 유스케이스와 port는 `application-core`에 둡니다. 3. **필요한 adapter만 선택합니다.** 전송 기술은 inbound, 데이터베이스·메시징·캐시·외부 연동은 outbound 모듈에서 선택하고 `app-bootstrap`에서 조립합니다. 4. **환경·운영 계약을 서비스 기준으로 확정합니다.** 환경 키 레지스트리와 Compose 기본값을 검토하되, 조직의 secret 관리·배포·관측 정책을 별도로 적용합니다. 5. **sample을 제거하고 독립성을 확인합니다.** `sample-portfolio`는 일반 테스트의 `sampleFixture`로만 연결되며 `sampleOffTest`는 샘플 없는 classpath에서 같은 핵심 테스트 corpus를 실행합니다. 도입 중 코드의 위치가 애매하면 “이 코드는 비즈니스 규칙인가, 유스케이스 조정인가, 기술 구현인가, 조립인가?”를 먼저 묻고 위 모듈 표에 배치하십시오. 새 모듈을 추가하면 Gradle 의존성 정책에도 명시적으로 등록해야 합니다. ## 검증 루프 작업 목적에 맞는 가장 작은 검증부터 실행하고, 변경을 공유하기 전 전체 계약으로 넓힙니다. - 일반 테스트: `./gradlew test` - 모듈 의존 방향만 빠르게 확인: `./gradlew verifyCleanArchitectureDependencies` - sample 제거 가능성 확인: `./gradlew :app-bootstrap:sampleOffTest` - 전체 품질 계약: `./gradlew check` ```bash cd src ./gradlew test ./gradlew verifyCleanArchitectureDependencies ./gradlew :app-bootstrap:sampleOffTest ./gradlew check ``` `check`는 테스트뿐 아니라 아키텍처 의존성, 환경 키, 산출물, 타입 배치, 취약점 예외, quarantine 만료, README 명령 검증을 집계합니다. ## 상세 문서 지도와 적용 한계 README는 판단과 첫 실행에 필요한 정보만 유지합니다. 세부 계약은 소유 위치에서 확인하십시오. - [빌드·실행·환경 설정](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 모듈이 포함되어 있지만 실제 서비스가 채택할 범위와 배포 환경은 템플릿이 결정하지 않습니다. - 기본 로컬 실행 경로는 Docker와 PostgreSQL 16 Compose 서비스를 전제로 합니다. - 자동 검증은 저장소 내부의 구조·구성 계약을 지킵니다. 조직별 threat model, SLO, 부하 특성, 데이터 보존과 복구 목표는 별도의 설계·검증 대상입니다.