Files
document-haness/docs/clean-architecture-backend-template/final/evidence/raw/187-notification-spi-testkit-probes.txt
T
DongHyeonkaandClaude Opus 5 b2963105a8 docs(keycloak-session-store): import the session-storage lab as a new project
The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.

Follows the import procedure in README.md.

  source/     the originating repository verbatim — 78 documents, 28 SVGs,
              8 manifests, plus .source-revision recording the commit
  final/      the SSOT
    document.md   729 lines written from the 29 experiment documents, not
                  concatenated: what was predicted, what was measured, and
                  where the measurement itself was wrong
    evidence/raw    125 outputs, flattened to <experiment>__<file> because
                    the originals collided (01-baseline.txt appeared three
                    times) and the audit only globs the top level
    evidence/meta   one per raw file; command and exitCode are null and the
                    README says why rather than inventing them
    evidence/browser  22 captures
    assets/       three diagrams through techviz
    .techviz/     their VizSpecs

A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.

Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.

verify-pipeline.py passes. audit-records.py reports no issues.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 22:51:59 +09:00

97 lines
10 KiB
Plaintext

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