Files
llm-wiki/raw/branch-notes/feature-skeleton-package-blueprint-contract.md
T

34 KiB

title, source_type, status, branch, related_projects, tags, created, last_reviewed, target_merge, status_label, id, kind, project, work_item, inherits, refines, overrides, depends_on, contract_packet, parent_branch, contract_packet_sha256
title source_type status branch related_projects tags created last_reviewed target_merge status_label id kind project work_item inherits refines overrides depends_on contract_packet parent_branch contract_packet_sha256
branch / feature-skeleton-package-blueprint-contract branch-note verified feature-skeleton-package-blueprint-contract
ca-skeleton
branch
ca-skeleton
package
module
blueprint
2026-05-22 2026-06-04 locally-verified BR-CA-SKELETON-OPERATIONAL-CONTRACT-040 project-work-item ca-skeleton-operational-contract WI-CA-SKELETON-OPERATIONAL-CONTRACT-040
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-BUILD-001@1
1 08f4adda9deebbce6ac685d214e739d3d086211429f2522a2db4886ca1f9cead

branch: feature-skeleton-package-blueprint-contract

Layer: raw/branch-notes/ — 실제 구현 시 package/module 위치가 흔들리지 않도록 skeleton blueprint를 정의합니다.

부모 (필수)

ca-skeleton 은 별도 root branch 없이 project-note 가 SSOT 역할. 본 feature branch 는 project-note 의 운영 계약 중 해당 영역 (§<관련 섹션>) 의 결정/근거/금지 사항을 정제한다.

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 1
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: Gradle module graph가 declared layout과 일치한다

상속한 프로젝트 결정

Decision Ref Project Summary Branch Application Source
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1 Gradle multi-module에서 domain-core·application-core·adapter-*·shared-contract·app-bootstrap·sample-portfolio 책임을 분리한다 Work Item 완료 조건에 적용 raw/project-notes/ca-skeleton-operational-contract
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-BUILD-001@1 build tool은 Gradle Groovy DSL이다 Work Item 완료 조건에 적용 raw/project-notes/ca-skeleton-operational-contract

브랜치 지역 결정

기존 branch-local 결정은 아래 ## Decision Evidence Map / 결정-근거 매핑의 D-row가 소유하며 이 packet에서 복제하지 않는다.

Decision ID Decision Relation Supporting Claims Status

선언한 예외

Override ID Overrides Reason Approval Status

목표

좋은 원칙이 있어도 module boundary와 package 위치를 함께 고정하지 않으면 구현자는 자기 방식으로 구조를 만듭니다. 이 branch는 Gradle multi-module을 1차 경계로 두고, 각 module 내부 package 책임을 Clean Architecture / Hexagonal 규칙에 맞게 고정해 실제 도메인 기능이 바로 들어올 수 있게 합니다.

  • 이슈:
  • PR: (local branch only; remote PR not created in this session)

범위

포함 범위

  • Gradle multi-module blueprint.
  • module dependency direction.
  • module 내부 package blueprint.
  • shared/common module 허용 범위.
  • sample module 격리 기준.
  • architecture rule 연결 기준.
  • single-module 축소형은 예외 mapping으로만 허용.

제외 범위

  • build tool plugin 구현.
  • code generator 구현.

TODO

TODO drained 2026-05-22, revised 2026-05-27 — 결정은 아래 "결정 사항" / "Default Module Blueprint" / "판정 기준" / "테스트 계약" 참조. Gradle multi-module blueprint, module dependency direction, module 내부 package 책임, shared/common 책임, sample 격리, architecture test 모두 결정 라인 또는 blueprint tree로 반영됨. 잔존 TODO 없음.

본 branch는 패키지 트리 자체가 결정 산출물. 별도 Decisionized Work Items 표는 작성하지 않음. 트리의 각 sub-package 책임은 결정 사항과 판정 기준이 등가로 정의.

Work Item Contract

각 TODO는 아래 판정 단위로 재작성되어야 canonical 승급 가능합니다. TODO가 단순히 기준 작성으로 남아 있으면 이 branch는 완료로 보지 않습니다.

