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. * *
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. * *
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. * *
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