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>
239 lines
15 KiB
Plaintext
239 lines
15 KiB
Plaintext
adapter-outbound-messaging — 모듈 인벤토리
|
|
revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5
|
|
generatedAt=2026-08-30T06:23:18+00:00
|
|
|
|
=== tracked file 총계 ===
|
|
$ git ls-files 'adapter/outbound/messaging' | wc -l
|
|
69
|
|
exit=0
|
|
|
|
$ for d in $(git ls-files 'adapter/outbound/messaging/src' | sed 's|^adapter/outbound/messaging/src/||' | cut -d/ -f1 | sort -u); do n=$(git ls-files "adapter/outbound/messaging/src/$d" | wc -l); l=$(git ls-files "adapter/outbound/messaging/src/$d" | xargs wc -l 2>/dev/null | tail -1 | awk '{print $1}'); echo "$d: $n files, $l LOC"; done
|
|
main: 46 files, 4607 LOC
|
|
test: 19 files, 3670 LOC
|
|
exit=0
|
|
|
|
=== 패키지 배치 ===
|
|
$ git ls-files 'adapter/outbound/messaging/src/main' | grep '\.java$' | sed 's|.*/dev/caskeleton/||' | xargs -n1 dirname | sort | uniq -c | sort -rn
|
|
5 adapter/outbound/messaging/kafka
|
|
5 adapter/outbound/messaging/envelope
|
|
5 adapter/outbound/messaging/core
|
|
4 adapter/outbound/messaging/outbox
|
|
4 adapter/outbound/messaging/destination
|
|
3 adapter/outbound/messaging/contract
|
|
2 adapter/outbound/messaging/realtime
|
|
2 adapter/outbound/messaging/config
|
|
2 adapter/outbound/messaging/autoconfigure
|
|
2 adapter/outbound/messaging
|
|
exit=0
|
|
|
|
$ git ls-files 'adapter/outbound/messaging/src/test' | grep '\.java$' | sed 's|.*/dev/caskeleton/||' | xargs -n1 dirname | sort | uniq -c | sort -rn
|
|
3 adapter/outbound/messaging/envelope
|
|
2 adapter/outbound/messaging/qualification
|
|
2 adapter/outbound/messaging/outbox
|
|
2 adapter/outbound/messaging/kafka
|
|
2 adapter/outbound/messaging/destination
|
|
2 adapter/outbound/messaging/contract
|
|
1 adapter/outbound/messaging/core
|
|
1 adapter/outbound/messaging/config
|
|
1 adapter/outbound/messaging
|
|
exit=0
|
|
|
|
=== main 전체 (크기순) ===
|
|
$ git ls-files 'adapter/outbound/messaging/src/main' | grep '\.java$' | xargs wc -l | sort -rn
|
|
4246 total
|
|
701 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/envelope/LocalJsonSchemaRegistry.java
|
|
548 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/envelope/DeterministicEnvelopeWriter.java
|
|
274 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/contract/ContractCatalogCompiler.java
|
|
263 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/contract/CompiledIntegrationEventContract.java
|
|
248 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/destination/DestinationBindingCompiler.java
|
|
238 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/destination/DestinationBindingSettings.java
|
|
235 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/config/MessagingCapabilityCardRegistry.java
|
|
232 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/envelope/JsonSchemaIntegrationEventEncoder.java
|
|
204 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/config/CompiledMessagingDescriptor.java
|
|
132 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/destination/PartitionKeyV1.java
|
|
108 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/kafka/BrokerAddress.java
|
|
105 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/destination/CompiledPublicationBinding.java
|
|
91 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/contract/ContractCatalogDigest.java
|
|
79 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/MessagingConfig.java
|
|
78 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/realtime/RealtimeFanoutEnvelopeJson.java
|
|
70 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/outbox/OutboxEnvelopeJson.java
|
|
65 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/outbox/Slf4jOutboxRelayFailureReportAdapter.java
|
|
61 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/core/OutboundMessagePublisher.java
|
|
60 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/realtime/MessagingDurableFanoutAdapter.java
|
|
56 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/envelope/EnvelopeAdmissionLimits.java
|
|
52 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/autoconfigure/MessagingOffAutoConfigurationImportFilter.java
|
|
48 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/kafka/KafkaAdapterSettings.java
|
|
41 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/outbox/OutboxMessagePublishAdapter.java
|
|
36 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/envelope/EnvelopeHashV1.java
|
|
32 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/kafka/KafkaAdapterConfig.java
|
|
31 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/kafka/KafkaMessageBroker.java
|
|
25 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/core/OutboundMessage.java
|
|
24 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/autoconfigure/MessagingBridgeRootAutoConfiguration.java
|
|
20 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/outbox/DisabledOutboxMessagePublisher.java
|
|
20 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/core/MessageBroker.java
|
|
20 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/MessagingSettings.java
|
|
19 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/kafka/KafkaSender.java
|
|
17 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/core/DisabledMessagePublisher.java
|
|
13 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/core/MessagePublisher.java
|
|
exit=0
|
|
|
|
=== 비 Java ===
|
|
$ git ls-files 'adapter/outbound/messaging' | grep -v '\.java$'
|
|
adapter/outbound/messaging/CLAUDE.md
|
|
adapter/outbound/messaging/README.md
|
|
adapter/outbound/messaging/build.gradle
|
|
adapter/outbound/messaging/gradle.lockfile
|
|
adapter/outbound/messaging/src/main/resources/META-INF/spring.factories
|
|
adapter/outbound/messaging/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
|
|
adapter/outbound/messaging/src/main/resources/contracts/messaging/meta/draft-2020-12/authority.sha256
|
|
adapter/outbound/messaging/src/main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/meta/applicator
|
|
adapter/outbound/messaging/src/main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/meta/content
|
|
adapter/outbound/messaging/src/main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/meta/core
|
|
adapter/outbound/messaging/src/main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/meta/format-annotation
|
|
adapter/outbound/messaging/src/main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/meta/format-assertion
|
|
adapter/outbound/messaging/src/main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/meta/meta-data
|
|
adapter/outbound/messaging/src/main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/meta/unevaluated
|
|
adapter/outbound/messaging/src/main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/meta/validation
|
|
adapter/outbound/messaging/src/main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/schema
|
|
adapter/outbound/messaging/src/test/resources/contracts/messaging/test.event/v1.invalid.json
|
|
adapter/outbound/messaging/src/test/resources/contracts/messaging/test.event/v1.schema.json
|
|
adapter/outbound/messaging/src/test/resources/contracts/messaging/test.event/v1.valid.json
|
|
exit=0
|
|
|
|
=== 레지스트리 ===
|
|
$ python3 -c "
|
|
import json;d=json.load(open('config/architecture/modules.json'))
|
|
for m in d['modules']:
|
|
if m['id']=='adapter-outbound-messaging': print(json.dumps(m,ensure_ascii=False,indent=2))
|
|
"
|
|
{
|
|
"id": "adapter-outbound-messaging",
|
|
"gradle_path": ":adapter:outbound:messaging",
|
|
"source_path": "src/adapter/outbound/messaging",
|
|
"allowed_dependencies": [
|
|
"domain-core",
|
|
"application-core",
|
|
"shared-contract",
|
|
"adapter-outbound-support"
|
|
],
|
|
"runtime_memberships": [
|
|
"app-bootstrap"
|
|
]
|
|
}
|
|
exit=0
|
|
|
|
=== build.gradle ===
|
|
$ cat -n 'adapter/outbound/messaging/build.gradle'
|
|
1
|
|
2 dependencies {
|
|
3 implementation project(':application-core')
|
|
4 implementation project(':shared-contract')
|
|
5 implementation project(':adapter:outbound:support')
|
|
6
|
|
7 implementation 'org.springframework.boot:spring-boot-autoconfigure'
|
|
8 implementation 'org.springframework.boot:spring-boot-starter-json'
|
|
9 implementation('com.networknt:json-schema-validator:3.0.2') {
|
|
10 exclude group: 'com.fasterxml.jackson.dataformat', module: 'jackson-dataformat-yaml'
|
|
11 }
|
|
12 implementation 'org.slf4j:slf4j-api'
|
|
13 annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
|
|
14 }
|
|
15 tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' }
|
|
16 tasks.withType(Test).configureEach {
|
|
17 systemProperty 'messaging.commonEvidenceSchema',
|
|
18 rootProject.file('config/messaging/evidence/build-evidence-manifest-v1.schema.json')
|
|
19 .absolutePath
|
|
20 }
|
|
21
|
|
22 configurations.configureEach {
|
|
23 exclude group: 'tools.jackson.dataformat', module: 'jackson-dataformat-yaml'
|
|
24 exclude group: 'org.yaml', module: 'snakeyaml'
|
|
25 exclude group: 'org.snakeyaml', module: 'snakeyaml-engine'
|
|
26 }
|
|
27
|
|
28 tasks.register('verifyJsonSchemaRuntimeGraph') {
|
|
29 group = 'verification'
|
|
30 description = 'Verifies the closed Jackson 3 / NetworkNT graph contains no YAML or Jackson 2 runtime.'
|
|
31 doLast {
|
|
32 Set<String> modules = configurations.runtimeClasspath.incoming.resolutionResult
|
|
33 .allComponents
|
|
34 .findAll { it.moduleVersion != null }
|
|
35 .collect {
|
|
36 "${it.moduleVersion.group}:${it.moduleVersion.name}:${it.moduleVersion.version}"
|
|
37 .toString()
|
|
38 } as Set
|
|
39 List<String> forbidden = modules.findAll { String coordinate ->
|
|
40 String lowered = coordinate.toLowerCase(Locale.ROOT)
|
|
41 lowered.contains('yaml') ||
|
|
42 lowered.startsWith('org.yaml:') ||
|
|
43 lowered.startsWith('org.snakeyaml:') ||
|
|
44 lowered ==~ /com\.fasterxml\.jackson\.core:jackson-(core|databind):.*/
|
|
45 }.sort()
|
|
46 if (!forbidden.isEmpty()) {
|
|
47 throw new GradleException(
|
|
48 "Messaging JSON runtime contains forbidden Jackson 2/YAML modules: ${forbidden}")
|
|
49 }
|
|
50 [
|
|
51 'com.networknt:json-schema-validator:3.0.2',
|
|
52 'tools.jackson.core:jackson-core:3.0.2',
|
|
53 'tools.jackson.core:jackson-databind:3.0.2'
|
|
54 ].each { String required ->
|
|
55 if (!modules.contains(required)) {
|
|
56 throw new GradleException(
|
|
57 "Messaging JSON runtime is missing required locked module ${required}")
|
|
58 }
|
|
59 }
|
|
60 // Jackson 3 intentionally retains the 2.x-namespace annotations artifact. It is not a
|
|
61 // Jackson 2 databind/runtime engine and is part of the official Jackson 3 BOM graph.
|
|
62 }
|
|
63 }
|
|
64
|
|
65 tasks.named('check') {
|
|
66 dependsOn tasks.named('verifyJsonSchemaRuntimeGraph')
|
|
67 }
|
|
68
|
|
69 def messagingCompiledContractsQualification = registerStrictQualificationTest(
|
|
70 name: 'messagingCompiledContractsQualificationTest',
|
|
71 sourceSet: sourceSets.test,
|
|
72 requiredClasses: [
|
|
73 'dev.caskeleton.adapter.outbound.messaging.config.MessagingCapabilityCardRegistryTest',
|
|
74 'dev.caskeleton.adapter.outbound.messaging.contract.ContractCatalogCompilerTest',
|
|
75 'dev.caskeleton.adapter.outbound.messaging.contract.ContractCatalogDigestTest',
|
|
76 'dev.caskeleton.adapter.outbound.messaging.destination.DestinationBindingCompilerTest',
|
|
77 'dev.caskeleton.adapter.outbound.messaging.destination.PartitionKeyV1Test'
|
|
78 ],
|
|
79 junitXmlOutput: rootProject.layout.buildDirectory.dir(
|
|
80 'test-results/messaging-evidence/compiled'),
|
|
81 binaryResultsOutput: rootProject.layout.buildDirectory.dir(
|
|
82 'test-results/messaging-evidence-binary/compiled'),
|
|
83 description: 'Runs exact Messaging compiled-contract qualification tests.')
|
|
84 messagingCompiledContractsQualification.configure {
|
|
85 dependsOn ':prepareMessagingContractEvidence'
|
|
86 }
|
|
87
|
|
88 def messagingJsonSchemaV1Qualification = registerStrictQualificationTest(
|
|
89 name: 'messagingJsonSchemaV1QualificationTest',
|
|
90 sourceSet: sourceSets.test,
|
|
91 requiredClasses: [
|
|
92 'dev.caskeleton.adapter.outbound.messaging.envelope.LocalJsonSchemaRegistryTest',
|
|
93 'dev.caskeleton.adapter.outbound.messaging.envelope.JsonSchemaIntegrationEventEncoderTest',
|
|
94 'dev.caskeleton.adapter.outbound.messaging.envelope.EnvelopeAdversarialCorpusTest',
|
|
95 'dev.caskeleton.adapter.outbound.messaging.qualification.MessagingEvidenceManifestSchemaValidatorTest'
|
|
96 ],
|
|
97 junitXmlOutput: rootProject.layout.buildDirectory.dir(
|
|
98 'test-results/messaging-evidence/json-schema'),
|
|
99 binaryResultsOutput: rootProject.layout.buildDirectory.dir(
|
|
100 'test-results/messaging-evidence-binary/json-schema'),
|
|
101 description: 'Runs exact Messaging JSON Schema v1 qualification tests.')
|
|
102 messagingJsonSchemaV1Qualification.configure {
|
|
103 dependsOn ':prepareMessagingContractEvidence'
|
|
104 }
|
|
exit=0
|
|
|
|
=== leaf 밖 소비자 ===
|
|
$ git grep -l 'dev.caskeleton.adapter.outbound.messaging' -- . | grep -v '^adapter/outbound/messaging/' | sed 's|/src/.*||' | sort | uniq -c
|
|
5 app-bootstrap
|
|
1 build.gradle
|
|
exit=0
|
|
|