field required rule
Decision yes 구현자가 선택해야 하는 기본값
Allowed yes 허용되는 예외와 조건
Forbidden yes 절대 금지되는 구현/문서 상태
Required registry update conditional error/env/header/log/metric/capability 변경 시 필수
Required contract test yes 계약 위반 시 실패해야 하는 테스트
Failure condition yes review/build에서 실패로 판정할 상태
Canonical extraction target yes wiki/projects 승급 위치

결정 사항

  • 2026-05-22: 초기 문서의 기본 구조는 single-module feature-first package layout이었다.
  • 2026-05-27: Phase C2 기본 구조는 Gradle multi-module + Clean Architecture / Hexagonal boundary 로 수정한다. module boundary가 1차 강제선이고, module 내부 package는 2차 책임 분류다.
  • 2026-05-27: 기본 module은 app-bootstrap, domain-core, application-core, adapter-web, adapter-persistence, adapter-outbound, shared-contract, sample-portfolio으로 둔다.
  • 2026-05-27: application-coredomain-coreshared-contract에만 의존한다. Spring Web / JPA / Redis / Kafka / outbound HTTP client 구현체는 adapter module 밖으로 들어오면 안 된다.
  • 2026-05-27: domain-core는 framework-neutral POJO를 기본으로 하며 Spring annotation, JPA annotation, HTTP DTO를 알지 않는다.
  • 2026-05-27: shared-contract에는 response envelope, error code, header/MDC/metric registry, 공통 annotation처럼 skeleton-wide operational contract만 둔다. business/domain concept는 넣지 않는다.
  • 2026-05-27: single-module 구조는 학습/예제 축소형으로만 허용한다. Phase C2 기본값은 multi-module이다.

판정 기준

구분 기준
Decision Gradle multi-module blueprint를 skeleton contract의 기본값으로 관리
Allowed demo/readme용 single-module 축소형은 허용하되, 반드시 multi-module responsibility mapping을 보존
Forbidden domain-core 또는 application-core가 Spring Web/JPA/Redis/Kafka/outbound HTTP 구현체에 직접 의존
Forbidden business/domain concept가 shared-contract 또는 adapter module로 이동
Required mapping bootstrap, domain, application, inbound adapter, outbound adapter, shared contract, sample, architecture/contract test
Failure condition 새 도메인 기능의 module 위치와 dependency direction을 blueprint로 판정할 수 없으면 실패

Default Module Blueprint

settings.gradle
  rootProject.name = 'ca-skeleton'
  include 'app-bootstrap'
  include 'domain-core'
  include 'application-core'
  include 'adapter-web'
  include 'adapter-persistence'
  include 'adapter-outbound'
  include 'shared-contract'
  include 'sample-portfolio'

app-bootstrap/
  src/main/java/{basePackage}/bootstrap/
    CaSkeletonApplication
    config/
  src/test/java/{basePackage}/bootstrap/
    smoke/

shared-contract/
  src/main/java/{basePackage}/shared/
    response/
    error/
    headers/
    logging/
    tracing/
    metrics/
    registry/
    annotation/
  src/test/java/{basePackage}/shared/
    contract/

domain-core/
  src/main/java/{basePackage}/domain/
    model/
    vo/
    event/
    service/
  src/test/java/{basePackage}/domain/
    unit/

application-core/
  src/main/java/{basePackage}/application/
    port/in/
    port/out/
    usecase/
    command/
    query/
    policy/
  src/test/java/{basePackage}/application/
    usecase/
    contract/

adapter-web/
  src/main/java/{basePackage}/adapter/web/
    controller/
    dto/
    mapper/
    filter/
    exception/
  src/test/java/{basePackage}/adapter/web/
    mvc/
    contract/

adapter-persistence/
  src/main/java/{basePackage}/adapter/persistence/
    entity/
    repository/
    mapper/
    migration/
  src/test/java/{basePackage}/adapter/persistence/
    integration/

adapter-outbound/
  src/main/java/{basePackage}/adapter/outbound/
    httpclient/
    messaging/
    cache/
    notification/
  src/test/java/{basePackage}/adapter/outbound/
    contract/

