Sub-scope 01 (inbound-web) governance + config/core/contract/moduleboundary/autoconfigure
revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5
generatedAt=2026-08-30T07:10:55+00:00

=== OWNED FILES ===
90e57818b114cc3277e0c58e0d4eccb976afb2cd CLAUDE.md 201
f4f0854d4adc874917c733c5aff42c679325481b README.md 463
ee75f0c51d4b8625503fc0ff7f49ad8c1fbb607d build.gradle 258
6e6bc29750eff1949506a5dc1df8c32743380f30 gradle.lockfile 277
0024fa7a3cdf02c9783b6740a8c0ff1b734dbe8c src/main/java/dev/caskeleton/config/JacksonNullableConfig.java 105
41a7edb09e2a0040bfe1d5cf6fd2e38592a7c232 src/main/java/dev/caskeleton/config/OpenApiContractConfig.java 37
84920ababeb83cdfbe254745c45ea264afcfb24a src/main/java/dev/caskeleton/config/PresentationWebConfig.java 25
87d4837e94c1c7dc3e9d79a7b18f4486e9710fb5 src/main/java/dev/caskeleton/contract/WebEnumValue.java 32
ff70b7a9ac01833458721918d4f2cb76ea59d2cf src/main/java/dev/caskeleton/contract/WebWireType.java 44
3458946bc981ed7e4a0c17aa702fc9e9da4d255e src/main/java/dev/caskeleton/contract/WebWireTypeManifest.java 81
79e01fc9aa6cc24542917620fb94ad15872512e2 src/main/java/dev/caskeleton/contract/WireTypeRule.java 24
63ef452cc59c081d2450087163612271d2e264b7 src/main/java/dev/caskeleton/controller/HealthcheckController.java 18
742d75642c00db97eeb12d27641e7d60f072282c src/main/java/dev/caskeleton/core/ActorContext.java 52
43f77605463a7671a04e99ac8af02d2dfeebea04 src/main/java/dev/caskeleton/core/ApiMajorVersion.java 32
81061fc734055971a2632e6136c90b8ae9b8ce2f src/main/java/dev/caskeleton/core/ExternalRequestContext.java 65
742ea591147ab56be4ccd71bbd485f9899b481eb src/main/java/dev/caskeleton/core/TenantContext.java 50
b19770b60e88badbde6b933527c48a05095eb55f src/main/java/dev/caskeleton/core/WebOperationName.java 36
e80feb5edc21b177414826d4b784fdc01b97f33d src/main/java/dev/caskeleton/core/WebRequestContext.java 78
632c41067197433eed616cd43894e570a3396de8 src/main/java/dev/caskeleton/core/WebRequestId.java 32
be49ad426c13326382d041765c837fed0aea09c5 src/main/java/dev/caskeleton/core/WebRouteId.java 31
1ba81b37055de78dbc46200b860854c97b007bcf src/main/java/dev/caskeleton/core/WebTraceId.java 31
70b8727cc42f5d5b27c8e2025df7995f81783abc src/main/java/dev/caskeleton/moduleboundary/WebModuleBoundary.java 108
6cfcb639fc0174b53540bd7129e90061464a040d src/main/java/dev/caskeleton/moduleboundary/WebModulePurity.java 21
40e3687b86a848bab42ed5aec3b9f645e80243ce src/main/java/dev/caskeleton/moduleboundary/WebStableModule.java 539
391d8bf972c51976c059528da4aff25a599934bf src/main/java/dev/caskeleton/mvc/autoconfigure/WebMvcPlatformAutoConfiguration.java 168
e7a62fb15a3de1fd58573476ec56846e2a5c74a2 src/main/java/dev/caskeleton/mvc/autoconfigure/WebMvcPlatformSettings.java 37
87cb1ad431e8536ec28beaaf6de891deff47b311 src/main/java/dev/caskeleton/settings/CorsSettings.java 54
b4becc39e34a72771f42e9a0ad4598eeb97e83fd src/main/java/dev/caskeleton/settings/PresentationSettings.java 27
6e3a63624607b3c42a0ad94b92e73fdb8d87fded src/main/java/dev/caskeleton/settings/SecuritySettings.java 110
fca7bd62588b76d0a7bb909ef28eb750795fa5fb src/main/java/dev/caskeleton/webflux/autoconfigure/WebFluxPlatformAutoConfiguration.java 131
5a2fc1b08a347bc3e2e06363382319c2a2e49b39 src/main/java/dev/caskeleton/webflux/autoconfigure/WebFluxPlatformSettings.java 42
447164ed3148b30fd23b563db6fc17bd0ed0d29c src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 2
f5d40ef0725211ae1812234493bce907d5bc44ce src/main/resources/META-INF/web/problem-catalog.yaml 99
4b59e1d21ff12d2306cace7587a9de8ff50252cc src/main/resources/META-INF/web/wire-type-manifest.yaml 39
a889295a34227c510c1a8aba307e8c50ca159e0f src/test/java/dev/caskeleton/config/JacksonNullableConfigTest.java 40
8b137891791fe96927ad78e64b0aad7bded08bdc src/test/java/dev/caskeleton/contract/.gitkeep 1
649cc3fe219ff2fa7e57f96edaa0626879a0f5d4 src/test/java/dev/caskeleton/contract/WebWireTypeManifestTest.java 91
06441218c2f0de61cf9851cdf595ec6c7ef2880c src/test/java/dev/caskeleton/core/WebIdentifierTest.java 78
beacf79d70a763159e9b9773eef323d82b532cb8 src/test/java/dev/caskeleton/core/WebRequestContextTest.java 112
31680e537e6be10081bf3624caa9611db5d47757 src/test/java/dev/caskeleton/fixtures/badcontroller/FixtureTransactional.java 20
e25217a977f625fdb0d271b119bd83ef00b2c0d6 src/test/java/dev/caskeleton/fixtures/badcontroller/RepositoryHoldingController.java 30
715702f50bacea7318099fa63786bff4dce24762 src/test/java/dev/caskeleton/moduleboundary/WebBuildModel.java 263
e373861528986b059c4ba8b70236097a76294fad src/test/java/dev/caskeleton/moduleboundary/WebModuleBoundaryTest.java 131
e6ff0865e0c0a1c93483c784f068cf137e19bb30 src/test/java/dev/caskeleton/moduleboundary/WebSourceGraph.java 30
8b137891791fe96927ad78e64b0aad7bded08bdc src/test/java/dev/caskeleton/mvc/.gitkeep 1
07b801351e0eb27d1326aeba0ee89f5c30d357a2 src/test/java/dev/caskeleton/mvc/autoconfigure/WebMvcPlatformAutoConfigurationTest.java 112
82564f4441e1d4870e743ba3591732242b49ebef src/test/java/dev/caskeleton/settings/CorsSettingsTest.java 142
2d01c28417abd053f8f1d3c1a7edd24341cecb0b src/test/java/dev/caskeleton/settings/PresentationSettingsTest.java 57
0b10a1b13d97b9f36f60d3dd924c1ae79a89ec37 src/test/java/dev/caskeleton/settings/SecuritySettingsTest.java 95
10e95f134229b47bc82d0c39ed8be0c803456a7e src/test/java/dev/caskeleton/webflux/autoconfigure/WebFluxPlatformAutoConfigurationTest.java 112
e5fcde1a925be6e7a76bae96ad2179914e0e1b73 src/test/resources/application-web-contract.yaml 19
file_count=51

