Files
document-haness/docs/clean-architecture-backend-template/final/evidence/raw/181-notification-module-inventory.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

191 lines
12 KiB
Plaintext

adapter-outbound-notification — 모듈 인벤토리
revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5
generatedAt=2026-08-30T06:35:30+00:00
=== tracked file 총계 ===
$ git ls-files 'adapter/outbound/notification' | wc -l
240
exit=0
$ for d in $(git ls-files 'adapter/outbound/notification/src' | sed 's|^adapter/outbound/notification/src/||' | cut -d/ -f1 | sort -u); do n=$(git ls-files "adapter/outbound/notification/src/$d" | wc -l); l=$(git ls-files "adapter/outbound/notification/src/$d" | xargs wc -l 2>/dev/null | tail -1 | awk '{print $1}'); echo "$d: $n files, $l LOC"; done
main: 171 files, 14695 LOC
test: 65 files, 10045 LOC
exit=0
=== main 패키지 배치 ===
$ git ls-files 'adapter/outbound/notification/src/main' | grep '\.java$' | sed 's|.*/dev/caskeleton/||' | xargs -n1 dirname | sort | uniq -c | sort -rn
23 adapter/outbound/notification/platform/dispatch
15 adapter/outbound/notification/provider
14 adapter/outbound/notification/platform/template
12 adapter/outbound/notification/catalog
11 adapter/outbound/notification/platform/provider/ses
11 adapter/outbound/notification/platform/autoconfigure
10 adapter/outbound/notification/platform/provider/webpush
10 adapter/outbound/notification/platform/provider/fcm
9 adapter/outbound/notification/platform/provider/twilio
7 adapter/outbound/notification/template
7 adapter/outbound/notification/platform/security
7 adapter/outbound/notification/platform/provider/smtp
6 adapter/outbound/notification/platform/provider/http
5 adapter/outbound/notification/platform/observation
4 adapter/outbound/notification/platform/provider/apns
3 adapter/outbound/notification/slack/webhook
3 adapter/outbound/notification/platform/reactor
3 adapter/outbound/notification/platform/provider/webhook
3 adapter/outbound/notification/platform/provider
3 adapter/outbound/notification/email/google
3 adapter/outbound/notification/core
2 adapter/outbound/notification
exit=0
=== test 패키지 배치 ===
$ git ls-files 'adapter/outbound/notification/src/test' | grep '\.java$' | sed 's|.*/dev/caskeleton/||' | xargs -n1 dirname | sort | uniq -c | sort -rn
9 adapter/outbound/notification/platform/testkit
7 adapter/outbound/notification/platform/security
7 adapter/outbound/notification/platform/dispatch
5 adapter/outbound/notification/provider
5 adapter/outbound/notification/platform/autoconfigure
4 adapter/outbound/notification/platform/template
3 adapter/outbound/notification/platform/provider/twilio
3 adapter/outbound/notification/platform/provider/http
3 adapter/outbound/notification/catalog
2 adapter/outbound/notification/platform/provider/webpush
2 adapter/outbound/notification/platform/provider/smtp
2 adapter/outbound/notification/platform/provider/ses
2 adapter/outbound/notification/platform/provider/fcm
2 adapter/outbound/notification/platform/provider
2 adapter/outbound/notification/core
1 adapter/outbound/notification/template
1 adapter/outbound/notification/platform/provider/webhook
1 adapter/outbound/notification/platform/provider/apns
exit=0
=== main 상위 25 ===
$ git ls-files 'adapter/outbound/notification/src/main' | grep '\.java$' | xargs wc -l | sort -rn | head -26
14695 total
516 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/catalog/NotificationBindingCompiler.java
473 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/template/LocalEmailRenderer.java
363 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/provider/NotificationProviderAttemptAdapter.java
276 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/dispatch/ProviderRuntime.java
258 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/provider/webhook/WebhookNotificationProviderAdapter.java
253 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/template/NotificationTemplateCatalog.java
239 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/autoconfigure/NotificationProviderAssembly.java
228 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/security/ProviderCredentialManager.java
220 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/security/AesGcmContactPointProtector.java
211 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/autoconfigure/NotificationSmtpProviderConfig.java
209 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/provider/ses/SesRequestMapper.java
197 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/dispatch/NotificationSchedulerWorker.java
193 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/provider/webpush/Rfc8291Aes128GcmEncryptor.java
190 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/autoconfigure/NotificationPlatformSettings.java
185 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/template/CanonicalNotificationRenderer.java
175 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/template/NotificationTemplateManifest.java
169 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/provider/ses/SesNotificationProviderAdapter.java
164 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/autoconfigure/SmtpProviderRuntimeAssembler.java
163 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/provider/NotificationAdmissionReadinessAdapter.java
162 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/template/ThymeleafStringTemplateEngine.java
159 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/security/AesGcmNotificationPayloadProtection.java
151 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/provider/NotificationReconciliationAdapter.java
151 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/catalog/NotificationCutoverRouteCatalog.java
151 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/catalog/CompiledNotificationBinding.java
147 adapter/outbound/notification/src/main/java/dev/caskeleton/adapter/outbound/notification/platform/provider/smtp/SmtpMimeMessageFactory.java
exit=0
=== 비 Java ===
$ git ls-files 'adapter/outbound/notification' | grep -v '\.java$'
adapter/outbound/notification/CLAUDE.md
adapter/outbound/notification/README.md
adapter/outbound/notification/build.gradle
adapter/outbound/notification/gradle.lockfile
adapter/outbound/notification/src/test/resources/notification/templates/email/contract-v1.html
adapter/outbound/notification/src/test/resources/notification/templates/email/contract-v1.subject.txt
adapter/outbound/notification/src/test/resources/notification/templates/email/contract-v1.text.txt
adapter/outbound/notification/src/test/resources/notification/templates/slack/contract-v1.txt
exit=0
=== 레지스트리 ===
$ python3 -c "
import json;d=json.load(open('config/architecture/modules.json'))
for m in d['modules']:
if m['id']=='adapter-outbound-notification': print(json.dumps(m,ensure_ascii=False,indent=2))
"
{
"id": "adapter-outbound-notification",
"gradle_path": ":adapter:outbound:notification",
"source_path": "src/adapter/outbound/notification",
"allowed_dependencies": [
"domain-core",
"application-core",
"shared-contract",
"adapter-outbound-support"
],
"runtime_memberships": [
"app-bootstrap"
]
}
exit=0
=== build.gradle ===
$ cat -n 'adapter/outbound/notification/build.gradle'
1 dependencies {
2 implementation project(':application-core')
3 implementation project(':shared-contract')
4 implementation project(':adapter:outbound:support')
5
6 implementation 'org.springframework.boot:spring-boot-autoconfigure'
7 implementation 'org.springframework:spring-web' // Slack webhook client (RestClient)
8 implementation 'org.slf4j:slf4j-api'
9
10 // Notification Delivery Platform.
11 // - mail: the SMTP provider adapter is built on JavaMailSender/MimeMessageHelper, which is where
12 // multipart/alternative, inline resources and header validation already live. Rebuilding MIME
13 // by hand to avoid one dependency would be the more dangerous choice.
14 // - jackson-databind: provider payloads, callback bodies and the canonical variables payload are
15 // JSON. It stays inside this adapter; application-core never sees a JSON type.
16 // - reactor-core: only the optional Reactor facade uses it. The core async type stays
17 // CompletionStage, so nothing else on this classpath depends on Reactor.
18 implementation 'org.springframework.boot:spring-boot-starter-mail'
19 implementation 'org.springframework.boot:spring-boot-starter-json'
20 implementation 'io.projectreactor:reactor-core'
21 // JSON Schema 2020-12 validation of template variables, using the same validator and version the
22 // messaging adapter already depends on rather than a second implementation of the same spec.
23 //
24 // Jackson's YAML dataformat is excluded because schemas arrive as JSON strings and a second
25 // parser for a format this leaf never reads is surface for nothing. It does not remove YAML from
26 // the runtime — org.yaml:snakeyaml is on this classpath via spring-boot-starter, which is how
27 // Spring Boot reads application.yml. The comment here used to claim the stronger outcome, and
28 // the resolved graph had said otherwise for as long as it stood; dependencyPolicy below now
29 // states the claim the build can check.
30 // Thymeleaf is the reference HTML renderer, added as the engine only — not the Spring
31 // starter, which would drag a view resolver and a servlet integration onto an outbound
32 // adapter that renders strings and never serves a request.
33 implementation 'org.thymeleaf:thymeleaf'
34
35 implementation('com.networknt:json-schema-validator:3.0.2') {
36 exclude group: 'tools.jackson.dataformat', module: 'jackson-dataformat-yaml'
37 exclude group: 'com.fasterxml.jackson.dataformat', module: 'jackson-dataformat-yaml'
38 }
39
40 annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
41
42 testImplementation 'io.projectreactor:reactor-test'
43 }
44 tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' }
45
46 // The exclusion above, stated as something the build verifies rather than something a comment
47 // asserts. verifyDependencyPolicy resolves runtimeClasspath and fails if the coordinate is present.
48 dependencyPolicy {
49 absent 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml',
50 because: 'schemas arrive as JSON strings; a second YAML parser is surface for a format ' +
51 'this leaf never reads'
52 absent 'tools.jackson.dataformat:jackson-dataformat-yaml',
53 because: 'the Jackson 3 coordinate of the same parser, excluded for the same reason'
54 }
exit=0
=== leaf 밖 소비자 ===
$ git grep -l 'dev.caskeleton.adapter.outbound.notification' -- . | grep -v '^adapter/outbound/notification/' | sed 's|/src/.*||' | sort | uniq -c
21 app-bootstrap
1 gradle/notification-api-surface.gradle
exit=0