sample-portfolio/
  src/main/java/{basePackage}/sample/worklog/
    domain/
    application/
    web/
    persistence/
  src/test/java/{basePackage}/sample/worklog/
    contract/

Module Dependency Rule

Module May depend on Must not depend on
domain-core (none) or shared-contract value-only types Spring, JPA, HTTP DTO, Redis/Kafka/client libraries, adapter modules
application-core domain-core, shared-contract adapter-*, app-bootstrap, Spring Web/JPA implementation APIs
adapter-web application-core, domain-core, shared-contract adapter-persistence, adapter-outbound direct implementation coupling
adapter-persistence application-core, domain-core, shared-contract adapter-web, app-bootstrap
adapter-outbound application-core, domain-core, shared-contract adapter-web, app-bootstrap
app-bootstrap all runtime modules domain policy implementation
sample-portfolio all runtime modules only as fixture consumer production module importing sample-portfolio

single-module 문서가 필요하면 위 module responsibility mapping을 보존한 축소 변환표를 함께 둡니다. 단, Phase C2 기본 구현은 multi-module이다.

근거 (필수, 최소 1개+)

본 branch의 결정 근거. multi-module 기본값은 company-case-study 근거가 중심이므로, 공식 best practice가 아니라 사례 기반 프로젝트 결정으로 취급한다.

Source 정당화하는 결정
raw/company-tech-blogs/woowahan-hexagonal-multimodule Domain / Application / Framework / Bootstrap module로 hexagonal boundary를 물리 분리한 국내 사례
raw/company-tech-blogs/modulith-kakaobank-techblog-2025 Gradle multi-module + Hexagonal 위에서 application/adapter 계층을 물리 분리하고 Port로 통신한 사례
raw/official-docs/hexagonal-cockburn-wikipedia-summary application core와 adapter를 port로 격리하는 Hexagonal / Ports and Adapters 원형
raw/official-docs/hexagonal-thombergs-buckpal-github feature/package 내부 port-adapter 책임 분리 참고
raw/official-docs/arch-clean-architecture-uncle-bob Dependency Rule과 Entities / Use Cases / Interface Adapters / Frameworks-Drivers 계층 사고 근거 (engineering-blog, official standard 아님)
raw/official-docs/feature-first-uncle-bob-screaming-architecture-2011 framework가 아니라 use case / business 영역이 구조에서 드러나야 한다는 feature-first 사상 근거
raw/company-tech-blogs/feature-first-sahibinden-package-by-layer-vs-feature layer-first 대비 feature 응집도 사례
raw/official-docs/modulith-spring-official-doc package/module boundary verification 대안. Phase C2 기본값은 아니며 후속 검토 후보
raw/company-tech-blogs/modulith-kakaobank-techblog-2025 Spring Modulith를 Gradle multi-module + Hexagonal 위에 체리픽한 사례
raw/company-tech-blogs/modulith-arawn-github-modular-monoliths-spring Spring Modulith 이전 modular monolith reference 구현 사례
raw/official-docs/layer-first-baeldung-clean-architecture-spring-boot layer-first / Clean Architecture 입문형 대안 비교
raw/company-tech-blogs/layer-first-kamilmazurek-github-template layer-first template 대안 비교
raw/company-tech-blogs/hexagonal-woowahan-techblog-2023 hexagonal 적용 사례 비교
raw/official-docs/onion-palermo-original-2008 Onion Architecture dependency direction 비교
raw/company-tech-blogs/onion-allegro-tech-blog-2023 Onion Architecture 적용 사례 비교

외부 근거 / 대안 조사 (2026-05-22 — Topic 1)

본 branch의 청사진 결정은 2026-05-27에 single-module feature-first package 기본값에서 Gradle multi-module Clean Architecture / Hexagonal 기본값으로 수정되었다. 5종 대안 비교는 wiki/concepts/clean-architecture-package-layout.md 참조.

결정-근거 매핑

각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시. Decision ID 는 본 branch-note 안에서 안정적으로 유지 (D1~D8). module tree 와 package 책임도 본 표의 row 로 매핑.