=== 8.1 도달성: 5개 커스텀 레인이 실제로 실행되는가 ===
$ grep -rn 'webCrossStackParityTest|webFluxContractTest|webJettyCompatTest|webNginxProxyTest|webAdvancedTest' --include=*.gradle --include=*.groovy . | grep -v 'adapter/inbound/web/build.gradle' | wc -l
0
exit=0

$ (cd /shared/codebase/clean-architecture-backend-template && grep -rn 'web.*Test' .github/workflows/web-pr.yml .github/workflows/web-nightly.yml .github/workflows/web-release.yml .github/workflows/web-advanced-nightly.yml .github/workflows/web-advanced-release.yml | grep ':adapter:inbound:web:')
.github/workflows/web-pr.yml:77:          :adapter:inbound:web:webCrossStackParityTest
.github/workflows/web-pr.yml:112:          :adapter:inbound:web:webNginxProxyTest
.github/workflows/web-nightly.yml:45:          :adapter:inbound:web:webJettyCompatTest
.github/workflows/web-nightly.yml:46:          :adapter:inbound:web:webFluxContractTest
.github/workflows/web-release.yml:45:          :adapter:inbound:web:webCrossStackParityTest
.github/workflows/web-release.yml:46:          :adapter:inbound:web:webNginxProxyTest
.github/workflows/web-advanced-nightly.yml:46:          :adapter:inbound:web:webAdvancedTest
.github/workflows/web-advanced-release.yml:45:          :adapter:inbound:web:webJettyCompatTest
.github/workflows/web-advanced-release.yml:46:          :adapter:inbound:web:webFluxContractTest
.github/workflows/web-advanced-release.yml:53:          :adapter:inbound:web:webAdvancedTest
exit=0

