Files
llm-wiki/vault/30-knowledge/projects/ca-tmpl/config-and-adapter-templates.md
T

10 KiB

title, source_type, status, confidence, tags, related_projects, last_reviewed
title source_type status confidence tags related_projects last_reviewed
ca-tmpl - Config & Adapter Templates 결정 (env-driven + ConditionalOnProperty) project verified high
ca-tmpl
12-factor
config
conditional-on-property
actually-implemented
locally-verified
ca-tmpl
2026-07-02

ca-tmpl - Config & Adapter Templates 결정 (env-driven + ConditionalOnProperty)

Layer: wiki/projects/ — ca-tmpl skeleton 프로젝트의 Config & Adapter 영역 결정 사항. 일반 개념은 wiki/concepts/config-and-adapter-templates 참조.

프로젝트 컨텍스트

ca-tmpl skeleton — Clean Architecture 기반 Spring Boot 템플릿. 신규 백엔드 서비스를 시작할 때 use case / port / adapter 경계, env-driven config, optional adapter on/off, 운영 contract(observability / failure / supply chain 등)를 미리 fix해 두는 사내용 skeleton.

본 문서가 다루는 영역(canonical §9 Env-driven Runtime Configuration, §29 Group G-I Adapter Failure & Disabled):

  • Env config 결정: APP_ prefix + Duration 30s 형식 1택 + boolean true/false only + no-runtime-reload + .env.example drift 검증.
  • Adapter on/off 결정: optional module + @ConditionalOnProperty 3-layer detection (Spring bean + ArchUnit static + AdapterDisabledException runtime fail-fast).

진행 상황: C2 부분 구현 + 로컬 검증 완료. docs/registries/env-keys.yaml, verifyEnvKeys, @ConfigurationProperties settings, startup safety validator, optional-adapter 조건부 테스트/ArchUnit guard가 존재한다. 모든 provider-specific adapter template가 구현된 것은 아니다.

실제 구현 내용 (actually-implemented)

  • docs/registries/env-keys.yaml과 Gradle verifyEnvKeys gate가 존재한다.
  • app-bootstrap, adapter-web, sample-portfolio 등에 @ConfigurationProperties 기반 *Settings 타입이 존재한다.
  • StartupSafetyValidator, RuntimeNumericBoundsValidator, RequiredEnvironmentValidator, RequiredAdapterDisabledException이 startup fail-fast guard를 구성한다.
  • DisabledAdapterArchitectureTest가 optional adapter bean의 @ConditionalOnProperty 부착과 disabled-default boundary를 정적으로 검증한다.
  • EnabledIfRedisCacheEnabled, EnabledIfHttpRetryEnabled, EnabledIfHttpCircuitBreakerEnabled 등 optional adapter contract test 조건부 실행 annotation이 존재한다.

로컬/dev 검증 (locally-verified)

  • ./gradlew check 통과(2026-07-02, BUILD SUCCESSFUL, 114 tasks).
  • 실행 중 verifyEnvKeys: OK — 99 env keys, 72 required placeholders covered, 85 APP_ keys registered가 출력되었다.
  • EnvProfileMatrixContractTest, StartupSafetyValidatorTest, RuntimeNumericBoundsValidatorTest, DisabledAdapterArchitectureTest가 env/profile/optional adapter contract를 검증한다.

운영 검증 (prod-verified)

없음. ca-tmpl은 skeleton이며 prod 배포 이력 없음.

문서/계획만 존재 (documented-only / planned)

다음 결정은 구현된 gate와 아직 provider-specific adapter template로 남은 부분을 함께 기록한다.

Env config (canonical §9)

  • APP_ prefix — application-owned env는 APP_ 접두사로 통일, 외부 의존 env(SPRING_*, JAVA_OPTS 등)와 시각적 분리.
  • Duration 1택 — Spring Duration 입력은 30s 형식으로 통일(ISO-8601 PT30S 금지). 동일 의미 두 표기가 공존하면 grep/diff 비용이 발생.
  • Boolean true/false only1/0, yes/no, on/off 금지. Spring Binder가 허용하더라도 contract 수준에서 1택.
  • No-runtime-reload@RefreshScope, Spring Cloud Config refresh endpoint, Spring Cloud Kubernetes auto-reload 모두 기본 금지. config 변경은 재배포로만 반영.
  • .env.example drift verify@ConfigurationProperties에 선언된 모든 env가 .env.example에도 존재해야 함을 빌드 단계에서 강제. 누락 시 build fail.

5종 대안 검토 (concept 문서 참조)