Decision ID Decision Supporting Claims Evidence Strength Open Risk
D1 Phase C2 기본 구조는 Gradle multi-module + Clean Architecture / Hexagonal boundary raw/company-tech-blogs/woowahan-hexagonal-multimodule.md#WW-HEX-C1, raw/company-tech-blogs/modulith-kakaobank-techblog-2025.md#KAKAOBANK-MOD-C4 company-case-study 두 자료 모두 사례이며 공식 표준은 아님. ca-tmpl에 그대로 이식하려면 build.gradle dependency graph와 ArchUnit rule로 별도 검증 필요
D2 domain-core는 framework-neutral domain model을 담고 adapter/framework에 의존하지 않음 raw/company-tech-blogs/woowahan-hexagonal-multimodule.md#WW-HEX-C1, raw/official-docs/arch-clean-architecture-uncle-bob.md company-case-study + engineering-blog shared-contract value-only type까지 허용할지 여부는 ca-tmpl 자체 결정
D3 application-core는 domain에만 직접 의존하고 adapter 구현체와 통신하지 않음 raw/company-tech-blogs/woowahan-hexagonal-multimodule.md#WW-HEX-C2, raw/company-tech-blogs/modulith-kakaobank-techblog-2025.md#KAKAOBANK-MOD-C4 company-case-study Spring transaction boundary를 application port로 추상화할 때 spring-tx 의존을 어느 module에 둘지는 TransactionPort branch와 함께 검증 필요
D4 adapter module은 inbound(adapter-web)와 outbound(adapter-persistence, adapter-outbound)로 물리 분리 raw/company-tech-blogs/modulith-kakaobank-techblog-2025.md#KAKAOBANK-MOD-C4, raw/official-docs/hexagonal-cockburn-wikipedia-summary.md#HEX-WIKI-C5 company-case-study + official-reference adapter를 persistence/outbound로 나누는 세부 module 수는 ca-tmpl 자체 운영 결정
D5 module 간 통신은 public API / port interface를 통해서만 허용 raw/company-tech-blogs/modulith-kakaobank-techblog-2025.md#KAKAOBANK-MOD-C2, raw/company-tech-blogs/modulith-kakaobank-techblog-2025.md#KAKAOBANK-MOD-C4 company-case-study Spring Modulith를 바로 도입하지 않으면 public API 강제는 ArchUnit/package-private convention으로 보완해야 함
D6 shared-contract에는 skeleton-wide operational contract만 두고 business/domain concept는 금지 raw/official-docs/feature-first-uncle-bob-screaming-architecture-2011.md#SCREAM-C1 engineering-blog shared-contract가 커지면 de-facto common dumping ground가 될 수 있음. registry owner와 forbidden import rule 필요
D7 (UNSUPPORTED_DECISION) sample-portfolio은 fixture module이며 production module이 import하면 실패 D1~D5에서 파생된 ca-tmpl 자체 결정 — 외부 공식 근거 없음 project-decision 외부 직접 근거 부족. ArchUnit + Gradle dependency rule로 실증 필요. UNSUPPORTED_DECISION — external official-doc/company-tech-blog claim 없음. 외부 근거 보강 시 갱신 예정
D8 single-module 구조는 축소형 문서/예제로만 허용하고 Phase C2 기본값은 multi-module raw/company-tech-blogs/woowahan-hexagonal-multimodule.md#WW-HEX-C1, raw/company-tech-blogs/modulith-kakaobank-techblog-2025.md#KAKAOBANK-MOD-C4 company-case-study 작은 프로젝트에서는 single-module이 비용이 낮을 수 있음. ca-tmpl은 skeleton template이므로 boundary 학습/검증 비용을 감수한다는 프로젝트 결정
D9 module 간 dependency 선언 기본값은 implementation이며, 소비자 module의 public ABI(port interface 반환·파라미터 타입)에 타 module type이 노출될 때만 api 사용 raw/official-docs/gradle-java-library-api-vs-implementation.md#GRADLE-JAVALIB-C2, raw/official-docs/gradle-java-library-api-vs-implementation.md#GRADLE-JAVALIB-C3, raw/official-docs/gradle-java-library-api-vs-implementation.md#GRADLE-JAVALIB-C4 official-vendor-doc 각 module의 build.gradle dependency 선언 시 api vs implementation 구분 기준이 없어 정책 미정이었던 구멍을 해소. ca-tmpl 8개 module 모두에 적용
D10 @SpringBootApplicationapp-bootstrap 모듈의 dev.caskeleton.bootstrap (root package) 에 배치한다. default package 사용 금지. raw/official-docs/spring-boot-structuring-your-code.md#SB-STRUCT-C1, raw/official-docs/spring-boot-structuring-your-code.md#SB-STRUCT-C2, raw/official-docs/spring-boot-structuring-your-code.md#SB-STRUCT-C3, raw/official-docs/spring-boot-structuring-your-code.md#SB-STRUCT-C4 official-vendor-doc multi-module 구조에서 @SpringBootApplication 이 어느 모듈·패키지에 위치해야 하는지는 이 공식 근거로 직접 뒷받침되지 않음 (단일 모듈 기준 설명). scanBasePackages 추가 설정 필요 여부는 integration test로 검증 필요

