Files
document-haness/docs/clean-architecture-backend-template/final/evidence/raw/319-kafka-assembly-census.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

93 lines
6.1 KiB
Plaintext

# 주제: messaging-kafka 34개 main 타입 중 무엇이 조립되고 무엇이 조립되지 않는가
# revision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
# command: git grep -nE "new ([a-zA-Z0-9_.]+\.)?<T>\s*\(" -- src (T별 집계)
KafkaMessagingTransport src/main=1 src/test+jmh=12 <- 스타터가 3-arg 로 생성
KafkaSecurityConfigurer src/main=1 src/test+jmh=2
KafkaProfileValidator src/main=1 src/test+jmh=1
KafkaTransactionProfileValidator src/main=1 src/test+jmh=0
KafkaPublishFailureClassifier src/main=2 src/test+jmh=1
KafkaPublishMapper src/main=2 src/test+jmh=0 (transport/transactional 내부)
KafkaHeaderMapper src/main=2 src/test+jmh=4 (두 매퍼 내부)
KafkaTransactionalPublisher src/main=1 src/test+jmh=1 (자기 정적 팩토리)
KafkaDeliveryMapper src/main=1 src/test+jmh=1 (registrar 내부)
KafkaSettlementQueue src/main=1 src/test+jmh=0 (registrar 내부)
KafkaPartitionRetryScheduler src/main=1 src/test+jmh=0 (registrar 내부)
PartitionWorkCoordinator src/main=1 src/test+jmh=6 (registrar 내부)
ContiguousPartitionOffsetTracker src/main=1 src/test+jmh=2 (registrar 내부)
KafkaRetryMetadataMapper src/main=2 src/test+jmh=3
-----
KafkaConsumerRegistrar src/main=0 src/test+jmh=6 <- 테스트에서만
KafkaOffsetResetExecutor src/main=0 src/test+jmh=2 <- 테스트에서만
KafkaReplayPlanner src/main=0 src/test+jmh=1 <- 테스트에서만
SpringKafkaTransactionalProcessor src/main=0 src/test+jmh=1 <- 테스트에서만
-----
KafkaBatchConsumerRegistrar src/main=0 src/test+jmh=0 <- **어디에서도 생성되지 않음**
KafkaRetryExecutor src/main=0 src/test+jmh=0 <- **어디에서도**
KafkaRetryTopicPublisher src/main=0 src/test+jmh=0 <- **어디에서도**
KafkaDeadLetterPublisher src/main=0 src/test+jmh=0 <- **어디에서도**
KafkaReplayCapability src/main=0 src/test+jmh=0 <- **어디에서도**
KafkaTopologyInspector src/main=0 src/test+jmh=0 <- 인터페이스, 구현 0
# src/main 에서 이 leaf 의 타입을 만드는 외부 지점 (전수)
KafkaMessagingAutoConfiguration.java:42 new KafkaProfileValidator()
KafkaMessagingAutoConfiguration.java:75 new KafkaTransactionProfileValidator()
KafkaMessagingAutoConfiguration.java:86 new KafkaPublishFailureClassifier()
KafkaMessagingAutoConfiguration.java:111 new KafkaSecurityConfigurer(credentials, tlsPolicy)
KafkaMessagingAutoConfiguration.java:168 new KafkaMessagingTransport("kafka", 1L, producer)
MessagingConfigurationCompiler.java:116 new KafkaBrokerProfile(...)
# => 외부에서 생성되는 것은 검증기 3 + 보안 설정기 1 + 전송 1 + 프로필 1 = 6개뿐이다.
# ---- 소비 불가가 타입으로 표현되어 있다 ----
# KafkaMessagingTransport.java:74-92 (스타터가 쓰는 3-arg 생성자)
# public KafkaMessagingTransport(String brokerName, long generation, Producer<byte[],byte[]> producer) {
# this(brokerName, generation, producer,
# spec -> {
# throw new MessagingCapabilityUnavailableException(
# "KAFKA_CONSUMER_NOT_CONFIGURED",
# "this Kafka transport was created without a consumer factory");
# });
# }
# KafkaMessagingTransport.java:159-167
# public TransportConsumerRegistration register(TransportConsumerSpec spec) {
# ...
# return consumerFactory.apply(spec); // 3-arg 경로에서는 항상 throw
# }
# => 부팅된 애플리케이션에서 transport.register(...) 는 KAFKA_CONSUMER_NOT_CONFIGURED 로 실패한다.
# 조용히 아무 일도 안 하는 것이 아니라 이름 붙은 오류로 거절한다.
# "소비 경로가 배선되지 않았다"(EVD-316)가 이 leaf 에서 타입으로 표현된 형태다.
# ---- 토폴로지 인스펙터: 두 인터페이스, 구현 0 ----
# command: git grep -n "BrokerTopologyInspector" -- src
# admin-runtime/BrokerTopologyInspector.java:14 (선언)
# CompositeTopologyValidator:21,29 / DefaultMessagingAdminService:54,80 (소비)
# MessagingAdminAutoConfiguration:5,81,83 (@ConditionalOnBean)
# TopologyValidatorTest.java:133 new BrokerTopologyInspector() { ... } <- 유일한 구현, 테스트 익명클래스
# command: git grep -n "KafkaTopologyInspector" -- src
# messaging-kafka/KafkaTopologyInspector.java:13 (선언) <- 그 외 등장 0
#
# 두 인터페이스의 모양이 다르다:
# BrokerTopologyInspector : Optional<DestinationTopology> describe(String), String topologyVersion()
# KafkaTopologyInspector : int partitionCount(String), short replicationFactor(String),
# Map<String,String> configuration(String), List<String> topics()
#
# 실제로 브로커 토폴로지를 읽는 코드는 컨테이너 IT 안의 private static 헬퍼다:
# KafkaTopologyValidationIT.java:42-61
# private static DestinationTopology describe(String topic) {
# try (Admin admin = KafkaContainerFixture.admin()) {
# Map<String, TopicDescription> described = admin.describeTopics(List.of(topic))...;
# ...
# return new DestinationTopology(topic, description.partitions().size(), replication, Map.of(), true);
# } catch (...) { return DestinationTopology.absent(topic); }
# }
# => 어느 인터페이스도 구현하지 않는다.
#
# 판정: analysis/messaging/messaging-admin-api.md §17 첫 항목("BLOCKING 이면 기동 실패"가 미배선)을
# 고치려 해도 **줄 인스펙터가 없다.** Kafka leaf 는 그 자리에 다른 모양의 인터페이스를
# 선언만 해 두었고, 실제로 동작하는 20줄은 테스트의 private 메서드로만 존재한다.
# ---- 이 leaf 를 import 하는 외부 파일은 3개뿐 ----
# messaging-spring-boot-starter/.../CompiledMessagingConfiguration.java
# messaging-spring-boot-starter/.../KafkaMessagingAutoConfiguration.java
# messaging-spring-boot-starter/.../MessagingConfigurationCompiler.java