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>
128 lines
8.6 KiB
Plaintext
128 lines
8.6 KiB
Plaintext
Sub-scope 01 (outbound-messaging) governance + 루트 + autoconfigure + config — manifest and probes
|
|
revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5
|
|
generatedAt=2026-08-30T06:24:40+00:00
|
|
|
|
=== OWNED FILES ===
|
|
a9a027466f4efa9392aa9ec427994bd68d09d041 CLAUDE.md 76
|
|
941306ce9dcb4e3c7a456194404a9d66f524066d README.md 159
|
|
d23001caa29acef982dc0f28815f0fc5062b7e68 build.gradle 104
|
|
1126ebf2aa98feb153ee05da8837b10015487529 gradle.lockfile 152
|
|
905739a9d1bf9ba5a96ac4f9d6d7302f7d6db2ce src/main/java/dev/caskeleton/adapter/outbound/messaging/MessagingConfig.java 79
|
|
a80a60cf324fa430fff38da6cf96b794da0961f0 src/main/java/dev/caskeleton/adapter/outbound/messaging/MessagingSettings.java 20
|
|
8dd9090e6539c0e43997a2425ce820cea060bccd src/main/java/dev/caskeleton/adapter/outbound/messaging/autoconfigure/MessagingBridgeRootAutoConfiguration.java 24
|
|
597b0c54064855673332ecc8c07e912107de3a4f src/main/java/dev/caskeleton/adapter/outbound/messaging/autoconfigure/MessagingOffAutoConfigurationImportFilter.java 52
|
|
b0ea8ae1189bfc6a111b1ad66acc438b63f4df3e src/main/java/dev/caskeleton/adapter/outbound/messaging/config/CompiledMessagingDescriptor.java 204
|
|
cf646bfed662b820c418bacc58293848fa18cc34 src/main/java/dev/caskeleton/adapter/outbound/messaging/config/MessagingCapabilityCardRegistry.java 235
|
|
eb62f492984e1b5df49394eaf201243802ea4691 src/main/resources/META-INF/spring.factories 2
|
|
0d6aa7d86c134a24d68be492f3b83ff8b5f1e5be src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 1
|
|
98014fb834de5beb45aa94924119a77cdbfe9f17 src/test/java/dev/caskeleton/adapter/outbound/messaging/MessagingConfigTest.java 88
|
|
8edcd1efd2f11bd68a9f1f83a93d29ccc9a51fd0 src/test/java/dev/caskeleton/adapter/outbound/messaging/config/MessagingCapabilityCardRegistryTest.java 97
|
|
|
|
=== 8.1 활성화 게이트가 실제로 등록돼 있는가 ===
|
|
$ cat adapter/outbound/messaging/src/main/resources/META-INF/spring.factories
|
|
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
|
|
dev.caskeleton.adapter.outbound.messaging.autoconfigure.MessagingOffAutoConfigurationImportFilter
|
|
exit=0
|
|
|
|
$ cat adapter/outbound/messaging/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
|
|
dev.caskeleton.adapter.outbound.messaging.autoconfigure.MessagingBridgeRootAutoConfiguration
|
|
exit=0
|
|
|
|
=== 8.2 compiled descriptor 계열의 도달성 ===
|
|
CompiledMessagingDescriptor: leaf main 참조 0 · app-bootstrap 참조 0
|
|
MessagingCapabilityCardRegistry: leaf main 참조 4 · app-bootstrap 참조 0
|
|
ContractCatalogCompiler: leaf main 참조 1 · app-bootstrap 참조 0
|
|
DestinationBindingCompiler: leaf main 참조 1 · app-bootstrap 참조 0
|
|
ContractCatalogDigest: leaf main 참조 2 · app-bootstrap 참조 0
|
|
$ git grep -rn 'CompiledMessagingDescriptor' -- 'app-bootstrap/src' | head
|
|
exit=0
|
|
|
|
=== 8.3 broker 조립: 두 스위치의 관계 ===
|
|
$ grep -n 'ConditionalOnProperty' -r adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging
|
|
adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/kafka/KafkaAdapterConfig.java:4:import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/kafka/KafkaAdapterConfig.java:23: @ConditionalOnProperty(name = "app.messaging.broker", havingValue = "kafka")
|
|
adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/autoconfigure/MessagingBridgeRootAutoConfiguration.java:7:import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/autoconfigure/MessagingBridgeRootAutoConfiguration.java:21:@ConditionalOnProperty(prefix = "app.messaging", name = "enabled", havingValue = "true")
|
|
adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/MessagingConfig.java:21: * {@code @ConditionalOnProperty(app.messaging.broker=<id>)}-gated bean, at most one active — adding
|
|
exit=0
|
|
|
|
$ git grep -rn 'app.messaging' -- 'app-bootstrap/src/main/resources' | head
|
|
app-bootstrap/src/main/resources/application.yml:657: # MSG-024: an enabled relay with a blank app.messaging.broker fails startup
|
|
exit=0
|
|
|
|
=== 8.4 config test ===
|
|
$ git ls-files 'adapter/outbound/messaging/src/test/java/dev/caskeleton/adapter/outbound/messaging' | grep -E "^adapter/outbound/messaging/src/test/java/dev/caskeleton/adapter/outbound/messaging/[^/]+\.java$|^adapter/outbound/messaging/src/test/java/dev/caskeleton/adapter/outbound/messaging/config/" | xargs -n1 basename
|
|
MessagingConfigTest.java
|
|
MessagingCapabilityCardRegistryTest.java
|
|
exit=0
|
|
|
|
$ git grep -h ' void [a-z]' -- 'adapter/outbound/messaging/src/test/java/dev/caskeleton/adapter/outbound/messaging/config' "$(git ls-files 'adapter/outbound/messaging/src/test/java/dev/caskeleton/adapter/outbound/messaging' | grep -E \"^adapter/outbound/messaging/src/test/java/dev/caskeleton/adapter/outbound/messaging/[^/]+\.java\$\" | head -1)" | sed 's/^ *//'
|
|
fatal: empty string is not a valid pathspec. please use . instead if you meant to match all paths
|
|
exit=0
|
|
|
|
|
|
=== 8.4b 실행 probe: verifyJsonSchemaRuntimeGraph (check 에 붙어 있음) ===
|
|
$ ./gradlew :adapter:outbound:messaging:verifyJsonSchemaRuntimeGraph
|
|
FAILED — Messaging JSON runtime is missing required locked module tools.jackson.core:jackson-core:3.0.2
|
|
EXIT=1
|
|
|
|
--- 태스크가 요구하는 정확한 좌표 ---
|
|
$ sed -n '50,59p' adapter/outbound/messaging/build.gradle
|
|
[
|
|
'com.networknt:json-schema-validator:3.0.2',
|
|
'tools.jackson.core:jackson-core:3.0.2',
|
|
'tools.jackson.core:jackson-databind:3.0.2'
|
|
].each { String required ->
|
|
if (!modules.contains(required)) {
|
|
throw new GradleException(
|
|
"Messaging JSON runtime is missing required locked module ${required}")
|
|
}
|
|
}
|
|
exit=0
|
|
|
|
--- 잠긴 실제 좌표 ---
|
|
$ grep -E 'jackson|networknt|yaml' adapter/outbound/messaging/gradle.lockfile
|
|
com.fasterxml.jackson.core:jackson-annotations:2.21=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
|
com.networknt:json-schema-validator:3.0.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
|
org.springframework.boot:spring-boot-jackson:4.0.8=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
|
org.springframework.boot:spring-boot-starter-jackson-test:4.0.8=testCompileClasspath,testRuntimeClasspath
|
|
org.springframework.boot:spring-boot-starter-jackson:4.0.8=testCompileClasspath,testRuntimeClasspath
|
|
tools.jackson.core:jackson-core:3.1.5=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
|
tools.jackson.core:jackson-databind:3.1.5=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
|
tools.jackson:jackson-bom:3.1.5=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
|
exit=0
|
|
|
|
=== 8.4c 컴파일된 서술자 계열의 소비자 ===
|
|
$ git grep -l 'adapter.outbound.messaging.contract\|adapter.outbound.messaging.destination\|adapter.outbound.messaging.envelope\|adapter.outbound.messaging.config' -- . | grep -v '^adapter/outbound/messaging/'
|
|
exit=1
|
|
|
|
$ git grep -h 'import dev.caskeleton.adapter.outbound.messaging' -- 'app-bootstrap/src' | sort -u
|
|
import dev.caskeleton.adapter.outbound.messaging.MessagingConfig;
|
|
import dev.caskeleton.adapter.outbound.messaging.core.DisabledMessagePublisher;
|
|
import dev.caskeleton.adapter.outbound.messaging.core.MessageBroker;
|
|
import dev.caskeleton.adapter.outbound.messaging.core.MessagePublisher;
|
|
import dev.caskeleton.adapter.outbound.messaging.core.OutboundMessage;
|
|
import dev.caskeleton.adapter.outbound.messaging.core.OutboundMessagePublisher;
|
|
import dev.caskeleton.adapter.outbound.messaging.kafka.KafkaAdapterConfig;
|
|
import dev.caskeleton.adapter.outbound.messaging.kafka.KafkaAdapterSettings;
|
|
import dev.caskeleton.adapter.outbound.messaging.kafka.KafkaSender;
|
|
import dev.caskeleton.adapter.outbound.messaging.outbox.DisabledOutboxMessagePublisher;
|
|
import dev.caskeleton.adapter.outbound.messaging.outbox.OutboxMessagePublishAdapter;
|
|
import dev.caskeleton.adapter.outbound.messaging.outbox.Slf4jOutboxRelayFailureReportAdapter;
|
|
exit=0
|
|
|
|
$ git grep -rn 'CompiledMessagingDescriptor' -- 'adapter/outbound/messaging/src/main' | grep -v 'config/CompiledMessagingDescriptor.java'
|
|
exit=1
|
|
|
|
=== 8.4d README의 jackson-databind 주장 ===
|
|
$ sed -n '34,40p' adapter/outbound/messaging/README.md
|
|
## OutboxEnvelopeJson — 손수 짠 JSON
|
|
|
|
이 모듈은 `jackson-databind` 를 classpath 에 두지 않아(스켈레톤을 가볍게 유지) outbox envelope
|
|
직렬화는 의존성 없는 손수 짠 JSON 이다.
|
|
|
|
## MessagePublisher vs OutboxMessagePublishPort
|
|
|
|
exit=0
|
|
|