검증해야 할 주장

공식 문서나 사례는 근거지만, 내 프로젝트의 실 동작을 자동으로 보장하지 않음.

Claim Why uncertain How to verify Status
Gradle multi-module이 application/domain과 adapter 의존을 build graph 수준에서 차단한다 우아한형제들/카카오뱅크 사례는 구조 사례이며 ca-tmpl build.gradle이 아직 없음 ./gradlew verifyCleanArchitectureDependencies. application-coreadapter-*에 의존하면 실패 locally-verified
domain-core가 framework-neutral POJO로 유지된다 domain module에 Spring/JPA annotation이 들어오는 순간 Clean Architecture 경계가 약해짐 ArchUnit: domain-core에서 org.springframework.., jakarta.persistence.., javax.persistence.. import 금지 locally-verified
application-core가 outbound 구현체가 아닌 port interface만 사용한다 multi-module이어도 project dependency를 잘못 열면 adapter 구현체 직접 호출이 가능 ArchUnit + Gradle: application-core -> adapter-* dependency 금지. 현재 production application-core는 anchor 중심이며, reference repository port는 sample-portfolio/domain/repository에 격리됨 locally-verified
shared-contract가 business common으로 오염되지 않는다 shared module은 커지기 쉬워 domain concept가 흘러들 위험이 있음 ArchUnit package rule: shared에는 response/error/header/logging/tracing/metrics/registry/annotation만 허용. 현재는 package anchor만 존재 locally-verified-empty-anchor
sample-portfolio이 production module로 역수입되지 않는다 sample은 fixture이지만 편의상 production에서 import할 위험이 있음 Gradle dependency rule + ArchUnit: production modules must not depend on sample-portfolio locally-verified
Spring Modulith를 도입하지 않아도 최소 module boundary 검증이 가능하다 Modulith verifier를 쓰지 않으면 public API/named interface 검증이 약할 수 있음 1차는 Gradle dependency + ArchUnit으로 검증. named interface/public API 검증은 Spring Modulith 없이 아직 약함 locally-verified-minimum-boundary

테스트 계약

  • domain-core가 Spring / JPA / HTTP DTO / adapter module type을 참조하면 실패.
  • application-coreadapter-web, adapter-persistence, adapter-outbound, app-bootstrap에 의존하면 실패.
  • adapter module끼리 직접 의존하면 실패. 공유가 필요하면 application port 또는 shared operational contract로 승격해야 함.
  • production module이 sample-portfolio을 import하거나 dependency로 선언하면 실패.
  • shared-contract에 business/domain package 또는 domain-specific class가 추가되면 실패.
  • 새 도메인 기능의 module 위치를 Default Module Blueprint로 판정할 수 없으면 review 실패.

완료 후 wiki 추출 대상

구현 결과