=== 8.2 조건 형제 비교: 두 자동설정의 게이트 ===
$ grep -n 'ConditionalOn\|matchIfMissing\|@Bean' adapter/inbound/web/src/main/java/dev/caskeleton/adapter/inbound/web/mvc/autoconfigure/WebMvcPlatformAutoConfiguration.java | head -20
23:import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
24:import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
25:import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
38: * <p>{@link ConditionalOnWebApplication} with {@code SERVLET} is what keeps this starter and the
42: * <p>Every bean is {@link ConditionalOnMissingBean}. An adopter that registers its own operation
47:@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
48:@ConditionalOnProperty(
52:    matchIfMissing = true)
57:  @Bean
58:  @ConditionalOnMissingBean(WebOperationCatalog.class)
64:  @Bean
65:  @ConditionalOnMissingBean
73:  @Bean
74:  @ConditionalOnMissingBean
87:  @Bean
88:  @ConditionalOnMissingBean
94:  @Bean
95:  @ConditionalOnMissingBean
101:  @Bean
102:  @ConditionalOnMissingBean
exit=0

$ grep -n 'ConditionalOn\|matchIfMissing\|@Bean' adapter/inbound/web/src/main/java/dev/caskeleton/adapter/inbound/web/webflux/autoconfigure/WebFluxPlatformAutoConfiguration.java | head -20
21:import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
22:import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
23:import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
31: * <p>{@link ConditionalOnWebApplication} with {@code REACTIVE} is the other half of the mutual
39: * forbids; duplicating six {@code @Bean} methods is the cheaper of the two costs.
42:@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
43:@ConditionalOnProperty(
47:    matchIfMissing = true)
52:  @Bean
53:  @ConditionalOnMissingBean
63:  @Bean
64:  @ConditionalOnMissingBean
65:  @ConditionalOnProperty(
69:      matchIfMissing = true)
75:  @Bean
76:  @ConditionalOnMissingBean(WebOperationCatalog.class)
82:  @Bean
83:  @ConditionalOnMissingBean
91:  @Bean
92:  @ConditionalOnMissingBean
exit=0

$ cat adapter/inbound/web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
dev.caskeleton.adapter.inbound.web.mvc.autoconfigure.WebMvcPlatformAutoConfiguration
dev.caskeleton.adapter.inbound.web.webflux.autoconfigure.WebFluxPlatformAutoConfiguration
exit=0

