Sub-scope 07 (notification) slack/webhook + email/google + testkit + template resources — manifest and probes revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5 generatedAt=2026-08-30T07:01:25+00:00 === OWNED FILES === 8d8fe37be09d243fb97df633b23729fb30382956 main/java/dev/caskeleton/adapter/outbound/notification/email/google/GoogleEmailClient.java 19 88514a5f083ea33705176543ef257ba6f60c18af main/java/dev/caskeleton/adapter/outbound/notification/email/google/GoogleEmailNotificationAdapterConfig.java 25 69e42abedab03da18483238b1618254292c0a80d main/java/dev/caskeleton/adapter/outbound/notification/email/google/GoogleEmailProvider.java 41 78e64152922eb35ce07a498a507adbe6b38e325d main/java/dev/caskeleton/adapter/outbound/notification/slack/webhook/SlackClient.java 19 a09129dfab637aa5b32bd15c44eba03f2cc43ae8 main/java/dev/caskeleton/adapter/outbound/notification/slack/webhook/SlackNotificationAdapterConfig.java 25 b7805947e3e04e799712e6448bf822e8444c1418 main/java/dev/caskeleton/adapter/outbound/notification/slack/webhook/SlackWebhookProvider.java 42 0bf316a4e6e68ca17bbff6cd5e53cb81b05ea91e test/java/dev/caskeleton/adapter/outbound/notification/platform/testkit/CallbackContract.java 96 6f4e1d597f0ccb31a015f582135286b7a78bde16 test/java/dev/caskeleton/adapter/outbound/notification/platform/testkit/ContractAdapters.java 274 346fc17c930bb3170dbc668f1a3f7347f01c4ad1 test/java/dev/caskeleton/adapter/outbound/notification/platform/testkit/CrossProviderContractSuiteTest.java 137 199d6ba156a53f6899cc1129db4b425a1f96d701 test/java/dev/caskeleton/adapter/outbound/notification/platform/testkit/NotificationChaosSecurityTest.java 124 cbcc07ee440a1ea6a8b64dd4766ae0ecb65e428b test/java/dev/caskeleton/adapter/outbound/notification/platform/testkit/NotificationPerformanceCertificationTest.java 141 76c5365f47107d10bf37e5c47dcb92cb1c16a82b test/java/dev/caskeleton/adapter/outbound/notification/platform/testkit/PiiLeakScanner.java 36 5c64b64a1b550ed32d64dba8827cb77e323909cf test/java/dev/caskeleton/adapter/outbound/notification/platform/testkit/ProviderAdapterContract.java 109 6a4e2bc808ea46db2b381bcd9e386121ea779229 test/java/dev/caskeleton/adapter/outbound/notification/platform/testkit/ProviderFaultHarness.java 125 8d1790dc425fc39d978cdcbe408293ca736cb20b test/java/dev/caskeleton/adapter/outbound/notification/platform/testkit/ProviderFixtures.java 127 c1000b004248ba20ad12fea292535bd604331434 test/resources/notification/templates/email/contract-v1.html 2 bea116c3fc2ce9008071ea1d49b486de0b6a5984 test/resources/notification/templates/email/contract-v1.subject.txt 1 756df6f304c23cf6a225d1184ae7dbe5032831a7 test/resources/notification/templates/email/contract-v1.text.txt 2 ce4b590959b647ef653dd931c78b1d2016b1ea89 test/resources/notification/templates/slack/contract-v1.txt 3 main_count=6 test_count=9 resource_count=4 === 8.1 도달성: 공유 provider 계약을 상속하는 어댑터 테스트 === $ grep -rn 'extends ProviderAdapterContract' adapter/outbound/notification/src/test adapter/outbound/notification/src/test/java/dev/caskeleton/adapter/outbound/notification/platform/provider/ses/SesNotificationProviderAdapterTest.java:50:class SesNotificationProviderAdapterTest extends ProviderAdapterContract { adapter/outbound/notification/src/test/java/dev/caskeleton/adapter/outbound/notification/platform/provider/twilio/TwilioSmsProviderAdapterTest.java:24:class TwilioSmsProviderAdapterTest extends ProviderAdapterContract { adapter/outbound/notification/src/test/java/dev/caskeleton/adapter/outbound/notification/platform/provider/apns/ApnsNotificationProviderAdapterTest.java:31:class ApnsNotificationProviderAdapterTest extends ProviderAdapterContract { exit=0 $ grep -n 'new [A-Za-z]*ProviderAdapter\|new [A-Za-z]*SmsProviderAdapter' adapter/outbound/notification/src/test/java/dev/caskeleton/adapter/outbound/notification/platform/testkit/ContractAdapters.java 108: new SesNotificationProviderAdapter( 148: new TwilioSmsProviderAdapter( 175: new ApnsNotificationProviderAdapter( 199: new WebPushNotificationProviderAdapter( 236: new WebhookNotificationProviderAdapter( exit=0 === 8.2 조건 형제 비교: transport 실패가 ambiguous 로 번역되는 어댑터 === $ grep -rln 'ProviderResults.fromTransport' adapter/outbound/notification/src/main adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/provider/ses/SesNotificationProviderAdapter.java adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/provider/webpush/WebPushNotificationProviderAdapter.java adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/provider/twilio/TwilioSmsProviderAdapter.java adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/provider/apns/ApnsNotificationProviderAdapter.java adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/provider/webhook/WebhookNotificationProviderAdapter.java exit=0 $ grep -n 'sendBatch\|try\|catch' adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/provider/fcm/FcmBatchCoordinator.java 83: FcmBatchResult batch = gateway.sendBatch(messages); exit=0 $ grep -rln 'AMBIGUOUS' adapter/outbound/notification/src/test/java/dev/caskeleton/adapter/outbound/notification/platform/provider adapter/outbound/notification/src/test/java/dev/caskeleton/adapter/outbound/notification/platform/provider/smtp/SmtpNotificationProviderAdapterTest.java adapter/outbound/notification/src/test/java/dev/caskeleton/adapter/outbound/notification/platform/provider/webhook/WebhookNotificationProviderAdapterTest.java exit=0 === 8.3 SPI provider 두 종의 배선 === $ grep -n 'ConditionalOnProperty' -A 4 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/slack/webhook/SlackNotificationAdapterConfig.java adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/email/google/GoogleEmailNotificationAdapterConfig.java adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/slack/webhook/SlackNotificationAdapterConfig.java:4:import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/slack/webhook/SlackNotificationAdapterConfig.java-5-import org.springframework.context.annotation.Bean; adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/slack/webhook/SlackNotificationAdapterConfig.java-6-import org.springframework.context.annotation.Configuration; adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/slack/webhook/SlackNotificationAdapterConfig.java-7- adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/slack/webhook/SlackNotificationAdapterConfig.java-8-/** -- adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/slack/webhook/SlackNotificationAdapterConfig.java:18: @ConditionalOnProperty( adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/slack/webhook/SlackNotificationAdapterConfig.java-19- name = "app.notification.slack-webhook.enabled", adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/slack/webhook/SlackNotificationAdapterConfig.java-20- havingValue = "true", adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/slack/webhook/SlackNotificationAdapterConfig.java-21- matchIfMissing = false) adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/slack/webhook/SlackNotificationAdapterConfig.java-22- public NotificationProvider slackWebhookProvider(SlackClient slackClient) { -- adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/email/google/GoogleEmailNotificationAdapterConfig.java:4:import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/email/google/GoogleEmailNotificationAdapterConfig.java-5-import org.springframework.context.annotation.Bean; adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/email/google/GoogleEmailNotificationAdapterConfig.java-6-import org.springframework.context.annotation.Configuration; adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/email/google/GoogleEmailNotificationAdapterConfig.java-7- adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/email/google/GoogleEmailNotificationAdapterConfig.java-8-/** -- adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/email/google/GoogleEmailNotificationAdapterConfig.java:18: @ConditionalOnProperty( adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/email/google/GoogleEmailNotificationAdapterConfig.java-19- name = "app.notification.google-email.enabled", adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/email/google/GoogleEmailNotificationAdapterConfig.java-20- havingValue = "true", adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/email/google/GoogleEmailNotificationAdapterConfig.java-21- matchIfMissing = false) adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/email/google/GoogleEmailNotificationAdapterConfig.java-22- public NotificationProvider googleEmailProvider(GoogleEmailClient googleEmailClient) { exit=0 === 8.4 테스트 레인 실행 === $ tail -6 /tmp/ntf_test.log > Task :adapter:outbound:notification:test BUILD SUCCESSFUL in 5s 19 actionable tasks: 1 executed, 18 up-to-date Consider enabling configuration cache to speed up this build: https://docs.gradle.org/9.0.0/userguide/configuration_cache_enabling.html GRADLE_EXIT=0 exit=0