D9 — api vs implementation 정책

  • 결정: 모듈 간 의존은 기본 implementation. 소비자의 public ABI 가 다른 모듈 타입을 노출할 때만 api.
  • 구현: CLAUDE.md (root) §"Gradle api vs implementation policy" 에 명시. 현재 ca-tmpl 의 모든 */build.gradleimplementation 사용 — 별도 코드 변경 없이 정책 충족 (actually-implemented).
  • 검증: cd src && ./gradlew verifyCleanArchitectureDependencies 통과 + ./gradlew check 통과.
  • 잔여: port interface design 완료 후 api 가 필요한 모듈이 등장하면 build.gradle 갱신 + 사용 사례를 본 brunch 의 후속 메모로 기록.

D10 — @SpringBootApplication root package 배치

  • 결정: dev.caskeleton.bootstrap 에 배치. default package 사용 금지.
  • 구현: CaSkeletonApplicationdev.caskeleton.bootstrap package 에 있음 — 충족 (actually-implemented).
  • 추가 설정: @SpringBootApplication(scanBasePackages = "dev.caskeleton") 으로 다른 모듈 (sample-portfolio 포함) 의 component 도 scan 가능. component scan default base package 가 dev.caskeleton.bootstrap 이지만 multi-module 구조라서 scanBasePackages 명시.
  • 검증: cd src && ./gradlew bootRun 시 sample-portfolio 의 Spring component 가 자동 등록되는지 확인 (별도 integration test 미수행, documented-only).

마주친 문제

짧은 메모만 둔다. 깊이 있는 트러블슈팅은 raw/errors/ 로 분리하고 아래 Cluster에 연결한다.

  • 2026-05-27: B안 구현 중 빈 anchor module은 ArchUnit 검사 대상 class가 없어 empty should failure가 발생했다.
    • 원인: skeleton production package가 비어 있는 것이 의도된 상태인데 rule이 empty state를 허용하지 않았다.
    • 해결: 빈 anchor가 유효한 rule에만 allowEmptyShould(true)를 적용했다.
    • 별도 에러 노트로 분리됨: raw/errors/archunit-empty-should-anchor-2026-05-27
  • 2026-05-27: reference code를 sample-portfolio으로 격리한 뒤 InvalidBearerTokenException compile error가 발생했다.
  • 2026-05-27: reference blog의 repository port는 아직 branch-note blueprint의 application/port/out이 아니라 sample-portfolio/domain/repository에 남아 있다. 이는 reference implementation 격리를 우선한 B안 범위의 잔여 차이이며, production use case port 정리는 feature-application-port-usecase-contract branch에서 수행한다.

묶음 (이 branch에서 파생된 자료)

이 branch는 package/module skeleton blueprint의 entry point다. 자식 branch는 없지만, local implementation 중 발생한 error note와 면접 준비 raw note는 아래에 명시적으로 묶는다.

Sub-branches (세부 작업)

  • (없음 — project 직접 자식 branch이며 하위 branch 없음)

근거 자료

오류 기록 (이 branch 작업 중 발생)

면접 준비 (이 작업에서 나올 수 있는 면접 질문)

강의 (이 작업을 위해 학습한 강의)

  • (없음 — 이번 branch는 official-doc/company-tech-blog raw 근거 기반이며 별도 lecture note 없음)

job-posting tie-ins (이 작업에서 파생된 글감)

관련 일일 노트

Ground-truth 대조

ca-tmpl 실제 레포(/home/donghyeon/workspace/ca-tmpl @ 5d89766)와 대조하여 status: raw → verified 승급. 근거: actual code + passing test. 등급은 locally-verified 유지(운영 배포·로그 없음).

주장 ca-tmpl 실재 증거 판정
D1 multi-module 8개 settings.gradle include 8개 일치
D9 전 module implementation, api 0개 9개 build.gradle 모두 api 선언 없음
D10 CaSkeletonApplication @ dev.caskeleton.bootstrap + scanBasePackages="dev.caskeleton" app-bootstrap/src/main/java/dev/caskeleton/bootstrap/CaSkeletonApplication.java
verifyCleanArchitectureDependencies task root build.gradle:53 등록
CleanArchitectureTest app-bootstrap/.../architecture/CleanArchitectureTest.java
anchor package-info.java domain-core·shared-contract·adapter-* 존재
sample reference 격리 dev.caskeleton.sample.portfolio.*.worklog

