# 가족 문서가 이 항목을 어떻게 들고 있는가 messaging/CLAUDE.md:70:## application이 이 family에 도달하는 경로 (MSG-015, 미해결) messaging/CLAUDE.md:82:이것이 리뷰의 **MSG-015 (P0)** 이며 닫히지 않았다. 지금 안전한 이유는 설계가 아니라 기본값이다 — # 두 스택의 설정 클래스와 생산자 빈 bootstrap/messaging/KafkaSenderConfig.java:37 @Configuration(proxyBeanMethods = false) bootstrap/messaging/KafkaSenderConfig.java:38 @ConditionalOnProperty(name = "app.messaging.broker", havingValue = "kafka") bootstrap/messaging/KafkaSenderConfig.java:39 public class KafkaSenderConfig { bootstrap/messaging/KafkaSenderConfig.java:61 @Bean(name = "kafkaSeamProducer", destroyMethod = "close") bootstrap/messaging/KafkaSenderConfig.java:62 @ConditionalOnMissingBean(name = "kafkaSeamProducer") bootstrap/messaging/KafkaSenderConfig.java:63 public Producer kafkaSeamProducer(KafkaAdapterSettings settings) { autoconfigure/KafkaMessagingAutoConfiguration.java:126 * @return the producer, closed with the context autoconfigure/KafkaMessagingAutoConfiguration.java:127 */ autoconfigure/KafkaMessagingAutoConfiguration.java:128 @Bean(destroyMethod = "close") autoconfigure/KafkaMessagingAutoConfiguration.java:129 @ConditionalOnMissingBean autoconfigure/KafkaMessagingAutoConfiguration.java:130 public org.apache.kafka.clients.producer.Producer messagingKafkaProducer( autoconfigure/KafkaMessagingAutoConfiguration.java:131 org.springframework.core.env.Environment environment) { # 플랫폼 쪽이 켜지는 사슬 main · messaging/autoconfigure/MessagingPlatformRootAutoConfiguration.java:28 @ConditionalOnProperty(prefix = MessagingSettings.PREFIX, name = "enabled", havingValue = "true") main · messaging/autoconfigure/MessagingProviderSelection.java:48 "kafka", KafkaMessagingAutoConfiguration.class, # broker 만 준 시험이 통과하는 이유 — 게이트 뒤 설정을 손으로 등록한다 test · adapter/outbound/messaging/MessagingConfigTest.java:41 .withUserConfiguration(KafkaAdapterConfig.class) test · OptionalAdapterBeanGatingTest.java:59 private final ApplicationContextRunner runner = test · OptionalAdapterBeanGatingTest.java:60 new ApplicationContextRunner() test · OptionalAdapterBeanGatingTest.java:61 // Registered as a real auto-configuration entry, which is how the composition root test · OptionalAdapterBeanGatingTest.java:62 // reaches it: the HTTP Client platform's off state is a property of that entry, not of a test · OptionalAdapterBeanGatingTest.java:63 // hand-assembled subset of its children. test · OptionalAdapterBeanGatingTest.java:64 .withConfiguration(AutoConfigurations.of(HttpClientPlatformAutoConfiguration.class)) test · OptionalAdapterBeanGatingTest.java:65 .withUserConfiguration( test · OptionalAdapterBeanGatingTest.java:66 OutboundSupportConfig.class, test · OptionalAdapterBeanGatingTest.java:67 MessagingConfig.class, test · OptionalAdapterBeanGatingTest.java:68 KafkaAdapterConfig.class, test · OptionalAdapterBeanGatingTest.java:69 NotificationConfig.class, test · OptionalAdapterBeanGatingTest.java:70 SlackNotificationAdapterConfig.class, 두 시험이 컴포지션 루트를 쓰는가 : MessagingConfigTest.java CaSkeletonApplication 언급 0 건 OptionalAdapterBeanGatingTest.java CaSkeletonApplication 언급 0 건 KafkaSenderConfig 가 그 슬라이스에 등록되는가 : MessagingConfigTest.java KafkaSenderConfig 언급 0 건 OptionalAdapterBeanGatingTest.java KafkaSenderConfig 언급 0 건 # 이 조합을 거르는 검증기가 있는가 CapabilityDependencyValidator.java:64 } CapabilityDependencyValidator.java:65 if (relay && !outbox) { CapabilityDependencyValidator.java:66 violations.add( CapabilityDependencyValidator.java:67 "ca-skeleton.outbox.relay-enabled=true only starts the scheduler for a capability that is " CapabilityDependencyValidator.java:68 + "off; set ca-skeleton.outbox.enabled=true or turn the relay off."); CapabilityDependencyValidator.java:69 } CapabilityDependencyValidator.java:70 if (messaging && broker.isEmpty()) { CapabilityDependencyValidator.java:71 violations.add( CapabilityDependencyValidator.java:72 "app.messaging.enabled=true needs a transport; set app.messaging.broker to a registered " CapabilityDependencyValidator.java:73 + "broker id."); CapabilityDependencyValidator.java:74 } CapabilityDependencyValidator.java:75 if ("jdbc" CapabilityDependencyValidator.java:76 .equalsIgnoreCase( CapabilityDependencyValidator.java:77 environment.getProperty( CapabilityDependencyValidator.java:78 "ca-skeleton.capabilities.idempotency.provider", "disabled")) CapabilityDependencyValidator.java:79 && !jpa) { CapabilityDependencyValidator.java:80 violations.add( # 운영 문서가 이 키를 무엇이라고 설명하는가 docs/runbooks/outbox-publish-failed.md:26 ### Step 1 — 확인 docs/runbooks/outbox-publish-failed.md:27 1. ERROR log에서 `OUTBOX_PUBLISH_FAILED` 라인 확인: `event_type`, `event_id`, `correlation_id`, `attempt_count` 추출 docs/runbooks/outbox-publish-failed.md:28 2. broker 상태 확인: `APP_MESSAGING_BROKER` 값과 broker endpoint 가용성. 이 키는 활성화 스위치가 docs/runbooks/outbox-publish-failed.md:29 아니라 **선택자**다 — messaging을 끄는 것은 `APP_MESSAGING_ENABLED=false`이고, 이 값을 비운다고 docs/runbooks/outbox-publish-failed.md:30 messaging이 꺼지지는 않는다. docs/runbooks/outbox-publish-failed.md:31 - `APP_MESSAGING_BROKER`가 공백인 채로 relay가 켜져 있으면 **애플리케이션이 기동하지 않는다** docs/runbooks/outbox-publish-failed.md:32 (`OutboxRelayBrokerRequirementValidator`, MSG-024). 이 조합에서는 publish가 전부 # 출하 설정이 두 키를 어떻게 주는가 compose-profile-contracts.json:170: "APP_MESSAGING_ENABLED": "true", compose-profile-contracts.json:171: "APP_MESSAGING_BROKER": "kafka", compose-profile-contracts.json:202: "APP_MESSAGING_ENABLED": "true", compose-profile-contracts.json:203: "APP_MESSAGING_BROKER": "kafka", compose-profile-contracts.json:604: "APP_MESSAGING_ENABLED": "true", compose-profile-contracts.json:605: "APP_MESSAGING_BROKER": "kafka", .env:38:APP_MESSAGING_BROKER= .env.example:229:APP_MESSAGING_BROKER= .env.example:299:APP_MESSAGING_ENABLED=false .env.local.example:20:APP_MESSAGING_ENABLED=false .env.local.example:21:APP_MESSAGING_BROKER= # KafkaSenderConfig 가 조건에서 물러나는가 KafkaSenderConfig.java:60 */ KafkaSenderConfig.java:61 @Bean(name = "kafkaSeamProducer", destroyMethod = "close") KafkaSenderConfig.java:62 @ConditionalOnMissingBean(name = "kafkaSeamProducer") KafkaSenderConfig.java:63 public Producer kafkaSeamProducer(KafkaAdapterSettings settings) { KafkaSenderConfig.java:64 Map config = new HashMap<>(); KafkaSenderConfig.java:65 config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, String.join(",", settings.brokers())); # 이음매 설정 클래스 자신은 스캔 대상인가 KafkaSenderConfig.java:1 package dev.caskeleton.bootstrap.messaging; AUTO_CONFIGURED_PACKAGES 가 bootstrap.messaging 을 제외하는가 : 0 건 # 이음매 쪽 생산자가 요구하는 설정 빈은 어디서 오는가 main · adapter/outbound/messaging/kafka/KafkaAdapterConfig.java:19 @EnableConfigurationProperties(KafkaAdapterSettings.class) main · adapter/outbound/messaging/autoconfigure/MessagingBridgeRootAutoConfiguration.java:21 @ConditionalOnProperty(prefix = "app.messaging", name = "enabled", havingValue = "true") main · adapter/outbound/messaging/autoconfigure/MessagingBridgeRootAutoConfiguration.java:23 @Import({MessagingConfig.class, KafkaAdapterConfig.class}) # 그 설정 클래스가 컴포넌트 스캔으로 들어올 수 있는가 CaSkeletonApplication.java:41 @ComponentScan( CaSkeletonApplication.java:42 basePackages = { CaSkeletonApplication.java:43 "dev.caskeleton.bootstrap", CaSkeletonApplication.java:44 "dev.caskeleton.adapter", CaSkeletonApplication.java:45 "dev.caskeleton.application", CaSkeletonApplication.java:46 "dev.caskeleton.domain", CaSkeletonApplication.java:47 "dev.caskeleton.shared" CaSkeletonApplication.java:48 }, CaSkeletonApplication.java:49 excludeFilters = { CaSkeletonApplication.java:50 @ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), CaSkeletonApplication.java:51 @ComponentScan.Filter( CaSkeletonApplication.java:52 type = FilterType.CUSTOM, CaSkeletonApplication.java:53 classes = AutoConfigurationExcludeFilter.class), CaSkeletonApplication.java:54 @ComponentScan.Filter( CaSkeletonApplication.java:55 type = FilterType.REGEX, CaSkeletonApplication.java:56 pattern = CaSkeletonApplication.AUTO_CONFIGURED_PACKAGES) CaSkeletonApplication.java:57 }) CaSkeletonApplication.java:100 static final String AUTO_CONFIGURED_PACKAGES = CaSkeletonApplication.java:101 "dev\\.caskeleton\\.bootstrap\\.autoconfigure\\..*" CaSkeletonApplication.java:105 + "|dev\\.caskeleton\\.adapter\\.outbound\\.messaging\\..*" ConfigurationPropertiesScan 목록에 adapter.outbound.messaging 이 있는가 : 0 건 # broker=kafka 를 쓰는 시험마다 같은 파일이 enabled 를 주는가 MessagingConfigTest.java broker=kafka 3 줄 · enabled= 0 줄 OptionalAdapterBeanGatingTest.java broker=kafka 1 줄 · enabled= 0 줄 MessagingLiveRoundTripQualificationTest.java broker=kafka 1 줄 · enabled= 1 줄 MessagingStarterOffContractTest.java broker=kafka 3 줄 · enabled= 7 줄 enabled 를 한 줄도 주지 않는 파일의 시험 이름 : MessagingConfigTest.java:25 void blankBrokerBindsDisabledSentinelsCharacterization() { MessagingConfigTest.java:39 void selectedKafkaBrokerWithoutProjectSenderFailsStartupCharacterization() { MessagingConfigTest.java:54 void selectedBrokerIdMismatchFailsStartupCharacterization() { MessagingConfigTest.java:76 public void send( OptionalAdapterBeanGatingTest.java:77 void allOptionalAdaptersAreDisabledByDefaultAndTheAppStillStarts() { OptionalAdapterBeanGatingTest.java:114 void kafkaSelectedRegistersTheBrokerAndBindsTheRealPublishers() { OptionalAdapterBeanGatingTest.java:135 void slackWebhookEnabledContributesTheProviderAndRoutesBoundNotifications() { OptionalAdapterBeanGatingTest.java:153 void googleEmailEnabledContributesTheProviderAndRoutesBoundNotifications() { OptionalAdapterBeanGatingTest.java:170 void aRouteBindingToADisabledProviderFailsStartup() {