wiki/concepts/config-and-adapter-templates에서 다음 5종을 검토하고 ca-tmpl scope에서는 모두 채택하지 않기로 결정:

  • Spring Cloud Config Server — config server SPOF + bootstrap 의존
  • k8s ConfigMap + Spring Cloud Kubernetes auto-reload — pod별 partial-state + k8s lock-in
  • HashiCorp Consul KV — KV+watch 운영 비용
  • AWS Parameter Store / AppConfig — AWS lock-in + per-call billing
  • LaunchDarkly / Unleash — product-grade A/B/canary 요구가 발생하기 전에는 over-engineering, ca-tmpl scope 밖

Adapter templates (canonical §29 G-I)

  • Layer 1 — Spring @ConditionalOnProperty: APP_ADAPTER_<NAME>_ENABLED=true일 때만 adapter bean 등록. optional module 자체는 dependency로 두지만 disabled 시 bean 등록 X.
  • Layer 2 — ArchUnit static detection: noClasses().that().resideInAPackage("..application..").should().dependOnClassesThat().resideInAPackage("..adapters.<disabled>..") 형태의 정적 dependency rule. application code가 disabled adapter package를 import하는 것을 빌드 단계에서 차단.
  • Layer 3 — AdapterDisabledException runtime fail-fast: disabled adapter가 어떤 경로로든 호출되면 즉시 AdapterDisabledException을 던져 silent failure 방지.
  • ArchUnit Layer 2 정적 검사 범위 명확화 (2026-05-22) — annotation 존재까지만 정적 보장(@ConditionalOnProperty 부착 + app.adapter.<name>.enabled naming pattern), runtime active 여부 검사는 Layer 3 (AdapterDisabledException)에 위임. 자세한 평가는 raw/official-docs/archunit-conditional-on-property-3-layer-pattern (status: needs-confirmation).

Layer 1/2 일부와 startup fail-fast guard는 구현되어 있다. 다만 Kafka/Slack/Email 같은 모든 provider-specific adapter template와 runtime call path의 disabled sentinel은 범위별로 추가 확인이 필요하다.

면접에서 말할 수 있는 범위

자신 있게 답할 수 있는 질문

  • "12-factor §III. Config가 의미하는 'config와 코드 분리'는 구체적으로 무엇을 강제하는가"
  • "ca-tmpl이 no-runtime-reload를 기본 방침으로 둔 결정의 근거는?"
  • "@ConditionalOnProperty 3-layer (Spring bean 조건 + ArchUnit static + runtime fail-fast)가 각각 어떤 실패 시나리오를 잡는지"
  • "Java SPI ServiceLoader@ConditionalOnProperty가 adapter on/off 표현에서 어떻게 다른지"
  • "LaunchDarkly 같은 feature flag SaaS와 @ConditionalOnProperty startup toggle은 어떤 운영 요구가 생겼을 때 갈라지는지(trade-off)"

적당히 답할 수 있는 질문

  • "@RefreshScope를 금지로 둔 이유" — 결정 근거는 설명 가능. 운영 데이터/사례는 없음.
  • "Vault dynamic credential과 @RefreshScope 같은 runtime reload 메커니즘이 충돌하는 지점" — 개념적으로는 설명 가능. 직접 운영 경험 없음.

답하면 안 되는 질문 (모른다고 해야 함)

  • "@ConfigurationProperties 검증을 운영 환경에서 어떻게 운용하는가" — 운영 경험 없음.
  • "adapter on/off를 실제 환경에서 전환한 경험" — 없음. ca-tmpl은 skeleton 단계.
  • "Layer 2 ArchUnit rule이 실제 빌드에서 어떤 위반을 잡았는가" — DisabledAdapterArchitectureTest./gradlew check 통과 범위까지 답할 수 있음. 모든 provider adapter runtime path 검증은 별도 확인 필요.

과장 금지 지점

  • "@RefreshScope만 도입하면 dynamic config가 된다". ca-tmpl은 @RefreshScope를 기본 금지로 두는 결정을 했고, 본인은 dynamic config를 운영한 경험이 없음. "도입 가능" 정도로만 표현해야 함.
  • "@ConditionalOnProperty 3-layer가 disabled adapter 호출을 완전 검증한다". Layer 1/2와 startup fail-fast 일부는 검증됐지만, 모든 provider adapter runtime path까지 자동 보장한다고 쓰지 않는다.
  • "ca-tmpl이 LaunchDarkly를 거부했다". "ca-tmpl scope 밖으로 위임했다" / "product-grade A/B/canary 요구가 발생하면 별도 branch로 다룬다"는 표현이 정확.
  • "Config & Adapter 전체가 구현 완료". env registry/gate와 optional-adapter guard는 구현됐지만 provider별 adapter template 완성도는 범위별 확인이 필요하다.

Blog-topic ingest: env/config/adapter 묶음 (2026-07-02)

관련 개념

Sources

Cluster / 묶음