관찰된 drift (이 branch 결정 범위 밖 — 추출 시 보정):

  • Drift① — 9번째 module adapter-identifier: 실제 settings.gradle에는 blueprint 8개 + adapter-identifier가 있음. 본 branch 결정이 아니라 후속 feature-resource-identifier-contract(commit c36b764)가 추가. blueprint 결정으로 흡수하지 않고 OUT_OF_BRANCH_SCOPE로 기록. canonical 블루프린트 추출 시 "adapter module은 책임별로 확장 가능(예: adapter-identifier)"으로만 각주.
  • Drift② — sample package 경로: blueprint tree는 {basePackage}/sample/worklog/이나 실제는 dev.caskeleton.sample.portfolio.{domain,application}.worklog(중간 portfolio. 한 단계 추가). 계획 대비 구현 divergence. canonical 추출 시 실제 경로 사용.

진행 중 메모

  • module blueprint와 dependency rule의 적용 상태는 구현 결과 및 ground-truth 대조 절에서 추적한다.

구현 가이드

  • domain-core·application-core·adapter-*·shared-contract·app-bootstrap의 책임을 Gradle module과 package 양쪽에 고정한다.
  • 허용 dependency는 한 방향으로만 선언하고 forbidden fixture가 architecture gate에서 실패해야 한다.
  • 신규 domain onboarding은 blueprint를 복사하지 않고 이 문서의 module 책임을 참조한다.

엣지·실패·의존

  • 순환 module dependency·bootstrap 역참조·shared-contract의 구현 의존 유입은 build 또는 architecture test에서 차단한다.
  • onboarding·application port·architecture enforcement 계약이 본 blueprint를 소비한다.

완료 후 정리

2026-05-27 local implementation 기준 정리. 원격 PR/머지는 이 세션에서 수행하지 않음.

  • PR 링크: (미생성 — local branch feature/skeleton-package-blueprint-contract)
  • 리뷰 메모: Gradle module rename, package anchor, ArchUnit/Gradle boundary rule, README/agent rule update, dev.caskeleton skeleton package rename, sample-portfolio reference 격리까지 B안 범위로 반영.
  • 머지 결과 / 배포 환경: 미머지, 미배포. ca-tmpl template local verification만 수행.
  • wiki 추출 대상 (verified만, wiki/projects/로만 추출):
    • actually-implemented 항목:
      • settings.gradle include가 app-bootstrap, domain-core, application-core, adapter-web, adapter-persistence, adapter-outbound, shared-contract, sample-portfolio로 전환됨.
      • production package root가 dev.caskeleton로 전환되고 BlogApplicationCaSkeletonApplication, CmdSettingsBootstrapSettings, blog.* 설정 prefix는 ca-skeleton.*로 전환됨.
      • 기존 reference code는 production module에서 sample-portfolio 내부 dev.caskeleton.sample.worklog.* package로 격리됨.
      • domain-core, application-core, adapter-persistence, adapter-outbound, shared-contract는 skeleton anchor package와 package-info.java 중심으로 유지됨.
      • AGENTS.md, CLAUDE.md, module CLAUDE.md, README가 새 module vocabulary로 갱신됨.
    • locally-verified 항목:
      • ./gradlew verifyCleanArchitectureDependencies 통과.
      • ./gradlew :app-bootstrap:test --tests '*CleanArchitectureTest' 통과.
      • ./gradlew :adapter-web:test --tests '*SettingsTest' 통과.
      • ./gradlew test 통과.
    • prod-verified 항목:
      • 없음. ca-tmpl은 template repository이며 운영 배포/운영 로그 검증 없음.
  • 추출하지 않을 항목 (planned / documented-only / abandoned):
    • Spring Modulith named interface 검증 도입은 후속 검토 후보.
    • application/port/in, application/port/out로 reference blog port를 완전히 재배치하는 작업은 feature-application-port-usecase-contract branch에서 수행.
    • sample-portfolio 실제 worklog fixture 구현은 후속 sample fixture branch에서 수행.