fix: 하네스 제거 및 keycloak 문서 보강
This commit is contained in:
@@ -1 +0,0 @@
|
||||
../../vault/10-projects/ca-skeleton-operational-contract/branch-notes/feature-developer-experience-contract.md
|
||||
@@ -0,0 +1,443 @@
|
||||
---
|
||||
title: branch / feature-developer-experience-contract
|
||||
source_type: branch-note
|
||||
status: raw
|
||||
branch: feature-developer-experience-contract
|
||||
parent_branch:
|
||||
related_projects: [ca-skeleton]
|
||||
governing_docs: [wiki/projects/ca-tmpl/devops-ci-supply-chain-dx]
|
||||
tags: [branch, ca-skeleton, developer-experience, local-dev]
|
||||
created: 2026-05-22
|
||||
target_merge:
|
||||
status_label: review
|
||||
id: BR-CA-SKELETON-OPERATIONAL-CONTRACT-033
|
||||
kind: project-work-item
|
||||
project: ca-skeleton-operational-contract
|
||||
work_item: WI-CA-SKELETON-OPERATIONAL-CONTRACT-033
|
||||
inherits: [DEC-CA-SKELETON-OPERATIONAL-CONTRACT-BOOTSTRAP-001@1, DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-BUILD-001@1]
|
||||
refines: []
|
||||
overrides: []
|
||||
depends_on: []
|
||||
contract_packet: 1
|
||||
contract_packet_sha256: d507282d4a550e9385db2a647f07c608950ae223886a80132d45d1957d2a2aee
|
||||
---
|
||||
|
||||
# branch: feature-developer-experience-contract
|
||||
|
||||
> Layer: `raw/branch-notes/` — 실무자가 skeleton을 받아 바로 실행, 검증, 확장할 수 있는 local developer experience 기준을 정의합니다.
|
||||
|
||||
<!-- section-id: branch-parent -->
|
||||
## 부모 (필수)
|
||||
|
||||
- **Parent project (canonical SSOT)**: [[raw/project-notes/ca-skeleton-operational-contract]]
|
||||
|
||||
> ca-skeleton 은 별도 root branch 없이 project-note 가 SSOT 역할. 본 feature branch 는 project-note 의 운영 계약 중 §18 Control Plane Contract → Developer Experience 영역의 결정/근거/금지 사항을 정제한다. governing doc = [[wiki/projects/ca-tmpl/devops-ci-supply-chain-dx]] (DX 슬라이스).
|
||||
|
||||
<!-- GENERATED: branch-contract:start -->
|
||||
<!-- section-id: branch-contract-packet -->
|
||||
## 브랜치 계약 패킷
|
||||
|
||||
- **생성 시 프로젝트 개정**: `1`
|
||||
- **패킷 스키마**: `contract_packet: 1`
|
||||
- **완료 조건**: fresh environment에서 ./gradlew bootstrap이 성공한다
|
||||
|
||||
<!-- section-id: inherited-project-decisions -->
|
||||
### 상속한 프로젝트 결정
|
||||
|
||||
| Decision Ref | Project Summary | Branch Application | Source |
|
||||
|---|---|---|---|
|
||||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-BOOTSTRAP-001@1` | 신규 환경의 default 진입 명령은 ./gradlew bootstrap이다 | 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]] |
|
||||
|
||||
<!-- section-id: branch-local-decisions -->
|
||||
### 브랜치 지역 결정
|
||||
|
||||
> 기존 branch-local 결정은 아래 `## Decision Evidence Map / 결정-근거 매핑`의 D-row가 소유하며 이 packet에서 복제하지 않는다.
|
||||
|
||||
| Decision ID | Decision | Relation | Supporting Claims | Status |
|
||||
|---|---|---|---|---|
|
||||
|
||||
<!-- section-id: declared-overrides -->
|
||||
### 선언한 예외
|
||||
|
||||
| Override ID | Overrides | Reason | Approval | Status |
|
||||
|---|---|---|---|---|
|
||||
<!-- GENERATED: branch-contract:end -->
|
||||
|
||||
<!-- section-id: branch-goal -->
|
||||
## 목표
|
||||
|
||||
좋은 skeleton은 구조가 훌륭한 것에서 끝나지 않습니다. 새 개발자가 로컬에서 빠르게 실행하고, sample contract를 확인하고, 실패 기준을 재현할 수 있어야 합니다.
|
||||
|
||||
- 이슈:
|
||||
- PR:
|
||||
|
||||
<!-- section-id: branch-scope -->
|
||||
## 범위
|
||||
|
||||
### 포함 범위
|
||||
|
||||
- local bootstrap command.
|
||||
- `.env.example` 필수 key.
|
||||
- sample profile 실행/비활성화 기준.
|
||||
- Testcontainers 또는 local dependency 대체 기준.
|
||||
- smoke test command.
|
||||
- README/runbook link 기준.
|
||||
|
||||
### 제외 범위
|
||||
|
||||
- IDE별 개인 설정.
|
||||
- cloud development environment 강제.
|
||||
- production deployment guide.
|
||||
|
||||
## 근거 (필수, 최소 1개+)
|
||||
|
||||
> 이 branch의 구현·설계 결정의 근거가 되는 외부 자료. 상세 비교는 §외부 근거 / 대안 조사 참조. company-tech-blog 인용은 `company-case-study` 강도이며 official-standard / official-vendor-doc 으로 격상 금지.
|
||||
|
||||
| Source | 정당화하는 결정 |
|
||||
|---|---|
|
||||
| [[raw/official-docs/dx-testcontainers-java-best-practices]] | D3·D10 — bootstrap step 2 의 local dependency 도구 + Spring Boot 3.1+ `@ServiceConnection` 기반 default integration test backend 근거 (TC-CORE-C1~C4 / TC-SPRING-C1 / TC-REUSE-C1) |
|
||||
| [[raw/official-docs/dx-mise-asdf-tool-versioning]] | D6 — JDK Temurin 21 LTS + `.tool-versions`/`.sdkmanrc` 핀 (도구를 강제 않고 파일 포맷을 강제하는 전략, DX-TV-C4/C5) |
|
||||
| [[raw/official-docs/dx-devcontainer-spring-boot]] | D9 — devcontainer 를 default 로 두지 않는 결정의 대안 평가 (DX-DC-C2 development-phase 한정 / DX-DC-C4 VS Code 한정 / DX-DC-C5) |
|
||||
|
||||
근거 자료가 raw에 아직 없다면 먼저 `raw-source-template` 또는 `lecture-note-template` 으로 raw에 등록한 뒤 여기서 링크.
|
||||
|
||||
## 외부 근거 / 대안 조사 (2026-05-22 — Group G-E: Developer Experience)
|
||||
|
||||
본 branch의 `./gradlew bootstrap` 5단계 + Temurin 21 LTS + Testcontainers integration + markdown-link-check 결정에 대한 외부 source.
|
||||
|
||||
- **채택 결정 (Gradle bootstrap + Testcontainers + Temurin 21)**:
|
||||
- [[raw/official-docs/dx-testcontainers-java-best-practices]] — Testcontainers + Spring Boot 3.1 `@ServiceConnection` + reuse/singleton 패턴
|
||||
- [[raw/official-docs/dx-mise-asdf-tool-versioning]] — mise/asdf/SDKMAN + `.tool-versions` 포맷 + Temurin 21 LTS
|
||||
- **검토한 대안**:
|
||||
- **대안 1: `make bootstrap`** — POSIX 표준이나 Windows 친화성 낮음
|
||||
- **대안 2: `docker compose up` only** — bootstrap 5단계 합성 어려움
|
||||
- **대안 3: devcontainer (VSCode·Codespaces)** — [[raw/official-docs/dx-devcontainer-spring-boot]] (containers.dev spec, IDE 종속성 + bootstrap 5단계 진입점/smoke 미해결)
|
||||
- **대안 4: Nix flake** — reproducibility 강점이나 Java 생태계 성숙도 낮음
|
||||
- **비교 핵심**: Gradle bootstrap이 5단계 합성 가능 + Spring 생태계 정합. Testcontainers `@ServiceConnection`(Spring Boot 3.1+)이 integration test의 boilerplate 제거. devcontainer는 IDE 종속이라 CI/CD와 분리 필요. **보강 후보**: `.tool-versions`(asdf/mise) vs `.sdkmanrc`(SDKMAN) 포맷 차이 — branch note "또는" 표현은 drift 위험, 단일 source로 좁힐 필요.
|
||||
|
||||
### 2026-06-15 addendum — D8 link-rot 도구 재조사 (`wiki-decision-researcher`)
|
||||
|
||||
D8 의 `markdown-link-check` 선택이 `UNSUPPORTED_DECISION` 이었으므로 대안을 조사했다 (`/branch-spec` §5 자동조사). 3종 비교:
|
||||
|
||||
| 도구 | Node 의존 | 유지보수 | CI gate | 비고 |
|
||||
|---|---|---|---|---|
|
||||
| `markdown-link-check` (npm/tcort) | 필수 (Docker 우회) | 단일 메인테이너, v3.14.2 (2025-11) | `tcort/github-action-markdown-link-check` | JVM-only repo 에 Node 툴체인 추가 비용 |
|
||||
| **`lychee` (Rust/lycheeverse)** | **없음 (단일 정적 바이너리)** | 활발 (3,700+ stars, v0.24.2 2026-05, 40+ 프로젝트) | `lycheeverse/lychee-action@v2.0.2+` (CVE-2024-48908 패치 핀 필수) | **권고** — JVM/Gradle repo DX 마찰 최소 |
|
||||
| `linkinator` (npm/binary) | npm 경로 필수 / 바이너리 옵션 | 활발 (v7.6.1 2026-02, Google Cloud SDK 사용) | `JustinBeckwith/linkinator-action@v1` | Node 도입 시 후보 |
|
||||
|
||||
- **조건부 권고**: ca-tmpl 이 `package.json`/Node toolchain 미도입을 유지하는 한 → **lychee** (Node 의존 없음). Node 를 다른 이유로 도입하면 → linkinator. 기존 Docker-first/MegaLinter 파이프라인이면 → markdown-link-check.
|
||||
- **archiving 상태 (`deferred`)**: 위 비교의 raw 검증 자료(`wiki-source-summarizer` ×6, official + case-study) archiving 은 **사용자 승인 대기 중**. 승인 시 controller 가 dispatch → 생성 후 D8 의 `UNSUPPORTED_DECISION` 라벨을 `official-vendor-doc + company-case-study` 로 격상. 미archiving 상태에서는 D8 을 "조사됨, raw 미archiving" 로 표기(추측 단정 금지).
|
||||
|
||||
## TODO
|
||||
|
||||
> TODO drained 2026-05-22 — 결정은 아래 "결정 사항" / "Decision Evidence Map" / "Decisionized Work Items" / "테스트 계약" 참조. bootstrap/`.env.example`/sample profile/Testcontainers-local dep/smoke command/README-wiki 연결 모두 표 또는 결정 라인으로 반영됨. 잔존 TODO 없음.
|
||||
>
|
||||
> **구현 현황 (2026-06-15 ground truth)**: 본 branch 는 **documented-only / planned 단계** — ca-tmpl `src/` 실 코드에 `bootstrap` Gradle task·`.env.example`·`.tool-versions`·markdown-link-check·smoke test·CI 모두 미작성. 실제로 존재하는 것은 Flyway migration(V1/V3/V4) + JDK 21 toolchain + 수동 `@Container` Testcontainers + sample-portfolio(test-scope, ArchUnit 격리)뿐. 단계별 grade 는 §구현 가이드, drift 는 §Audit & Findings.
|
||||
>
|
||||
> **2026-06-24 구현 결과**: direct-owner 범위는 `actually-implemented`이며 Linux local에서 `locally-verified`됐다. `./gradlew bootstrap` 5단계, README command drift gate, `@ServiceConnection` context tests, local-only Testcontainers reuse policy, lychee workflow가 코드에 존재한다. `.env`/sample runtime toggle/fresh-clone CI는 기존 위임 owner를 유지한다. lychee remote CI와 macOS/WSL2는 `needs-confirmation`이다.
|
||||
|
||||
## 진행 중 메모
|
||||
|
||||
- 2026-06-15: ca-tmpl 코드 대조 결과 본 branch 의 다수 결정이 *아직 미구현(planned)* 이거나 *이미 구현된 sibling branch 와 drift* 함이 확인됨. 자동 rewrite 하지 않고 §Audit & Findings 에 정합 권고로 기록 (사용자 작성 결정 영역). 핵심 drift 5건: `BOOTSTRAP_TASK_ABSENT`, `GRADLE_VERSION_DRIFT`(8.x→실제 9.0.0), `ENV_EXAMPLE_SUPERSEDED`(`.env.example` → `src/.env`+`verifyEnvKeys` 로 sibling 이 이미 해소), `SAMPLE_ENABLE_MECHANISM_DRIFT`(@Profile 가정 → 실제 ArchUnit+env), `SERVICECONNECTION_NOT_USED`(@ServiceConnection 가정 → 실제 수동 `@Container`).
|
||||
- 2026-06-24: D3/D4/D8/D10을 구현했다. bootstrap 첫 실행에서 host 5432 collision과 slim JRE RNG provider 누락을 발견해 각각 internal-only DB network와 `SplittableRandom` composition bean으로 해결했다. `./gradlew bootstrap`, `./gradlew test check`, focused ServiceConnection tests를 local에서 검증했다.
|
||||
- 2026-06-30: CleanArchitectureTest.java의 자원 누수 경고 해결(@SuppressWarnings("resource") 추가 및 import 스타일 정리), README.md에서 누락되었던 feature-developer-experience-contract 식별자 복구로 테스트 통과 확인, Spring Boot 3.5.x EOL 경고 무시를 위한 VS Code settings.json 설정 반영. 추가로 Spring Boot 4.x 업그레이드 시 Testcontainers 2.0 라이브러리와의 마이그레이션 호환성을 면밀히 재평정한 spec 문서(docs/superpowers/specs/2026-06-30-testcontainers-2-0-migration-spec.md) 작성 완료.
|
||||
|
||||
## 결정 사항
|
||||
|
||||
- 2026-05-22: local 실행은 prod-safe 기본값을 훼손하지 않는 별도 profile/env로만 허용.
|
||||
- 2026-05-22: sample fixture는 local/dev에서 쉽게 켤 수 있어야 하고 prod에서는 기본 비활성화.
|
||||
- 2026-05-22: bootstrap command 기본값은 `./gradlew bootstrap`. 없으면 `./gradlew test`와 `docker compose up` wrapper를 제공.
|
||||
- 2026-05-22: README는 canonical wiki를 대체하지 않고, local start/smoke/adoption entrypoint만 제공.
|
||||
- 2026-05-22: OS 매트릭스 = Linux (Ubuntu 22.04+), macOS (Apple Silicon 우선), Windows (WSL2 only). CI는 Linux만, 개발자는 3개 OS 검증 의무.
|
||||
- 2026-05-22: JDK = Temurin 21 LTS. gradle-wrapper 8.x. `.tool-versions` 또는 `.sdkmanrc`로 핀.
|
||||
- 2026-05-22: bootstrap task 정의 = `./gradlew bootstrap` = (1) `./gradlew compileTestJava` (compile sanity) (2) `docker compose up -d` (local dependencies via Testcontainers config 또는 별도 compose file) (3) Flyway migrate (4) sample profile seed (5) smoke test 실행. 5단계 모두 통과 시 성공.
|
||||
- 2026-05-22: sample profile default = clone 직후 enabled. prod profile에서는 disabled (`feature-sample-removal-adoption-contract`와 일관).
|
||||
- 2026-05-22: link-rot 검증 = `markdown-link-check` (npm). CI에서 README + docs/ 전수 검사.
|
||||
- **2026-06-15 (위 항목 보강/대체 후보 — D8)**: link-rot 도구 재조사 결과 **lychee** (Node-free 단일 Rust 바이너리) 를 조건부 권고. 기존 `markdown-link-check` 결정은 *Node 의존 비용 미평가*였음(ca-tmpl 은 `package.json` 없는 JVM-only repo). 상세·트레이드오프: §외부 근거 2026-06-15 addendum + Decision Evidence Map D8.
|
||||
- **2026-06-15 (정합 메모 — gradle wrapper)**: 위 "gradle-wrapper 8.x" 결정은 ca-tmpl 실제 `gradle/wrapper/gradle-wrapper.properties` 의 **9.0.0** 과 drift. 핀 *전략*(repo wrapper 로 Gradle 버전 고정)은 유효하나 *버전 숫자*는 9.0.0 으로 정정 필요(§Audit `GRADLE_VERSION_DRIFT`).
|
||||
|
||||
## 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` 승급 위치 |
|
||||
|
||||
## 결정-근거 매핑
|
||||
|
||||
> 본 branch 의 각 결정을 raw source 의 Claim ID 로 매핑. `선택 조건`(R2): 이 조건일 때 이 결정 / 다른 조건이면 어떤 대안. company-tech-blog 인용은 `company-case-study` 강도이며 official-standard / official-vendor-doc 으로 격상 금지.
|
||||
|
||||
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|
||||
|---|---|---|---|---|---|
|
||||
| D1 | local 실행은 prod-safe 기본값을 훼손하지 않는 별도 profile/env 로만 허용 | 항상 — local 편의를 위해 prod 기본값(error detail 노출·body logging 등)을 바꿔야 하면 별도 profile/env override 로만. **금지 대안**: 단일 profile 로 local+prod 겸용(=prod-unsafe default 누출) | (ca-tmpl 고유 정책; 외부 raw claim 없음. parent §9 Env-driven Runtime Config 에 정합) | UNSUPPORTED_DECISION | 외부 standard 부재 — 자체 정책으로만 정당화 |
|
||||
| D2 | sample fixture 는 local/dev 기본 enabled, prod 기본 disabled | clone 직후 교육/계약검증 목적이면 enabled; prod 배포 profile 이면 disabled. **enable/disable 런타임 메커니즘 owner = `feature-sample-removal-adoption-contract`** (본 branch 는 DX 진입점만, 위임) | (`feature-sample-removal-adoption-contract` 와 연계; 본 branch 외부 raw 직접 claim 없음) | UNSUPPORTED_DECISION (delegated) | enable/disable (env `APP_SAMPLE_ENABLED`, registry-backed; 런타임 토글 *코드 메커니즘*은 owner 확정 대상 — 본 branch 가 단정 안 함) 는 sibling owner, 본 branch 미구현 |
|
||||
| D3 | bootstrap 단일 entry point = `./gradlew bootstrap` 5단계 (compileTestJava → docker compose up -d → Flyway migrate → sample profile seed → smoke test) | skeleton 채택자가 *single command first-run* 을 원할 때 `./gradlew bootstrap`; CI/스크립트가 단계별 제어 필요하면 각 sub-task 직접 호출. **대안**: `make`(Windows 친화성↓, §외부근거 대안1) / `docker compose up` only(5단계 합성 불가, 대안2) | `raw/official-docs/dx-testcontainers-java-best-practices.md#TC-CORE-C1`, `#TC-CORE-C2`, `#TC-CORE-C3` | `official-vendor-doc` (Testcontainers 가 integration test backend 로 적합함만 증명 — 5단계 합성 자체는 ca-tmpl 고유) | **`bootstrap` task 미존재(`planned`)** — 실제 first-run 은 README `cd src && ./gradlew bootRun`. docker-compose 파일 3종 모두 0-byte(빈). Flyway 만 실존. 5단계 합성·smoke 미구현 (§Audit `BOOTSTRAP_TASK_ABSENT`) |
|
||||
| D4 | README 는 canonical wiki 를 대체하지 않고 local start/smoke/adoption entrypoint 만 제공 | README 는 *진입점*(첫 실행/스모크/채택 절차)만; 개념·계약 설명이 필요하면 canonical wiki 로 링크. **금지 대안**: README 를 별도 SSOT 로 운영(=canonical 과 drift) | (ca-tmpl 고유 운영 규약; 외부 raw claim 없음) | UNSUPPORTED_DECISION | 외부 standard 부재. 실제 README 존재하나 `bootstrap`/smoke section 없음(`bootRun` 만) → `planned` 부분 |
|
||||
| D5 | OS 매트릭스 = Linux (Ubuntu 22.04+), macOS (Apple Silicon 우선), Windows (WSL2 only). CI 는 Linux, 개발자는 3개 OS 검증 | Linux = CI 필수 게이트; macOS Apple Silicon / Windows WSL2 = 개발자 로컬 검증 의무. **미지원 대안**: native Windows(non-WSL2) | (ca-tmpl 고유 정책; 외부 raw claim 없음) | UNSUPPORTED_DECISION | Apple Silicon arm64 emulation 비용은 Testcontainers 메모(TC raw §메모)에서 경고만 — 정량 근거 없음 |
|
||||
| D6 | JDK = Temurin 21 LTS. gradle wrapper 핀(전략). `.tool-versions` 또는 `.sdkmanrc` 로 IDE/CLI 핀 | JDK 강제는 *2층*: build 는 Gradle toolchain(`JavaLanguageVersion.of(21)`), IDE/CLI 는 `.tool-versions`/`.sdkmanrc`. 도구(mise/asdf/SDKMAN)는 강제 안 함 — **파일 포맷만** 강제(DX-TV-C5). 단일 포맷 권장(둘 다 두면 drift) | `raw/official-docs/dx-mise-asdf-tool-versioning.md#DX-TV-C4`, `#DX-TV-C5` | `official-vendor-doc` (asdf 의 `.tool-versions` 단일 spec 위치 정의) | **gradle wrapper 실제 = 9.0.0**(노트 "8.x" 와 drift, §Audit `GRADLE_VERSION_DRIFT`). `.tool-versions`/`.sdkmanrc`/`.mise.toml` 미존재(`planned`) — 실존은 build.gradle toolchain 21 뿐. Temurin 21 EOL(`DX-TV-C8`)·mise↔asdf 호환(`DX-TV-C5` "Does not prove")은 `needs-confirmation` |
|
||||
| D7 | sample profile default = clone 직후 enabled, prod profile disabled | D2 와 동일 정책의 default 표현. enable/disable 코드 owner = `feature-sample-removal-adoption-contract`(`APP_SAMPLE_ENABLED`); 격리 owner = `feature-sample-domain-contract-fixture`(ArchUnit). 본 branch 는 위임 | (sibling branch 와 일관성; 외부 raw claim 없음) | UNSUPPORTED_DECISION (delegated) | 실제 격리는 Spring `@Profile` 이 아니라 ArchUnit `production_code_does_not_depend_on_sample_portfolio` + test-scope (§Audit `SAMPLE_ENABLE_MECHANISM_DRIFT`) |
|
||||
| D8 | link-rot 검증 도구 — **lychee**(Node-free 단일 바이너리) 조건부 권고, 기존 `markdown-link-check` 대체 후보 | Node toolchain 미도입 유지 → **lychee**(`lycheeverse/lychee-action@v2.0.2+`); Node 도입 시 → linkinator; 기존 Docker-first/MegaLinter → markdown-link-check (2026-06-15 조사) | (조사됨 — §외부근거 2026-06-15 addendum; raw archiving `deferred`, 사용자 승인 대기) | researched, raw 미archiving (이전 `UNSUPPORTED_DECISION`) | lychee-action CVE-2024-48908 → v2.0.2+ pin 필수. Gradle exec task 래핑·로컬 바이너리 프로비저닝 미설계. archiving 전까지 official Claim ID 부재 |
|
||||
| D9 | devcontainer 를 default 로 두지 않음 (IDE별 개인 설정 out-of-scope) | IDE 통일이 팀 강제이고 VS Code/Codespaces 단일 환경이면 devcontainer 고려; 다IDE/CI 분리 필요하면 default 제외(현 결정). 근거: spec 은 development-phase 한정(DX-DC-C2), VS Code 한정 통합(DX-DC-C4) | `raw/official-docs/dx-devcontainer-spring-boot.md#DX-DC-C2`, `#DX-DC-C4`, `#DX-DC-C5` | `official-standard` + `official-vendor-doc` | devcontainer + ca-tmpl bootstrap 양립 시연 없음 — 채택 시 별도 검증 필요(Claims To Verify 참조) |
|
||||
| D10 | Testcontainers (`@ServiceConnection`) 를 default integration test backend 로 둠 | Spring Boot 3.1+ integration test backend = Testcontainers; bootstrap 의 *로컬 dependency* 는 `docker compose`(test lifecycle ≠ bootstrap lifecycle, TC raw §메모). reuse 는 로컬 opt-in / CI off(TC-REUSE-C1) | `raw/official-docs/dx-testcontainers-java-best-practices.md#TC-CORE-C1`, `#TC-SPRING-C1`, `#TC-REUSE-C1` | `official-vendor-doc` (core 정의) + `needs-confirmation` (`@ServiceConnection` verbatim·reuse property 명 미확정) | **실제 코드는 `@ServiceConnection` 미사용 — 수동 `@Container PostgreSQLContainer`** (OutboxAppend/OutboxPublisher/DistributedLock contract test). @ServiceConnection 전환은 `planned` (§Audit `SERVICECONNECTION_NOT_USED`). `TC-SPRING-C1`/`TC-REUSE-C1`/`TC-SINGLETON-C1` 모두 `needs-confirmation` |
|
||||
| D11 | runtime container의 outbox jitter RNG는 `java.base` 구현을 명시 주입 | slim JRE에서도 startup이 필요하면 `SplittableRandom`; provider-specific algorithm이 필수면 runtime module 포함 대안 | 프로젝트 container stack trace + `OutboxConfigTest` RED/GREEN (외부 raw claim 없음) | `UNSUPPORTED_DECISION` | 알고리즘 품질/성능을 외부 공식 source로 재검토하지 않음. trade-off: provider portability를 startup 안정성보다 우선하지 않음 |
|
||||
| D12 | local PostgreSQL은 host port를 publish하지 않고 Compose internal network에서만 사용 | app container startup Flyway가 migration owner일 때 internal-only; host DB client가 필요하면 별도 override | 프로젝트 `docker compose config` + port collision 재현 (외부 raw claim 없음) | `UNSUPPORTED_DECISION` | host-side DB tool 사용자는 explicit override 필요. trade-off: zero-conflict 기본값과 직접 접속 편의의 교환 |
|
||||
| D13 | ArchCondition 초기화 시 발생하는 ECJ 자원 누수 경고(Resource leak)를 `@SuppressWarnings("resource")`로 억제 | 항상 — ArchCondition 익명 이너 클래스 정의 시 컴파일러의 오탐지로 인한 경고 해결 | (프로젝트 빌드 경고 해결용; 외부 raw claim 없음) | `UNSUPPORTED_DECISION` | N/A |
|
||||
| D14 | Spring Boot 3.5.x EOL 경고를 VS Code `settings.json`에서 무시하도록 설정 | 항상 — Testcontainers 2.x 메이저 업그레이드로 인한 패키지 변경 등 파급 효과를 피하기 위해 3.5.16 버전을 유지하고 IDE 경고만 비활성화 | (IDE 문제 경고 해결용; 외부 raw claim 없음) | `UNSUPPORTED_DECISION` | N/A |
|
||||
|
||||
## Decisionized Work Items
|
||||
|
||||
| item | Decision | Allowed | Forbidden | Required test |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| bootstrap | one command: `./gradlew bootstrap` | wrapper around docker compose/test | multiple competing first-run docs | bootstrap smoke |
|
||||
| `.env.example` | registry-complete safe local values | comments for secret placeholders | prod secrets in example | env example check |
|
||||
| sample profile | local/dev enabled, prod disabled | education profile | prod sample endpoint | sample profile smoke |
|
||||
| README/wiki | README entrypoint, wiki canonical | README links canonical | README as separate truth | doc drift check |
|
||||
|
||||
> ⚠️ **2026-06-15 정합 주의**: 위 `.env.example` row 는 sibling [[raw/branch-notes/feature-env-driven-runtime-configuration]] D7(2026-06-08 B 결정)이 **`.env.example` 미사용 + `src/.env` git-tracked 단일 소스 + `verifyEnvKeys` 3-way gate** 로 이미 해소함. 본 branch 의 `.env.example` 결정은 *superseded* — DX coverage 상 "env template self-sufficiency" 관심사는 그 sibling 에 **위임**한다(§Coverage). 자동 삭제하지 않고 정합 권고만(§Audit `ENV_EXAMPLE_SUPERSEDED`).
|
||||
|
||||
## DX Defaults (deprecated)
|
||||
|
||||
> DX 결정 표 SSOT는 위 "Decisionized Work Items". 별도 DX Defaults 양식은 deprecated.
|
||||
|
||||
## 구현 가이드
|
||||
|
||||
> *결정(Decisions)* 이 "*무엇*" 이라면 본 §는 "*어디에 어떻게*" 의 사전 명세. 각 sub-section 은 Decision ID + Supporting Claim ID 를 Trace. ca-tmpl `src/` 실 코드 대조(2026-06-15)로 reality grade(`actually-implemented`/`planned`/`documented-only`/delegated)를 셀마다 표기 — 노트 자기보고가 아니라 코드 grep 으로 확정.
|
||||
>
|
||||
> **3-rule**: R1 모든 detail 은 Decision+근거 도출 · R2 근거 없는 임의 detail 은 `UNSUPPORTED_IMPL_DECISION`+trade-off · R3 본 branch 결정 범위 밖은 위임(§Audit 에 이관 history).
|
||||
|
||||
### 1. bootstrap 단일 진입점 — `./gradlew bootstrap` 5단계
|
||||
|
||||
> **Trace**: D3 (5단계 정의) / `dx-testcontainers#TC-CORE-C1~C3`. anchor = ca-tmpl `src/build.gradle`(task 미존재) + `README.md` §로컬 실행 + `docker-compose*.yml`(3종) + `src/adapter-persistence/.../db/migration/`.
|
||||
>
|
||||
> - **UNSUPPORTED_IMPL_DECISION**: 5단계의 *합성 메커니즘*(단일 Gradle task vs Makefile vs compose wrapper)은 외부 raw 가 권고하지 않음. Gradle task 채택 trade-off: Spring 생태계 정합·step 별 exit code 분리 가능하나 Windows(WSL2 밖) 친화성은 make 보다 낮음(D5 WSL2 강제로 회피).
|
||||
|
||||
| 단계 | 구현 anchor (목표) | ca-tmpl 실제 상태 (2026-06-15) | grade |
|
||||
|---|---|---|---|
|
||||
| (1) compile sanity | `./gradlew compileTestJava` | 표준 task 존재 | `actually-implemented` |
|
||||
| (2) local dependency 기동 | `docker compose up -d` (별도 compose file) | `docker-compose.yml`/`.dev.yml`/`.local.yml` 모두 **0-byte(빈)** | `planned` |
|
||||
| (3) Flyway migrate | `flyway-core` + `db/migration/V*.sql` | V1__idempotency_record / V3__outbox_event / V4__int_lock (+ sample V2__work_log) 실존, `baseline-on-migrate: false` | `actually-implemented` |
|
||||
| (4) sample profile seed | sample-portfolio seed | sample-portfolio 모듈 실존(test-scope), 런타임 seed/profile 토글은 sibling 위임 | delegated → `feature-sample-removal-adoption-contract` |
|
||||
| (5) smoke test | `./gradlew ...smoke` 또는 health probe | `smoke`/`Smoke` task·class **미존재**. health endpoint `GET /api/healthcheck` 는 존재 | `planned` |
|
||||
| 합성: `bootstrap` task | custom Gradle task 가 5단계 묶음 | **`bootstrap` task 미등록** (`app-bootstrap` 은 *모듈*명이지 task 아님). 현 first-run = `cd src && ./gradlew bootRun` | `planned` (§Audit `BOOTSTRAP_TASK_ABSENT`) |
|
||||
|
||||
### 2. tool-version 핀 — Temurin 21 LTS + Gradle wrapper
|
||||
|
||||
> **Trace**: D6 / `dx-mise-asdf#DX-TV-C4`,`#DX-TV-C5`. anchor = `src/build.gradle` `java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }` + `gradle/wrapper/gradle-wrapper.properties`.
|
||||
>
|
||||
> - **UNSUPPORTED_IMPL_DECISION**: `.tool-versions`(asdf/mise) vs `.sdkmanrc`(SDKMAN) *단일 포맷 선택*. 외부 raw 는 포맷 spec 만 정의, 어느 것을 ca-tmpl default 로 둘지는 미권고. trade-off: `.tool-versions` 가 사실상 표준(DX-TV-C5)이고 mise/asdf 양쪽이 읽으나 mise 100% 호환은 `needs-confirmation`; `.sdkmanrc` 는 SDKMAN 단독. → 단일 source 로 `.tool-versions` 권장(둘 다 두면 drift, §외부근거 보강후보).
|
||||
|
||||
| 항목 | 구현 anchor (목표) | ca-tmpl 실제 상태 | grade |
|
||||
|---|---|---|---|
|
||||
| build JDK 핀 | Gradle toolchain 21 | `JavaLanguageVersion.of(21)` 실존 | `actually-implemented` |
|
||||
| Gradle 버전 핀 | repo wrapper 로 고정 | wrapper **9.0.0** (노트 "8.x" 와 drift) | `actually-implemented` (버전 숫자 정정 필요, §Audit `GRADLE_VERSION_DRIFT`) |
|
||||
| IDE/CLI JDK 핀 | `.tool-versions` 단일 포맷 | `.tool-versions`/`.sdkmanrc`/`.mise.toml` **미존재** | `planned` |
|
||||
| Temurin 21 LTS EOL 명시 | Adoptium support 페이지 인용 | `DX-TV-C8` `needs-confirmation` (별도 fetch 필요) | `planned` |
|
||||
|
||||
### 3. integration test backend — Testcontainers
|
||||
|
||||
> **Trace**: D10 / `dx-testcontainers#TC-CORE-C1`,`#TC-SPRING-C1`,`#TC-REUSE-C1`. anchor = ca-tmpl `src/app-bootstrap/.../contract/outbox/OutboxAppendTransactionalContractTest.java` 등.
|
||||
>
|
||||
> - **UNSUPPORTED_IMPL_DECISION**: container 공유 전략(`@ServiceConnection` vs 수동 `@Container` singleton). 외부 raw 의 `@ServiceConnection`(`TC-SPRING-C1`)·singleton(`TC-SINGLETON-C1`) 인용이 `needs-confirmation` 이라 verbatim 미확정. trade-off: 실제 코드는 수동 `@Container PostgreSQLContainer` 채택(boilerplate 더 많으나 명시적). @ServiceConnection 전환은 Spring Boot reference 재fetch 후 별도.
|
||||
|
||||
| 항목 | 구현 anchor (목표) | ca-tmpl 실제 상태 | grade |
|
||||
|---|---|---|---|
|
||||
| integration backend | Testcontainers | `@Testcontainers`+`@Container PostgreSQLContainer` (Outbox/DistributedLock contract test) 실존 | `actually-implemented` (수동 방식) |
|
||||
| boilerplate 제거 | `@ServiceConnection` (Spring Boot 3.1+) | `@ServiceConnection` **미사용** | `planned` (§Audit `SERVICECONNECTION_NOT_USED`) |
|
||||
| reuse 정책 | 로컬 opt-in / CI off | `.testcontainers.properties`·`testcontainers.reuse.enable` **미존재** | `planned` |
|
||||
| bootstrap vs test 분리 | docker compose(bootstrap) ↔ Testcontainers(test) 별도 명시 | compose 파일 빈 상태 → bootstrap 측 미구현 | `planned` |
|
||||
|
||||
### 4. README entrypoint + link-rot gate
|
||||
|
||||
> **Trace**: D4(README 진입점) + D8(link-rot 도구) / D8 은 §외부근거 2026-06-15 addendum. anchor = ca-tmpl `README.md`(§로컬 실행/§테스트/§환경 변수 규칙) + (link-rot config 미존재).
|
||||
>
|
||||
> - **UNSUPPORTED_IMPL_DECISION**: link-rot 도구 선택(lychee vs markdown-link-check vs linkinator). 2026-06-15 조사로 lychee 조건부 권고하나 raw archiving `deferred`(승인 대기). README↔command drift 검사 메커니즘(`verifyReadmeCommands` Gradle task)은 본 branch 임의 설계 — trade-off: 자동 강제 가능하나 ```bash 블록 파싱 규칙은 ca-tmpl 고유.
|
||||
|
||||
| 항목 | 구현 anchor (목표) | ca-tmpl 실제 상태 | grade |
|
||||
|---|---|---|---|
|
||||
| README local entrypoint | §로컬 실행 (첫 실행 명령) | README 실존, `cd src && ./gradlew bootRun` + `GET /api/healthcheck` | `actually-implemented` (단 `bootstrap`/smoke 미반영) |
|
||||
| README↔command drift 검사 | Gradle `verifyReadmeCommands` | **미존재** | `planned` |
|
||||
| link-rot gate | lychee(`lycheeverse/lychee-action@v2.0.2+`) CI 게이트 | config·CI·`package.json` **모두 미존재** | `planned` |
|
||||
|
||||
### 5. 위임 관심사 (OUT_OF_BRANCH_SCOPE → 다른 owner)
|
||||
|
||||
> 본 branch DX 진입점 밖이지만 governing DX 관심사인 것 — 결정 영역이 sibling owner 에 있으므로 §구현 가이드에 detail 을 남기지 않고 위임(R3). 위임 history 는 §Audit & Findings.
|
||||
|
||||
| 위임 관심사 | owner branch | 실제 메커니즘 (ca-tmpl) |
|
||||
|---|---|---|
|
||||
| `.env.example` / env key self-sufficiency | [[raw/branch-notes/feature-env-driven-runtime-configuration]] D7 | `src/.env`(git-tracked) + `verifyEnvKeys` 3-way + `env-keys.yaml` SSOT. `.env.example` **미사용** |
|
||||
| sample enable/disable 런타임 토글 | `feature-sample-removal-adoption-contract` | env `APP_SAMPLE_ENABLED`(registry-backed) + `prod_profile_must_be_false` + sample-off smoke. 런타임 토글 *코드 메커니즘*은 owner 확정 대상(미구현) — 본 branch 가 단정 안 함 |
|
||||
| sample production 격리 | [[raw/branch-notes/feature-sample-domain-contract-fixture]] D5 | ArchUnit `production_code_does_not_depend_on_sample_portfolio` + test-scope(`actually-implemented`) |
|
||||
| fresh-clone smoke CI job | `feature-ci-quality-gates-contract` | CI 미존재 — `fresh-clone-smoke` job `planned` |
|
||||
|
||||
## 엣지·실패·의존
|
||||
|
||||
> R4(깊이 게이트) 캡처용. 정상 경로 외 *구현 중 부딪힐* 실패/엣지/다른 계약 의존.
|
||||
|
||||
- **실패·엣지 경로**:
|
||||
- bootstrap (2) `docker compose up -d` — Docker daemon 미기동 시 즉시 fail-fast + 안내(현 compose 파일 빈 상태이므로 step 2 자체 미정의). 기대: exit ≠ 0 + "Docker 필요" 메시지.
|
||||
- bootstrap (3) Flyway — out-of-order migration / checksum mismatch 시 fail. `baseline-on-migrate: false` 이므로 빈 DB 가정; 기존 스키마 존재 시 baseline 충돌.
|
||||
- **Apple Silicon (arm64) emulation** — 일부 Testcontainers image 가 amd64-only 면 emulation → bootstrap 시간 증가(D5 "macOS Apple Silicon 우선" 과 충돌 가능, TC raw §메모 경고만, 정량 근거 없음 → Claims To Verify).
|
||||
- link-rot false-positive — GitHub/LinkedIn 등 bot-blocker 429/999, Obsidian `[[wikilink]]` 는 표준 URL 아님 → 세 도구 모두 미검출. lychee `accept`/`.lycheeignore` 로 제어, wikilink 는 별도 처리 필요.
|
||||
- tool-version 불일치 — `.tool-versions` 핀과 CI runner/로컬 JDK 가 다르면 reproducible build 깨짐(D6; ci-quality-gates 와 공유).
|
||||
- smoke test green ≠ 정상 — 5단계 중 어디서 실패했는지 step 별 exit code 분리 필요(wiki/projects DevOps 문서 "과장 금지" 항목).
|
||||
- **다른 계약 의존**:
|
||||
- `[[raw/branch-notes/feature-env-driven-runtime-configuration]]` D7 — `.env`/env-keys SSOT(`verifyEnvKeys`). 이 계약이 `.env.example` 부재를 확정하므로 본 branch 의 env template 관심사는 그쪽 결과를 consume. 그 계약이 바뀌면 본 branch bootstrap step 0(env 준비) 영향.
|
||||
- `[[raw/branch-notes/feature-sample-removal-adoption-contract]]` — `APP_SAMPLE_ENABLED` 런타임 토글. bootstrap (4) sample seed 가 이 flag 를 consume.
|
||||
- `[[raw/branch-notes/feature-sample-domain-contract-fixture]]` D5 — sample-portfolio 격리(ArchUnit). bootstrap 이 sample 을 켜도 prod 경로 침범 없음의 근거.
|
||||
- `[[raw/branch-notes/feature-ci-quality-gates-contract]]` — `fresh-clone-smoke` job + Testcontainers reuse CI off 정책. 본 branch 의 테스트 계약(fresh-clone-smoke)이 그 CI gate 에서 실행됨.
|
||||
- `[[raw/branch-notes/feature-test-taxonomy-fixture-contract]]` — integration test taxonomy 가 Testcontainers 를 default backend 로 둠(D10 과 공유). @ServiceConnection 전환 결정의 공동 영역.
|
||||
- `[[raw/branch-notes/feature-container-runtime-contract]]` — container JVM/healthcheck/graceful-shutdown 기준. bootstrap 이 띄우는 런타임의 health probe(`/api/healthcheck`)는 그 계약과 정합.
|
||||
|
||||
## 테스트 계약
|
||||
|
||||
- .env.example 자급자족 검사: clean clone 직후 `cp .env.example .env && ./gradlew bootstrap`만으로 5단계 sub-task(compileTestJava → docker compose up -d → Flyway migrate → sample profile seed → smoke test)가 모두 통과해야 함. 측정 방법: CI에 `fresh-clone-smoke` job 추가 — clean container에서 위 명령 시퀀스 실행 후 exit code 0 + smoke test green. 추가 prompt/수동 입력이 필요하면 fail. **⚠️ 2026-06-15 정합**: sibling `feature-env-driven-runtime-configuration` B 결정으로 `.env.example` 대신 `src/.env`(git-tracked) 사용 → 본 검사의 `cp .env.example .env` 전제는 `src/.env` 기준으로 갱신 필요(§Audit `ENV_EXAMPLE_SUPERSEDED`).
|
||||
- sample profile이 prod profile에서 켜지면 실패.
|
||||
- README ↔ 실 command drift 검사: README.md의 code block에 등장하는 모든 `./gradlew`, `docker compose`, `make` command가 실제 build script에 존재해야 함. 측정 방법: `markdown-link-check` + 자체 Gradle task `verifyReadmeCommands`. README parsing: ```bash 블록에서 command 추출 → 각 command의 첫 token이 build script에 정의된 task이거나 system 표준 도구(`docker`, `git` 등)여야 함. 미정의 command 1건이라도 있으면 fail.
|
||||
- bootstrap command가 하나로 고정되지 않으면 실패.
|
||||
|
||||
## 검증해야 할 주장
|
||||
|
||||
> 공식 문서 / 사례는 근거지만 ca-tmpl 프로젝트에서의 동작을 자동 보장하지 않음. 구현 전/중/후 실제 검증 대상.
|
||||
|
||||
| Claim | Why uncertain | How to verify | Status |
|
||||
|---|---|---|---|
|
||||
| `./gradlew bootstrap` 5단계가 clean clone 직후 추가 prompt 없이 모두 통과한다 | bootstrap task 자체가 ca-tmpl 고유 합성 — 외부 raw 가 5단계 합성을 보장하지 않음 (Testcontainers core claim 은 test backend 적합성만 증명) | CI `fresh-clone-smoke` job: clean container 에서 `cp .env.example .env && ./gradlew bootstrap` 실행 → exit code 0 + smoke test green | `planned` |
|
||||
| README ↔ build script command drift 가 0 건 | README 의 code block 과 실제 task 정의 일치는 자동 보장되지 않음 | Gradle task `verifyReadmeCommands` — README 의 ```bash 블록에서 command 추출 → 첫 token 이 build script task 또는 system 표준 도구인지 검사. 미정의 1건이라도 fail | `planned` |
|
||||
| `@ServiceConnection` 이 ca-tmpl 의 모든 dependency (PostgreSQL / Redis / Kafka 등) 에 대해 boilerplate 제거를 보장 | `TC-SPRING-C1` 이 `needs-confirmation` — 지원 module 범위 미확정 | Spring Boot reference docs 재fetch 로 supported module list 확보 → ca-tmpl dependency 목록과 교차 | `needs-confirmation` |
|
||||
| Testcontainers reuse 가 로컬에서 의도된 startup 단축 효과를 내고 CI 에서는 비활성화된다 | `TC-REUSE-C1` property 명과 "must not be enabled in CI" 표현이 `needs-confirmation` | Testcontainers reuse docs (https://java.testcontainers.org/features/reuse/) 재fetch + 로컬 측정 (cold start vs reused) + CI yaml 에서 reuse 플래그 부재 확인 | `needs-confirmation` |
|
||||
| Temurin 21 LTS 의 EOL 일자가 ca-tmpl 채택 주기 (≥ 36 개월) 와 호환 | `DX-TV-C8` 이 `needs-confirmation` — Adoptium support 페이지 인용 미확보 | https://adoptium.net/support/ 재fetch 로 정확한 EOL 일자 확정 후 branch note 갱신 | `needs-confirmation` |
|
||||
| mise 와 asdf 가 동일한 `.tool-versions` 파일을 100% 호환 해석 | `DX-TV-C5` "Does not prove" 컬럼에서 명시적으로 보장 안 됨 | mise 공식 페이지 (`.tool-versions` 호환성 섹션) 재fetch + 두 도구로 동일 파일 read/install 시연 | `needs-confirmation` |
|
||||
| `.sdkmanrc` 와 `.tool-versions` 가 동시 존재할 때 drift 가 발생하지 않는다 (또는 단일 source 정책 채택) | `DX-TV-C7` 이 `needs-confirmation` — SDKMAN `.sdkmanrc` 포맷 verbatim 미확보 | SDKMAN docs (https://sdkman.io/usage#env) fetch → ca-tmpl 정책을 "또는" 에서 단일 source 로 좁힐지 결정 | `planned` |
|
||||
| Apple Silicon (arm64) 에서 Testcontainers image 의 emulation 비용이 bootstrap 시간 (목표 1단계 분 이내) 을 초과하지 않는다 | Testcontainers raw 메모에서 경고만 됨 — 정량 근거 없음 | M1/M2 환경에서 bootstrap 측정 + arm64 native image 가용 여부 module 별 점검 | `planned` |
|
||||
| devcontainer 채택 시 ca-tmpl `./gradlew bootstrap` 5단계가 devcontainer 안에서 동등 동작 | `DX-DC-C5` 가 tool/runtime stack 만 보장 — Flyway 순서 / smoke test 자동 보장 안 함 | `.devcontainer/devcontainer.json` 작성 → Codespaces + 로컬 VS Code 양쪽에서 bootstrap 실행 → exit code 비교 | `planned` |
|
||||
| markdown-link-check 가 README + docs/ 의 모든 wikilink + URL 을 false-positive 없이 검출 | 도구 선택 자체에 외부 spec 미수집 (D8 — 2026-06-15 lychee 권고로 재검토) | npm 패키지 reference 확인 + CI 에서 dry-run → false-positive 목록 수집 후 ignore pattern 확정 | `planned` |
|
||||
| lychee 가 ca-tmpl 의 README + docs/ relative file link + external URL 을 false-positive 없이 검출하고 CI 에서 broken link 시 exit ≠ 0 | 2026-06-15 조사로 권고됐으나 ca-tmpl 실 파일 dry-run 미실시 + lychee-action CVE pin 필요 | `lychee --root-dir . './docs/**/*.md' './README.md'` dry-run → `.lycheeignore` 수렴 → `.github/workflows/link-check.yml`(`lycheeverse/lychee-action@v2.0.2+`, `fail: true`) 에 broken link 인위 삽입 → exit ≠ 0 확인 | `planned` |
|
||||
|
||||
## 관심사 커버리지
|
||||
|
||||
> `/coverage` 가 채우는 **생성물** — 손유지 금지. governing 문서(`wiki/projects/ca-tmpl/devops-ci-supply-chain-dx` §DX + parent §18 Developer Experience)가 요구하는 DX 관심사를 본 branch 가 빠짐없이 덮는지. 기준: `rules/coverage-gate.md`. 아래는 `/branch-spec` 가 staged 한 seed — `coverage-auditor` 가 코드/선례 대조로 확정.
|
||||
|
||||
| 관심사 (governing) | 상태 | owner | 심각도 | 근거 |
|
||||
|--------|------|-------|--------|------|
|
||||
| local bootstrap command (단일 진입점) | covered-here | — | — | D3 (`planned` — `bootstrap` task 미존재) |
|
||||
| `.env.example` / env template self-sufficiency | delegated | [[raw/branch-notes/feature-env-driven-runtime-configuration]] | OK | D7(sibling) — `src/.env`+`verifyEnvKeys`, §Audit `ENV_EXAMPLE_SUPERSEDED` |
|
||||
| Testcontainers 또는 local dependency 대체 | covered-here | — | — | D10 (manual `@Container` 실존, `@ServiceConnection` planned) |
|
||||
| smoke test command | covered-here | — | — | D3 step5 + 테스트 계약 (`planned`) |
|
||||
| sample profile 실행/비활성화 | delegated | [[raw/branch-notes/feature-sample-removal-adoption-contract]] | OK | D2/D7 위임, §Audit `SAMPLE_ENABLE_MECHANISM_DRIFT` |
|
||||
| README/runbook link 기준 | covered-here | — | — | D4 + D8 link-rot (`planned`) |
|
||||
| tool version pinning (Temurin 21 LTS) | covered-here | — | — | D6 (toolchain 21 실존, `.tool-versions` planned) |
|
||||
| link-rot / dead-link check | covered-here | — | — | D8 lychee 권고 (raw archiving deferred) |
|
||||
| fresh-clone smoke CI job | delegated | [[raw/branch-notes/feature-ci-quality-gates-contract]] | OK | §엣지·실패·의존 다른 계약 의존 |
|
||||
|
||||
## Audit & Findings
|
||||
|
||||
> 2026-06-15 `/branch-spec` ca-tmpl `src/` 코드 대조 결과. 사용자 작성 결정 영역이므로 자동 rewrite 하지 않고 **정합 권고만** 기록(추측 단정 금지).
|
||||
|
||||
| Finding ID | 유형 | 내용 | 권고 |
|
||||
|---|---|---|---|
|
||||
| `BOOTSTRAP_TASK_ABSENT` | planned (drift 아님) | `./gradlew bootstrap` task 미등록(`app-bootstrap` 은 모듈명). 현 first-run = `cd src && ./gradlew bootRun`. docker-compose 3종 0-byte. | D3 를 `planned` 로 명시(완료). Phase C2 구현 시 custom task + step exit code 분리. |
|
||||
| `GRADLE_VERSION_DRIFT` | drift | 노트 D6 "gradle-wrapper 8.x" vs 실제 `gradle-wrapper.properties` **9.0.0**. | 결정 사항 2026-06-15 정합 라인 + D6 Open Risk 반영(완료). 버전 숫자만 9.0.0 으로 정정, 핀 전략 유효. |
|
||||
| `ENV_EXAMPLE_SUPERSEDED` | drift (superseded by sibling) | 노트의 `.env.example` 결정(Decisionized Work Items + 테스트 계약)이 [[raw/branch-notes/feature-env-driven-runtime-configuration]] D7(2026-06-08 B: `.env.example` 미사용, `src/.env`+`verifyEnvKeys`+`env-keys.yaml` SSOT)과 충돌. | env template self-sufficiency 관심사를 그 sibling 에 **위임**(§Coverage). 테스트 계약의 `cp .env.example .env` 를 `src/.env` 기준으로 갱신 권고(완료). |
|
||||
| `SAMPLE_ENABLE_MECHANISM_DRIFT` | drift | 노트 D2/D7 이 Spring `@Profile` enablement 가정. 실제 = ArchUnit `production_code_does_not_depend_on_sample_portfolio` + test-scope(격리, [[raw/branch-notes/feature-sample-domain-contract-fixture]] D5) + env `APP_SAMPLE_ENABLED`(런타임 토글, `feature-sample-removal-adoption-contract` owner; registry-backed, 토글 코드 메커니즘 미구현). | enable/disable·격리 모두 sibling 위임으로 표기(완료). `@Profile` 표현은 sibling 결정으로 대체. 토글 코드 메커니즘은 owner 가 확정(본 branch 단정 안 함). |
|
||||
| `SERVICECONNECTION_NOT_USED` | planned (drift) | 노트 D10 "@ServiceConnection default" vs 실제 수동 `@Container PostgreSQLContainer`(Outbox/DistributedLock contract test). | D10 reality grade `planned`(완료). @ServiceConnection 전환은 `TC-SPRING-C1` 재fetch 후 별도(Claims To Verify). |
|
||||
|
||||
### 2026-06-24 구현 판정
|
||||
|
||||
| Finding ID | 결과 | 증거 등급 | 남은 경계 |
|
||||
|---|---|---|---|
|
||||
| `BOOTSTRAP_TASK_ABSENT` | `bootstrapCompile` → `bootstrapDependencies` → `bootstrapMigrateAndStart` → `bootstrapSampleContract` → `bootstrapSmoke` 구현 | `locally-verified` | macOS/WSL2 clean clone 미검증 |
|
||||
| `GRADLE_VERSION_DRIFT` | wrapper 9.0.0 유지, `.tool-versions` Temurin 21.0.11+10 소비 | `actually-implemented` | tool manager별 해석은 미검증 |
|
||||
| `ENV_EXAMPLE_SUPERSEDED` | `src/.env`를 Compose `env_file`로 소비, 새 `.env.example` 미생성 | `locally-verified` | sibling owner 유지 |
|
||||
| `SERVICECONNECTION_NOT_USED` | Spring context/slice 2개는 `@ServiceConnection`; direct JDBC/SQLState tests는 명시적 container factory 유지 | `locally-verified` | 공식 지원 범위 source refetch 미완료 |
|
||||
| `LINK_ROT_GATE_ABSENT` | `lycheeverse/lychee-action@v2.0.2`, `fail: true` workflow 추가 | `actually-implemented` | remote workflow 실행은 `needs-confirmation` |
|
||||
|
||||
## 완료 후 wiki 추출 대상
|
||||
|
||||
- `wiki/projects/ca-skeleton-operational-contract.md`의 developer experience canonical section.
|
||||
- `wiki/projects/ca-tmpl/devops-ci-supply-chain-dx.md` 의 DX 슬라이스 (governing doc).
|
||||
|
||||
## 마주친 문제
|
||||
|
||||
- [[raw/errors/bootstrap-postgres-port-collision-2026-06-24]] — 불필요한 DB host port publish가 기존 5432 container와 충돌; internal-only network로 해결.
|
||||
- [[raw/errors/slim-jre-random-generator-missing-2026-06-24]] — full JDK test에서 보이지 않던 slim JRE RNG provider 차이; `java.base` RNG bean과 container smoke로 해결.
|
||||
- 공식 Spring/Testcontainers 문서 web fetch는 403으로 차단됐다. D10의 최신 공식 지원 범위는 `needs-confirmation`을 유지한다.
|
||||
|
||||
## 묶음
|
||||
|
||||
<!-- GENERATED: branches:start -->
|
||||
- [[raw/branch-notes/chore-harness-policy-engine-alignment]]
|
||||
<!-- GENERATED: branches:end -->
|
||||
|
||||
### Sub-branches
|
||||
|
||||
- [[raw/branch-notes/chore-harness-policy-engine-alignment]] — module registry, strict evidence, platform renderer, risk-profile 기반 개발 하네스 정합.
|
||||
|
||||
<!-- GENERATED: sources:start -->
|
||||
- [[raw/official-docs/dx-devcontainer-spring-boot]]
|
||||
- [[raw/official-docs/dx-mise-asdf-tool-versioning]]
|
||||
- [[raw/official-docs/dx-testcontainers-java-best-practices]]
|
||||
- [[raw/official-docs/supply-chain-gradle-vs-maven-dependency-locking]]
|
||||
<!-- GENERATED: sources:end -->
|
||||
|
||||
<!-- GENERATED: interviews:start -->
|
||||
- [[raw/interviews/single-command-local-bootstrap]]
|
||||
<!-- GENERATED: interviews:end -->
|
||||
|
||||
<!-- GENERATED: errors:start -->
|
||||
- [[raw/errors/bootstrap-postgres-port-collision-2026-06-24]]
|
||||
- [[raw/errors/jpa-repository-scan-miss-multimodule-2026-06-10]]
|
||||
- [[raw/errors/slim-jre-random-generator-missing-2026-06-24]]
|
||||
<!-- GENERATED: errors:end -->
|
||||
|
||||
<!-- GENERATED: daily-notes:start -->
|
||||
- [[raw/daily-notes/2026-06-30]]
|
||||
<!-- GENERATED: daily-notes:end -->
|
||||
|
||||
<!-- GENERATED: blog-topics:start -->
|
||||
- [[raw/blog-topics/five-stage-local-bootstrap-contract-2026-06-24]]
|
||||
<!-- GENERATED: blog-topics:end -->
|
||||
|
||||
> 본 feature branch 는 개발 하네스 정합 child를 소유한다. 추가 child/derived 자료는 이 섹션에서 그룹화한다.
|
||||
|
||||
### 오류 기록 (본 feature 작업 중 발생)
|
||||
|
||||
- [[raw/errors/bootstrap-postgres-port-collision-2026-06-24]] — host 5432 충돌과 internal-only DB network 결정.
|
||||
- [[raw/errors/slim-jre-random-generator-missing-2026-06-24]] — slim JRE provider parity 오류와 `java.base` RNG 수정.
|
||||
|
||||
### 면접 준비 (이 작업에서 나올 수 있는 면접 질문)
|
||||
|
||||
- [[raw/interviews/single-command-local-bootstrap]] — 단일 bootstrap의 단계 분리·실패 계약·문서 drift 질문.
|
||||
|
||||
### 블로그·채용공고 연계 글감
|
||||
|
||||
- [[raw/blog-topics/five-stage-local-bootstrap-contract-2026-06-24]] — 5단계 bootstrap과 실제로 잡힌 runtime gap 글감.
|
||||
- Job posting: 없음 — 채용공고에서 파생된 작업이 아님.
|
||||
- derived blog: 생성 전. canonical 추출 요청이 없어 직접 생성하지 않음.
|
||||
|
||||
## 관련 일일 노트
|
||||
|
||||
> 이 브랜치를 작업한 날짜들. 양방향 nav 유지.
|
||||
|
||||
- [[raw/daily-notes/2026-06-30]]
|
||||
- (생성 2026-05-22 / branch-spec 2026-06-15 — 해당 daily-note 미연결. 작업 재개 시 `[[raw/daily-notes/YYYY-MM-DD]]` 추가)
|
||||
|
||||
## 완료 후 정리
|
||||
|
||||
> 머지/종료 시점에 채움.
|
||||
|
||||
- PR 링크:
|
||||
- 리뷰 메모:
|
||||
- 머지 결과 / 배포 환경:
|
||||
- **wiki 추출 대상** (verified만, `wiki/projects/`로만 추출):
|
||||
- `actually-implemented` 항목:
|
||||
- `locally-verified` 항목:
|
||||
- `prod-verified` 항목:
|
||||
- **추출하지 않을 항목** (planned / documented-only / abandoned):
|
||||
Reference in New Issue
Block a user