Files
document-haness/docs/clean-architecture-backend-template/final/evidence/raw/017-adapter-outbound-support-conditional-wiring.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

118 lines
7.3 KiB
Plaintext

Command: printf '%s\n' '--- support config annotations ---'; grep -n -E '@Configuration|@Bean|@Conditional' src/adapter/outbound/support/src/main/java/dev/caskeleton/adapter/outbound/support/OutboundSupportConfig.java; printf '%s\n' '--- app component scan/exclusions ---'; sed -n '35,125p' src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/CaSkeletonApplication.java; printf '%s\n' '--- registry support membership/consumers ---'; python3 - <<'PY'
import json
mods=json.load(open('src/config/architecture/modules.json'))['modules']
for m in mods:
if m['id']=='adapter-outbound-support' or 'adapter-outbound-support' in m.get('allowed_dependencies',[]):
print(m['id'],m['gradle_path'],'runtime=',m.get('runtime_memberships'),'allows=',m.get('allowed_dependencies'))
PY
printf '%s\n' '--- explicit support config references ---'; git grep -n -w 'OutboundSupportConfig' -- 'src/**' ':!src/adapter/outbound/support/**'; echo "git-grep-exit=$?"
Working directory: /shared/codebase/clean-architecture-backend-template
Executed at: 2026-08-29T07:19:26Z
Source revision: a24ece9cf797f7ea647e33bf846b115208ed1ba5
Observation boundary: Shows support configuration annotations, composition-root component-scan ownership, optional-adapter config references, and registry runtime membership; it does not boot the application.
--- stdout/stderr ---
--- support config annotations ---
10: * {@code @ConditionalOnMissingBean} lets a fork override it.
12:@Configuration
15: @Bean
16: @ConditionalOnMissingBean
--- app component scan/exclusions ---
* component scanner discover each child configuration on its own and assemble the capability
* whatever that switch said. Registering them as auto-configuration instead makes "off" a
* structural fact rather than a condition every future bean has to remember to repeat.
*/
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
basePackages = {
"dev.caskeleton.bootstrap",
"dev.caskeleton.adapter",
"dev.caskeleton.application",
"dev.caskeleton.domain",
"dev.caskeleton.shared"
},
excludeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@ComponentScan.Filter(
type = FilterType.CUSTOM,
classes = AutoConfigurationExcludeFilter.class),
@ComponentScan.Filter(
type = FilterType.REGEX,
pattern = CaSkeletonApplication.AUTO_CONFIGURED_PACKAGES)
})
@ConfigurationPropertiesScan(
basePackages = {
"dev.caskeleton.bootstrap.async",
"dev.caskeleton.bootstrap.autoconfigure.fileserver",
"dev.caskeleton.bootstrap.autoconfigure.httpclient",
"dev.caskeleton.bootstrap.concurrency",
"dev.caskeleton.bootstrap.idempotency",
"dev.caskeleton.bootstrap.outbox",
"dev.caskeleton.bootstrap.redis",
"dev.caskeleton.bootstrap.runtime",
"dev.caskeleton.bootstrap.security",
"dev.caskeleton.bootstrap.settings",
"dev.caskeleton.bootstrap.tracing",
"dev.caskeleton.adapter.inbound.grpc",
"dev.caskeleton.adapter.inbound.web",
"dev.caskeleton.adapter.inbound.websocket",
"dev.caskeleton.adapter.outbound.cache.redis",
"dev.caskeleton.adapter.outbound.fileserver",
"dev.caskeleton.adapter.outbound.objectstorage",
"dev.caskeleton.application",
"dev.caskeleton.domain",
"dev.caskeleton.shared"
})
public class CaSkeletonApplication {
/**
* Packages owned by an auto-configuration entry rather than by the component scan.
*
* <p>A package prefix rather than a class list: a new configuration added to an optional
* capability must not become active merely because nobody remembered to exclude it.
*
* <p>The Fileserver admin package is here for a different reason: those routes belong to the
* management context, and a component scan that also found them would publish the management
* plane on the public connector — the exposure the separate context exists to remove.
*
* <p>The web platform's error, budget and operation packages are here for a third reason. Their
* advices and controllers need beans that only exist when the corresponding platform
* auto-configuration is active, and a component scan finds them regardless — so an all-off or
* partially configured deployment failed to start on an unsatisfied dependency rather than simply
* not installing the control. Ownership by auto-configuration is what ties a control's presence
* to its dependency's.
*/
static final String AUTO_CONFIGURED_PACKAGES =
"dev\\.caskeleton\\.bootstrap\\.autoconfigure\\..*"
+ "|dev\\.caskeleton\\.bootstrap\\.notification\\..*"
+ "|dev\\.caskeleton\\.adapter\\.inbound\\.web\\.fileserver\\.admin\\..*"
+ "|dev\\.caskeleton\\.adapter\\.outbound\\.mongo\\..*"
+ "|dev\\.caskeleton\\.adapter\\.outbound\\.messaging\\..*"
+ "|dev\\.caskeleton\\.adapter\\.outbound\\.notification\\..*"
+ "|dev\\.caskeleton\\.adapter\\.outbound\\.persistence\\..*"
+ "|dev\\.caskeleton\\.adapter\\.inbound\\.graphql\\..*"
+ "|dev\\.caskeleton\\.adapter\\.inbound\\.web\\.mvc\\.error\\..*"
+ "|dev\\.caskeleton\\.adapter\\.inbound\\.web\\.mvc\\.budget\\..*"
+ "|dev\\.caskeleton\\.adapter\\.inbound\\.web\\.mvc\\.operation\\..*"
+ "|dev\\.caskeleton\\.adapter\\.inbound\\.web\\.webflux\\.error\\..*"
+ "|dev\\.caskeleton\\.adapter\\.inbound\\.web\\.webflux\\.operation\\..*"
+ "|dev\\.caskeleton\\.messaging\\..*";
public static void main(String[] args) {
SpringApplication.run(CaSkeletonApplication.class, args);
}
}
--- registry support membership/consumers ---
adapter-outbound-support :adapter:outbound:support runtime= ['app-bootstrap'] allows= ['domain-core', 'application-core', 'shared-contract']
adapter-outbound-cache-redis :adapter:outbound:cache-redis runtime= ['app-bootstrap'] allows= ['domain-core', 'application-core', 'shared-contract', 'adapter-outbound-support']
adapter-outbound-httpclient :adapter:outbound:httpclient runtime= ['app-bootstrap'] allows= ['domain-core', 'application-core', 'shared-contract', 'adapter-outbound-support']
adapter-outbound-messaging :adapter:outbound:messaging runtime= ['app-bootstrap'] allows= ['domain-core', 'application-core', 'shared-contract', 'adapter-outbound-support']
adapter-outbound-notification :adapter:outbound:notification runtime= ['app-bootstrap'] allows= ['domain-core', 'application-core', 'shared-contract', 'adapter-outbound-support']
app-bootstrap :app-bootstrap runtime= ['app-bootstrap'] allows= ['domain-core', 'application-core', 'adapter-outbound-persistence-jpa', 'adapter-outbound-support', 'adapter-outbound-messaging', 'adapter-outbound-cache-redis', 'adapter-outbound-notification', 'adapter-outbound-fileserver', 'adapter-outbound-httpclient', 'adapter-outbound-identifier', 'adapter-inbound-web', 'shared-contract', 'adapter-outbound-persistence-mongo', 'adapter-inbound-graphql', 'messaging-spring-boot-starter']
--- explicit support config references ---
src/app-bootstrap/src/test/java/dev/caskeleton/adapter/outbound/OptionalAdapterBeanGatingTest.java:27:import dev.caskeleton.adapter.outbound.support.OutboundSupportConfig;
src/app-bootstrap/src/test/java/dev/caskeleton/adapter/outbound/OptionalAdapterBeanGatingTest.java:66: OutboundSupportConfig.class,
git-grep-exit=0
Exit code: 0