32 KiB
title, source_type, status, branch, parent_branch, related_projects, governing_docs, tags, created, target_merge, status_label, id, kind, project, work_item, inherits, refines, overrides, depends_on, contract_packet, contract_packet_sha256
| title | source_type | status | branch | parent_branch | related_projects | governing_docs | tags | created | target_merge | status_label | id | kind | project | work_item | inherits | refines | overrides | depends_on | contract_packet | contract_packet_sha256 | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| branch / feature-sample-removal-adoption-contract | branch-note | raw | feature-sample-removal-adoption-contract |
|
|
|
2026-05-22 | review | BR-CA-SKELETON-OPERATIONAL-CONTRACT-039 | project-work-item | ca-skeleton-operational-contract | WI-CA-SKELETON-OPERATIONAL-CONTRACT-039 |
|
1 | 0039db652603df9d69ce72db49b6cd7ac22d717c9e9f52c3e74ea69c89d2d993 |
branch: feature-sample-removal-adoption-contract
Layer:
raw/branch-notes/—sample-portfolio모듈은 skeleton fixture/reference로 유지하되, production runtime과 새 도메인이 sample에 의존하지 않도록 하는 adoption 기준을 정의합니다.
부모 (필수)
- Parent project (canonical SSOT): raw/project-notes/ca-skeleton-operational-contract
ca-skeleton 은 별도 root branch 없이 project-note 가 SSOT 역할. 본 feature branch 는 project-note 의 sample fixture / adoption 영역을 multi-module Clean Architecture 기준으로 정제한다.
브랜치 계약 패킷
- 생성 시 프로젝트 개정:
1 - 패킷 스키마:
contract_packet: 1 - 완료 조건: sample 제거 후 production module smoke test가 통과한다
상속한 프로젝트 결정
| 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 |
브랜치 지역 결정
기존 branch-local 결정은 아래
## Decision Evidence Map / 결정-근거 매핑의 D-row가 소유하며 이 packet에서 복제하지 않는다.
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|
선언한 예외
| Override ID | Overrides | Reason | Approval | Status |
|---|
목표
sample-portfolio은 production feature가 아니라 contract fixture입니다. template repository에서는 sample-portfolio 모듈을 유지해야 합니다. 실제 프로젝트 시작 시에는 sample을 runtime에서 비활성화하고, 새 도메인이 sample import 없이 같은 contract를 따르는지 검증해야 합니다. fork한 프로젝트에서 sample 코드를 정리할 수는 있지만, ca-tmpl 기본 blueprint에서 sample-portfolio 모듈을 삭제하는 것은 목표가 아닙니다.
- 이슈:
- PR:
범위
포함 범위
sample-portfoliomodule 유지 기준과 production runtime 비활성화 기준.- sample disabled profile 기준.
app-bootstrap에서 sample wiring을 profile 조건으로 격리하는 기준.- core contract test 유지 기준.
- 새 도메인 adoption checklist는
feature-domain-feature-onboarding-contract의 New Domain Module Slice를 consume. - sample removal smoke test.
- README/wiki adoption guide 기준.
제외 범위
- 실제 프로젝트 도메인 구현.
- generator CLI 구현.
sample-portfolio실제 scenario 구현.- Backstage / Initializr 같은 별도 scaffolding platform 구현.
근거 (필수, 최소 1개+)
| Source | 정당화하는 결정 |
|---|---|
| raw/branch-notes/feature-skeleton-package-blueprint-contract | sample-portfolio이 기본 blueprint에 포함되는 fixture module이며 core module responsibility mapping을 보존해야 한다는 프로젝트 SSOT |
| raw/branch-notes/feature-domain-feature-onboarding-contract | 새 도메인 adoption checklist의 SSOT. 본 branch는 checklist를 중복 정의하지 않고 consume |
| raw/branch-notes/feature-architecture-enforcement-rules | production module이 sample-portfolio에 의존하지 못하도록 강제할 architecture rule 기준 |
| raw/official-docs/scaffolding-spring-initializr | generator 시점 sample-off 모델과 ca-tmpl dual-mode 검증 모델의 차이 |
| raw/official-docs/scaffolding-cookiecutter-official | 변수 치환 generator와 in-repo fixture removal 모델의 차이 |
| raw/official-docs/scaffolding-degit-svelte-github | clone 이후 정리 방식과 2-step removal 비교 근거 |
| raw/official-docs/scaffolding-github-template-repository | repository template 방식이 ca-tmpl의 기준 scaffolding 경로라는 대조 근거 |
| raw/company-tech-blogs/scaffolding-backstage-golden-path-spotify | 조직 IDP 단계 대안. ca-tmpl branch 범위에서는 채택하지 않음 |
TODO
각 항목 옆에 증거 등급 표기: actually-implemented | locally-verified | prod-verified | documented-only | planned | needs-confirmation
sample-portfolio을 removable module이 아니라 유지되는 fixture/reference module로 정의 — 등급:actually-implemented(src/settings.gradleinclude 'sample-portfolio')- production module →
sample-portfolioimport 차단 — 등급:actually-implemented(ArchUnitproduction_code_does_not_depend_on_sample_portfolio+ GradlesampleFixturescope) - sample-on / sample-off dual-mode verification 기준 정의 (build/test matrix — D7) — 등급:
actually-implemented - 새 도메인 adoption checklist owner를
feature-domain-feature-onboarding-contract로 분리 — 등급:documented-only - sample-off build (test classpath 에서 sample 제외) gradle task/source-set 구현 — 등급:
actually-implemented(D7 build/test matrix; runtime profile 아님) - sample-off build에서
./gradlew test와 architecture rule 통과 검증 — 등급:locally-verified - dual-mode CI matrix GitHub Actions workflow 작성 (sample on/off test classpath 두 축) — 등급:
actually-implemented
진행 중 메모
- 2026-05-28: Phase C2 package blueprint가 Gradle multi-module로 바뀌었으므로 기존 단일 package 삭제 방식과 단일 package adoption checklist는 폐기한다.
sample-portfoliomodule 자체는 template fixture로 유지한다. - 본 branch는 sample-off lifecycle을 소유한다. 새 도메인 module slice 자체는
feature-domain-feature-onboarding-contract가 소유한다. - 2026-06-15: ca-tmpl 코드 대조 결과 — 당시
sample-portfolio은testImplementation(test classpath only) 로 배선돼 있어 production app 에 sample bean/endpoint 가 애초에 로드되지 않았다. 따라서 D1(import 차단)은actually-implemented. 반대로 "sample-off profile 로 runtime 노출 차단"이라는 전제는 끌 runtime sample 이 없으므로 코드 현황과 어긋난다 — §Audit & FindingsSAMPLE_RUNTIME_MODEL_DRIFT참조. - 2026-06-15: 위 drift 를 사용자 결정으로 종결 — dual-mode = build/test matrix (runtime Spring profile 아님). sample-on=fixture 포함 test, sample-off=test classpath 에서 sample 제외 후 core 계약 test. D7 로 승격하고 D3/D4/Adoption Contract/구현 가이드 §2·§3 정합. sample 은 계속 production 의존 0 (ArchUnit 구조적 분리 보존).
- 2026-06-25: 구현 완료 —
app-bootstrap에sampleFixture(declarable fixture dependency)와sampleOffTestsource set/task를 추가했다.sampleOffTest는 동일 test source를 재사용하되sample-portfolio를 classpath에서 제외하고 main output을 포함한다. - 2026-06-25:
app-bootstrapcore contract test에서 직접 sample import를 제거하고, sample 전용PortfolioErrorCodeRegistryMappingTest는sample-portfolio모듈로 이동했다. - 2026-06-25: sample-off classpath에서 ArchUnit이
sampleOffTestoutput을 production class로 오인하지 않도록ProductionClassImportOption을 추가했다. - 2026-06-25: CI quality gates에 release-blocking
sample-offjob을 추가하고 gate matrix registry에sample-off-build를 등록했다.
결정 사항
- 2026-05-22:
sample-portfolio은 production code에서 import하면 안 됨. / 이유: fixture와 production feature를 분리 / 검토한 대안: sample을 production 예제로 유지 / 근거: raw/official-docs/scaffolding-spring-initializr - 2026-05-22: sample 제거 후에도 error/log/env/security/architecture contract test는 남아야 함. / 이유: sample 제거가 core contract 제거로 이어지면 skeleton 품질을 판정할 수 없음 / 검토한 대안: sample 관련 test 일괄 제거 / 근거: project decision
- 2026-05-22: sample-off CI matrix = sample-on profile과 sample-off profile 모두 release-blocking. / 이유: fixture가 있을 때와 없을 때 core contract를 모두 확인 / 검토한 대안: sample-off만 검증 / 근거: raw/official-docs/scaffolding-github-template-repository
- 2026-05-22: sample 비활성화 방식 = sample profile을 명시적으로 꺼서 runtime 노출을 차단하고,
sample-portfoliomodule은 template fixture/reference로 유지한다. fork한 프로젝트의 code cleanup은 선택 사항이다. / 이유: skeleton 검증 자산을 보존하면서 production dependency를 차단 / 검토한 대안: template에서 sample module 삭제 / 근거: raw/official-docs/scaffolding-degit-svelte-github - 2026-05-28: 새 도메인 adoption checklist는 본 branch가 중복 정의하지 않고
feature-domain-feature-onboarding-contract의 New Domain Module Slice + Read/Write Difference Table을 consume한다. / 이유: module slice SSOT 충돌 방지 / 검토한 대안: sample-removal branch에 별도 checklist 유지 / 근거: raw/branch-notes/feature-domain-feature-onboarding-contract
결정-근거 매핑
선택 조건열(R2): "이 조건일 때 이 결정, 다른 조건이면 어떤 대안". 분기 없으면N/A.
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|---|
| D1 | sample-portfolio은 production module에서 import 금지 |
sample 이 production feature 가 아닌 fixture 인 모든 ca-tmpl 컨텍스트에서 항상 적용 (skeleton 불변식). 대안(sample 을 production 예제로 유지)은 sample 이 실제 feature 인 다운스트림 프로젝트에서만 — ca-tmpl 은 fixture 이므로 부적용 | raw/branch-notes/feature-architecture-enforcement-rules.md, raw/official-docs/scaffolding-spring-initializr.md#SCAF-SI-C1; ca-tmpl 코드: ArchUnit production_code_does_not_depend_on_sample_portfolio + sampleFixture project(':sample-portfolio') |
project-decision + official-vendor-doc contrast + actually-implemented |
없음 (코드+ArchUnit 으로 강제됨). 단 reflection/bean lookup 경유 참조는 ArchUnit 사각 — §Claims |
| D2 | sample-off 상태에서도 core contract test 유지 | core 계약 test 가 sample 에 독립일 때 항상 유지. 대안(sample 관련 test 일괄 제거)은 core 계약이 sample 에만 존재할 때나 가능 — ca-tmpl 은 contract test 가 app-bootstrap 에 sample 독립으로 존재하므로 부적용 |
raw/branch-notes/feature-contract-verification-test-suite.md, raw/branch-notes/feature-skeleton-package-blueprint-contract.md; ca-tmpl 코드: sampleOffTest task + sample 직접 import 제거 |
project-decision + locally-verified |
GitHub hosted CI 실행 결과는 별도 확인 필요 |
| D3 | sample-on / sample-off dual-mode verification 유지 (구체 모델은 D7 = build/test matrix) | fixture 를 repo 에 유지하는 template repository 모델일 때 dual-mode. 대안(sample-off 단일 검증)은 fixture 를 generator 시점에 제거하는 Initializr/Cookiecutter 형 scaffolding 일 때 — ca-tmpl 은 in-repo fixture 유지 모델이므로 dual-mode | raw/official-docs/scaffolding-github-template-repository.md#SCAF-GH-C1, raw/official-docs/scaffolding-github-template-repository.md#SCAF-GH-C4, raw/official-docs/scaffolding-cookiecutter-official.md#SCAF-CC-C4; .github/workflows/ci-quality-gates.yml sample-off job |
official-vendor-doc contrast + actually-implemented + locally-verified |
GitHub template이 repo-level Secrets/branch protection까지 복제한다는 뜻은 아님. Hosted CI execution은 needs-confirmation |
| D4 | 2-step adoption = sample 을 build/test 에서 배제(sample-off, D7) 후 optional fork cleanup, ca-tmpl template 에서는 sample-portfolio module 유지 |
ca-tmpl 기본 blueprint = module 유지 + production dependency 0(항상). 대안(template 에서 sample module 삭제)은 fork 한 다운스트림이 fixture 검증 자산이 더는 불필요하다고 판단할 때만(선택) | raw/official-docs/scaffolding-degit-svelte-github.md#SCAF-DG-C3, raw/official-docs/scaffolding-spring-initializr.md#SCAF-SI-C1 |
official-vendor-doc contrast + project-decision |
없음 — D7 이 runtime-profile drift 를 build/test matrix 로 종결(§Audit SAMPLE_RUNTIME_MODEL_DRIFT RESOLVED) |
| D5 | 새 도메인 adoption checklist는 onboarding branch를 consume | module slice/onboarding 결정의 owner branch 가 별도로 존재할 때 consume(현 상태). 대안(본 branch 에 checklist 유지)은 onboarding owner branch 가 없을 때만 | raw/branch-notes/feature-domain-feature-onboarding-contract.md, raw/branch-notes/feature-skeleton-package-blueprint-contract.md |
project-decision |
onboarding branch가 바뀌면 본 branch의 검증 문구도 같이 갱신 필요 |
| D6 | Backstage Golden Path는 조직 IDP 단계라 본 branch 기본값으로 채택하지 않음 | 단일 repo skeleton 단계 = 미채택. 대안(Backstage 채택)은 service template/scorecard/catalog 를 별도 운영할 조직 IDP 규모 이후 | raw/company-tech-blogs/scaffolding-backstage-golden-path-spotify.md#BACKSTAGE-TMPL-C4, raw/company-tech-blogs/scaffolding-backstage-golden-path-spotify.md#BACKSTAGE-TMPL-C5 |
company-case-study |
company-case-study를 공식 best practice로 격상하지 않도록 주의 |
| D7 | sample-off / dual-mode 의 구체 모델 = build/test matrix (Spring runtime profile 아님) — sample-on = contract test 가 sample fixture 와 함께 실행 / sample-off = core 계약 test 가 sample 없이 실행 | 현행 wiring 이 testImplementation(test classpath only)이라 끌 runtime sample 이 없을 때(현 상태) = build/test matrix. 대안(profile-gated production dependency 로 승격해 runtime @Profile("sample") 데모 제공)은 채택자에게 동작 endpoint 데모가 필요하고 sample 을 production 의존으로 둬도 될 때 — ca-tmpl 은 구조적 분리(ArchUnit production→sample 0) 보존이 우선이므로 미채택 |
ca-tmpl 코드: sampleFixture project(':sample-portfolio'), sampleOffTest, SampleRemovalSmokeContractTest, ProductionClassImportOption, .github/workflows/ci-quality-gates.yml sample-off job |
actually-implemented + locally-verified + project-decision (사용자 확정 2026-06-15) |
Hosted CI execution은 needs-confirmation |
| D8 | reference scaffolding 1순위 = GitHub Template Repository | template-repo 형 scaffolding 일 때 1순위 — CI/Actions workflow 파일까지 복제돼 friction 최저. 대안(Spring Initializr/Cookiecutter/degit/Yeoman/Maven archetype)은 generator 시점 sample 제거 모델이라 dual-mode 검증 의미가 다름; Backstage 는 조직 IDP 규모 이후(D6) | raw/official-docs/scaffolding-github-template-repository.md#SCAF-GH-C1, raw/official-docs/scaffolding-github-template-repository.md#SCAF-GH-C4, raw/official-docs/scaffolding-spring-initializr.md#SCAF-SI-C1, raw/official-docs/scaffolding-cookiecutter-official.md#SCAF-CC-C4 |
official-vendor-doc contrast |
Actions 는 복제되나 Secrets/branch protection 은 별도 — §Claims needs-confirmation |
구현 가이드
결정 이 "무엇" 이라면 본 §는 "어디에 어떻게" 의 사전 명세. 각 sub-section 은 본 branch 의 결정 + 근거에서 도출되는 in-scope 항목만 다룬다(3-rule meta principle, CLAUDE.md §15.5). ca-tmpl 코드 anchor 는 2026-06-15 grep 으로 확인.
1. Production → sample-portfolio 의존 차단 (D1)
Trace: D1 +
feature-architecture-enforcement-rules(ArchUnit rule owner) +scaffolding-spring-initializr#SCAF-SI-C1.
- UNSUPPORTED_IMPL_DECISION: 없음 — 메커니즘이 이미 코드에 구현됨(
actually-implemented).
| 강제 지점 | 메커니즘 | 위치 | 등급 |
|---|---|---|---|
| ArchUnit rule | noClasses().that().resideOutsideOfPackage("..sample.portfolio..").should().dependOnClassesThat().resideInAPackage("..sample.portfolio..") |
src/app-bootstrap/.../architecture/CleanArchitectureTest.java:576-581 |
actually-implemented |
| Gradle scope | sampleFixture project(':sample-portfolio') — production scope 아님(sample 은 fixture/test classpath only) |
src/app-bootstrap/build.gradle |
actually-implemented |
| module include | include 'sample-portfolio' — 삭제하지 않고 유지 |
src/settings.gradle |
actually-implemented |
ArchUnit rule 의 owner 는 raw/branch-notes/feature-architecture-enforcement-rules — 본 branch 는 그 rule 을 consume 하고 sample 특화 회귀(dummy import → fail)만 검증한다(§Claims).
2. sample-off = build/test 에서 sample 배제 (D4, D7)
Trace: D7(build/test matrix 확정) + D4 +
scaffolding-degit-svelte-github#SCAF-DG-C3. runtime Spring profile 이 아니다 — sample 은 fixture/test classpath only라 production app 에 애초에 로드되지 않으므로(§Audit RESOLVED), sample-off 는 test classpath 에서 sample 을 빼고 core 계약 test 를 돌리는 build/test 모드다.
- UNSUPPORTED_IMPL_DECISION: sample 을 test classpath 에서 제외하는 gradle 메커니즘(별도 source-set / 전용 test task /
-PsampleOffproperty 분기)은 근거 raw 가 권고하지 않음 — 임의 trade-off. 구현에서는 normaltest와 동일 source를 재사용하는sampleOffTestsource set/task를 채택했다.sample-portfolio직접 import가 있던 core contract test는 app-bootstrap에서 제거하고 sample-owned check로 이동했다.
| 항목 | 명세 | 위치(예정) | 등급 |
|---|---|---|---|
| sample runtime 노출 | production app 에 sample bean/route 없음 — sampleFixture fixture scope라 구조적으로 이미 off |
— | actually-implemented |
| sample-on (test) | sample fixture 가 test classpath 에 포함된 상태로 contract test 실행 | 기존 ./gradlew test |
locally-verified |
| sample-off (test) | sample 을 test classpath 에서 제외하고 core 계약 test 실행 | src/app-bootstrap/build.gradle sampleOffTest |
locally-verified |
| sample-off smoke | sample classpath 부재, core healthcheck endpoint 통과, runtime toggle 부재 확인 | SampleRemovalSmokeContractTest, OperationalContractRuntimeTest |
locally-verified |
3. dual-mode CI matrix (D3, D7)
Trace: D3 + D7(build/test matrix) +
scaffolding-github-template-repository#SCAF-GH-C1/C4,scaffolding-cookiecutter-official#SCAF-CC-C4. CI matrix 의 두 축은 runtime profile 이 아니라 test classpath 의 sample on/off.
- UNSUPPORTED_IMPL_DECISION: GitHub Actions matrix 축 이름·gradle task 분기 방식은 근거 raw 가 "둘 다 release-blocking" 원칙만 권고 — 구체 detail 은 임의 trade-off. 구현에서는 기존 quality-gates workflow에
sample-offjob을 추가하고 gate matrix registry에sample-off-buildrow를 등록했다.
| job | 검증 대상 | 등급 |
|---|---|---|
sample-on |
sample fixture 가 test classpath 에 포함된 상태에서 envelope/capability/transaction/idempotency 계약 통과 | actually-implemented (기존 quality gates) |
sample-off |
sample 을 test classpath 에서 제외한 상태에서 동일 core 계약 통과(회귀 방지) | actually-implemented (ci-quality-gates.yml, ci-gate-matrix.yml) |
4. core contract test 보존 (D2)
Trace: D2 +
feature-contract-verification-test-suite.
- UNSUPPORTED_IMPL_DECISION: 없음 — 보존 대상이 이미 존재하는 계약 test 집합.
- 현존 계약 test:
src/app-bootstrap/.../contract/*(ErrorCodeRegistryMappingTest, SecretsClassificationRegistryTest, RepositoryAccessCapabilityRegistryTest, Outbox*ContractTest 등) — sample 독립. 등급actually-implemented. - sample-off 실행 모드에서도 동일 통과해야 함 —
./gradlew :app-bootstrap:sampleOffTest로locally-verified.
5. onboarding checklist consume (D5)
Trace: D5.
- UNSUPPORTED_IMPL_DECISION: 없음 — link-only 위임.
- 본 branch 는 New Domain Module Slice/Read·Write Difference Table 을 정의하지 않는다(중복 정의 시 SSOT drift). raw/branch-notes/feature-domain-feature-onboarding-contract 의 해당 표를 link 만 한다.
Adoption Contract
| step | required result |
|---|---|
| sample-off (build/test) | sample 을 test classpath 에서 제외한 상태에서 core 계약 test 통과 — sample endpoint/seed 는 production app 에 애초에 없음(sampleFixture, D7) |
| keep module, block production dependency | sample-portfolio module은 유지하되 production scope 가 sample 에 0 의존(ArchUnit + sampleFixture 강제) |
| keep core contracts | error/log/env/security/architecture/verification tests 유지 |
| consume onboarding checklist | 새 도메인은 feature-domain-feature-onboarding-contract의 New Domain Module Slice + Read/Write Difference Table을 따른다 |
| copy structure, not imports | sample-portfolio import 없음 |
| register changed contracts | error/env/header/log/metric/capability 변경 시 registry owner branch에 row 등록 |
| run dual-mode | sample-on / sample-off (test classpath on/off) 두 build 모두에서 required test 통과 |
엣지·실패·의존
- 실패·엣지 경로:
- custom source-set tooling drift: dual-mode 모델은 D7 으로 build/test matrix 로 확정됨(runtime profile 아님). 구현 중
sampleOffTest가 Gradle lock state, main output, ArchUnit import option, checkstyle/spotbugs task policy와 함께 움직여야 함을 확인했다. 해결: lockfile 재생성, main output 추가,ProductionClassImportOption, sampleOff static-analysis warning-only policy. - ArchUnit false-negative: import 대신 reflection / Spring bean name lookup 으로 sample 참조 시
production_code_does_not_depend_on_sample_portfolio가 못 잡을 수 있음. 기대: dummy import case 로 rule fail 을 먼저 확인(§Claims). - core contract test 의 sample 컴파일 coupling:
app-bootstrap의 일부 contract test 가 sample 을 직접 import 함(ErrorCodeRegistryMappingTest→dev.caskeleton.sample). 해결: sample error-code registry check를sample-portfolio소유 테스트로 이동하고 app-bootstrap core contract는 sample import 0으로 정리. - dual-mode CI hosted 미검증:
.github/workflow와 gate matrix wiring은 작성됐고 로컬 gate matrix script는 통과. 실제 GitHub-hosted run은 별도 확인 필요.
- custom source-set tooling drift: dual-mode 모델은 D7 으로 build/test matrix 로 확정됨(runtime profile 아님). 구현 중
- 다른 계약 의존:
- raw/branch-notes/feature-architecture-enforcement-rules 의 ArchUnit production→sample 차단 rule(D1 강제) — 그 rule 이 바뀌면 본 branch 의 import 차단 보장이 영향받음.
- raw/branch-notes/feature-domain-feature-onboarding-contract 의 New Domain Module Slice(D5 consume: dry-run checklist SSOT) — onboarding checklist 변경 시 본 branch 검증 문구 갱신.
- raw/branch-notes/feature-contract-verification-test-suite 의 contract test suite(D2) — sample-off 에서도 통과해야 할 대상.
- raw/branch-notes/feature-sample-domain-contract-fixture 가 fixture(sample-portfolio scenario) owner — 본 branch 는 sample-off/adoption lifecycle 만 소유하고 fixture 정의는 그쪽에 위임.
Audit & Findings
ca-tmpl 코드(
/home/donghyeon/workspace/ca-tmpl) 대조에서 발견한 drift. 사용자 작성 결정 영역이므로 자동 rewrite 하지 않고 정합 권고만 남긴다(CLAUDE.md §2 ground truth 절차).
| 코드 | 심각도 | 발견 | 권고 |
|---|---|---|---|
SAMPLE_RUNTIME_MODEL_DRIFT |
RESOLVED (2026-06-15, D7; implemented 2026-06-25) | governing doc + 본 branch 가 전제했던 "sample-off profile 로 runtime sample 차단" + "dual-mode runtime"은 실제 wiring과 어긋났음 — production app 에 끌 runtime sample 이 없었음 | 사용자 결정으로 (b) dual-mode 를 build/test matrix 로 재정의(runtime profile 아님) 채택 → D7. 구현은 sampleFixture/sampleOffTest/CI sample-off job으로 정합. governing doc 의 runtime-profile 문구 정합은 fixture owner/governing doc 차원의 후속(SAMPLE_DOMAIN_NAME_DRIFT 와 함께 이관) |
SAMPLE_OFF_SOURCE_SET_TOOLING_DRIFT |
RESOLVED (2026-06-25) | custom source set은 sample jar 제외만으로 충분하지 않았다. Gradle dependency locking, main output, ArchUnit test-output exclusion, empty ArchUnit corpus, MVC slice import, custom checkstyle/spotbugs task policy가 함께 필요했다 | sampleOffTest 구현과 문제별 보강 완료. 재발 가능한 절차는 raw/errors/gradle-custom-source-set-isolation-failures-2026-06-25 에 캡처 |
SAMPLE_DOMAIN_NAME_DRIFT |
Advisory | governing wiki doc wiki/projects/ca-tmpl/sample-fixture-and-adoption 은 "sample-ticket"(TicketId/TicketStatus/12 scenario)로 기술. 실제 코드는 sample-portfolio WorkLog/RepoStats 도메인. 본 branch note 는 코드와 일치(sample-portfolio) |
fixture owner branch(raw/branch-notes/feature-sample-domain-contract-fixture) / governing doc 에 stale 명칭 정합 권고 — 본 branch 범위 밖이므로 이관 |
테스트 계약
- sample-off build(test classpath 제외)에서 sample endpoint/seed 가 core test 에 잔존하면 실패.
- sample-off build에서 core app smoke/contract test가 실패하면 실패.
- production module이
sample-portfolio을 import하면 실패. (현행: ArchUnitproduction_code_does_not_depend_on_sample_portfolio가 강제 —actually-implemented) - 새 도메인 adoption 기준을 본 branch에 중복 정의하면 실패. 본 branch는 onboarding branch의 checklist를 consume only.
- sample-on / sample-off (test classpath on/off) CI matrix 중 하나라도 누락되면 실패.
검증해야 할 주장
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
| sample-off build(test classpath 제외)에서 sample endpoint/seed 가 core test 에 남지 않는다 | custom source-set classpath와 test output import option이 drift할 수 있음 | sample 제외 build 로 core test 실행 후 sample component/class 부재 확인 | locally-verified (:app-bootstrap:sampleOffTest) |
| sample-off build에서 core app smoke/contract test가 통과한다 | app-bootstrap 또는 contract test가 sample test bean에 coupling됐을 수 있음(sampleFixture sample-portfolio 경유) |
sample 제외 build 로 sampleOffTest + startup smoke. sample-portfolio module include는 유지 |
locally-verified |
production module이 sample-portfolio을 import하면 실패한다 |
ArchUnit rule 이 reflection/bean lookup 우회를 못 잡을 수 있음 | production dependency scan + SampleRemovalSmokeContractTest app-bootstrap test import scan |
locally-verified (reflection 우회는 여전히 advisory) |
| sample-off CI job에서 sample module import 검출 시 fail한다 | Hosted workflow 미실행 가능 | CI 작성 후 gate matrix script와 local sampleOffTest 실행 | locally-verified (GitHub-hosted run은 needs-confirmation) |
| 새 도메인 adoption checklist가 onboarding branch와 충돌하지 않는다 | checklist를 중복 관리하면 SSOT drift 발생 | 본 branch에 별도 module slice table이 없는지 확인하고 onboarding branch table만 link | documented-only |
| GitHub Template Repository 복제 범위가 ca-tmpl adoption에 충분하다 | Actions는 복제되더라도 Secrets/branch protection은 별도일 수 있음 | dummy repo 생성 후 Actions/Secrets/branch protection 복제 범위 확인 | needs-confirmation |
관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때)
/coverage가 채우는 생성물 — 손으로 유지하지 않는다. governing doc = wiki/projects/ca-tmpl/sample-fixture-and-adoption. 기준:rules/coverage-gate.md. (coverage-auditor 2026-06-15 판정: Covered — Blocking 0)
| 관심사 | 상태 | owner | 심각도 | 근거 |
|---|---|---|---|---|
| 12 scenario matrix (fixture) | delegated | raw/branch-notes/feature-sample-domain-contract-fixture | OK | raw/branch-notes/feature-sample-domain-contract-fixture 가 fixture scenario owner (§Edge 위임) |
| 6-field minimum model (fixture) | delegated | raw/branch-notes/feature-sample-domain-contract-fixture | OK | 동 fixture branch §Coverage |
| state machine (fixture) | delegated | raw/branch-notes/feature-sample-domain-contract-fixture | OK | 동 fixture branch §Coverage |
| optimistic lock (fixture) | delegated | raw/branch-notes/feature-sample-domain-contract-fixture | OK | 동 fixture branch §Coverage |
| idempotency key (fixture) | delegated | raw/branch-notes/feature-sample-domain-contract-fixture | OK | 동 fixture branch §Coverage |
| production → sample import 차단 | covered-here | — | — | D1 (ArchUnit production_code_does_not_depend_on_sample_portfolio + sampleFixture, actually-implemented) |
| sample-off first adoption (2-step) | covered-here | — | — | D4 + D7 (build/test matrix; SAMPLE_RUNTIME_MODEL_DRIFT RESOLVED) |
| dual-mode 검증 (sample-on/off) | covered-here | — | — | D3 + D7 (test classpath on/off; CI actually-implemented, local verification 완료) |
| multi-module adoption checklist | covered-here(consume) | raw/branch-notes/feature-domain-feature-onboarding-contract | — | D5 (consume only, 중복 정의 금지) |
| reference scaffolding 1순위 = GitHub Template Repository | covered-here | — | — | D8 (6개 대안 비교, SCAF-GH-C1) |
| Backstage golden path 채택 임계점 | covered-here | — | — | D6 (조직 IDP 규모 이후, 본 branch 미채택) |
| core contract test 보존 (sample-off에서도) | covered-here | — | — | D2 (app-bootstrap contract/* 현존, sample 독립) |
마주친 문제
- Gradle custom source set은 dependency lock state, main output, ArchUnit import option, empty corpus, slice test import, static-analysis task policy가 같이 맞아야 했다. 상세 재발 방지 기록: raw/errors/gradle-custom-source-set-isolation-failures-2026-06-25.
묶음 (이 branch에서 파생된 자료)
- raw/company-tech-blogs/scaffolding-backstage-golden-path-spotify
- raw/official-docs/scaffolding-cookiecutter-official
- raw/official-docs/scaffolding-degit-svelte-github
- raw/official-docs/scaffolding-github-template-repository
- raw/official-docs/scaffolding-spring-initializr
- raw/blog-topics/clean-architecture-reference-project-adoption-2026-06-17
- raw/blog-topics/sample-fixture-dual-mode-build-matrix-2026-06-25
Sub-branches (세부 작업)
- (없음 — 현재 leaf branch)
오류 기록 (이 branch 작업 중 발생)
면접 준비 (이 작업에서 나올 수 있는 면접 질문)
강의 (이 작업을 위해 학습한 강의)
- (없음)
job-posting tie-ins (이 작업에서 파생된 글감)
관련 일일 노트
완료 후 정리
- PR 링크:
- 리뷰 메모:
- 머지 결과 / 배포 환경:
- wiki 추출 대상 (verified만,
wiki/projects/로만 추출):actually-implemented항목:sampleFixture/sampleOffTest, sample-off CI job, sample 직접 import 제거, sample-owned registry test 이동locally-verified항목:./gradlew test,./gradlew :app-bootstrap:sampleOffTest,./gradlew check verifyPublicPathSnapshot, gate matrix scriptprod-verified항목:
- 추출하지 않을 항목 (planned / documented-only / abandoned):
- GitHub-hosted CI 실제 run 결과, GitHub Template Repository Secrets/branch protection 복제 범위