=== 8.3 배선: app-bootstrap 이 이 leaf 에서 가져오는 타입 ===
$ grep -rh '^import dev.caskeleton.adapter.inbound.web' app-bootstrap/src/main --include=*.java | sort -u
import dev.caskeleton.adapter.inbound.web.auth.RestrictedPathRule;
import dev.caskeleton.adapter.inbound.web.fileserver.admin.FileserverAdminController;
import dev.caskeleton.adapter.inbound.web.fileserver.config.FileserverWebProperties;
import dev.caskeleton.adapter.inbound.web.fileserver.config.TransferExecutorProperties;
import dev.caskeleton.adapter.inbound.web.fileserver.draft12.Draft12Properties;
import dev.caskeleton.adapter.inbound.web.fileserver.http.MvcConditionalRequestFactory;
import dev.caskeleton.adapter.inbound.web.fileserver.http.MvcDownloadResponseWriter;
import dev.caskeleton.adapter.inbound.web.fileserver.http.ZeroCopyEligibility;
import dev.caskeleton.adapter.inbound.web.fileserver.mapper.MultipartUploadRequestMapper;
import dev.caskeleton.adapter.inbound.web.fileserver.mapper.RawUploadRequestMapper;
import dev.caskeleton.adapter.inbound.web.fileserver.nginx.DefaultNginxInternalUriMapper;
import dev.caskeleton.adapter.inbound.web.fileserver.nginx.NginxDelegationProperties;
import dev.caskeleton.adapter.inbound.web.fileserver.nginx.NginxDownloadStrategy;
import dev.caskeleton.adapter.inbound.web.fileserver.nginx.NginxInternalUriMapper;
import dev.caskeleton.adapter.inbound.web.fileserver.problem.FileserverProblemFactory;
import dev.caskeleton.adapter.inbound.web.fileserver.security.FileserverRequestContextFactory;
import dev.caskeleton.adapter.inbound.web.fileserver.tus.TusChecksumVerifier;
import dev.caskeleton.adapter.inbound.web.fileserver.tus.TusProperties;
import dev.caskeleton.adapter.inbound.web.fileserver.tus.TusRequestParser;
exit=0

$ for a in Component RestController RestControllerAdvice Configuration AutoConfiguration; do echo "@$a files = $(grep -rl "@$a" adapter/inbound/web/src/main --include=*.java | wc -l)"; done
@Component files = 7
@RestController files = 18
@RestControllerAdvice files = 6
@Configuration files = 23
@AutoConfiguration files = 2
exit=0

=== 8.4 모듈 경계 강제 ===
$ grep -c 'WebStableModule\.' adapter/inbound/web/src/main/java/dev/caskeleton/adapter/inbound/web/moduleboundary/WebStableModule.java
0
exit=1

$ grep -c '^  [A-Z_]*(' adapter/inbound/web/src/main/java/dev/caskeleton/adapter/inbound/web/moduleboundary/WebStableModule.java
62
exit=0

$ grep -n 'void [a-z]' adapter/inbound/web/src/test/java/dev/caskeleton/adapter/inbound/web/moduleboundary/WebModuleBoundaryTest.java
34:  static void scanProductionTree() {
40:  void theScanActuallyReadsTheProductionTree() {
49:  void everyProductionPackageHasADeclaredModuleIdentity() {
57:  void everyDeclaredModuleExistsInTheProductionTree() {
65:  void everyCrossModuleImportIsADeclaredEdge() {
71:  void coreModulesStayFrameworkFree() {
79:  void anUndeclaredCrossModuleImportIsRejected(@TempDir Path tree) {
88:  void aFrameworkImportInACoreModuleIsRejected(@TempDir Path tree) {
97:  void aPackageWithNoDeclaredIdentityIsRejected(@TempDir Path tree) {
106:  void aScanThatFindsNothingFailsInsteadOfPassing(@TempDir Path tree) {
113:  private static void writeType(
exit=0

$ grep -n 'FRAMEWORK_IMPORT' -A 8 adapter/inbound/web/src/test/java/dev/caskeleton/adapter/inbound/web/moduleboundary/WebBuildModel.java | head -14
44:  public static final Pattern FRAMEWORK_IMPORT =
45-      Pattern.compile(
46-          // `tools.jackson` is Jackson 3 and `com.fasterxml` is Jackson 2. Both are listed because
47-          // this repository runs on Spring 7, whose message converters take Jackson 3 — so a CORE
48-          // module could have imported a mapper without this detector noticing, which is a hole in
49-          // exactly the check that is supposed to have none.
50-          "^(org\\.springframework|jakarta|reactor|io\\.micrometer|com\\.fasterxml"
51-              + "|tools\\.jackson|org\\.slf4j|io\\.swagger)\\.");
52-
--
114:        } else if (FRAMEWORK_IMPORT.matcher(imported).find()) {
115-          frameworkImports.get(moduleId).add(imported);
116-        }
117-      }
exit=0

=== 8.4b CORS 소비처 ===
$ grep -n 'setAllowedOrigin' adapter/inbound/web/src/main/java/dev/caskeleton/adapter/inbound/web/auth/SecurityConfig.java
151:    cfg.setAllowedOrigins(corsSettings.allowedOrigins());
exit=0

