Sub-scope 01 (inbound-graphql) governance + autoconfigure + moduleboundary + architecture + api revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5 generatedAt=2026-08-30T08:27:13+00:00 === OWNED FILES === 434aeacc2a92ec3f812fd77999192c4410713c8a CLAUDE.md 224 7e3fc1f6019455df9a7a71ebe9ba67182b5cb0fa README.md 224 42cebcf264bcbd74dd6b843a0ea54b6113446b09 build.gradle 174 74f612c854c95a48370a3608825866d192098b1b gradle.lockfile 178 4c01cbfdef67b3705c97570c4c36d762786dd9f1 src/main/java/dev/caskeleton/HealthGraphqlController.java 25 f2c0492b134eab75b7da6067987a10cbee2a88c8 src/main/java/dev/caskeleton/api/GraphQlClientProfile.java 27 86602c8c38d90d35f8e18374efb87eb7de8e6af6 src/main/java/dev/caskeleton/api/GraphQlClientProfileName.java 50 061a5a56bb501104162e08369f27813b395e8f87 src/main/java/dev/caskeleton/api/GraphQlOperationId.java 24 25fbe6e3f919e5635b0173c32202e2a4ec4a38a6 src/main/java/dev/caskeleton/api/GraphQlOperationName.java 43 f9c4a18019af5ca8400bfea60815afc1aa923a64 src/main/java/dev/caskeleton/api/GraphQlSchemaCoordinate.java 61 d1abaaaedf7c0bfb8ae2e6541a82267eec218c61 src/main/java/dev/caskeleton/architecture/GraphQlAsyncReturnShape.java 72 47ba73dfbd1e5c732cd68006bdb53085415b9f4d src/main/java/dev/caskeleton/architecture/GraphQlControllerContractException.java 40 419ab3992b89c8cc5cbb802446b7b5f91998b36a src/main/java/dev/caskeleton/architecture/GraphQlControllerInspector.java 109 770738711cad63f25c19ca686717f36018e0a5b8 src/main/java/dev/caskeleton/architecture/GraphQlControllerTransactionRule.java 81 647166f486151c90a602dd54a571ebb46f3554ab src/main/java/dev/caskeleton/architecture/GraphQlInputTypePolicy.java 44 8986f2fb27b1ff10c3524710c5f863dffd8e450d src/main/java/dev/caskeleton/architecture/GraphQlResolverBoundaryRules.java 313 d4f7e591ad688299691fb26650c4e1c57d8148ec src/main/java/dev/caskeleton/architecture/GraphQlReturnTypePolicy.java 111 fc934d492e2ef4141a0ed46f8db15d96b0bdcb6b src/main/java/dev/caskeleton/architecture/GraphQlTransportTypeRules.java 87 a32cb82a95758cdafa33be8df27dd28a959ecb5d src/main/java/dev/caskeleton/architecture/GraphQlTypeGraph.java 112 346dc5a32d924565420ab6b61ed20595985522d2 src/main/java/dev/caskeleton/autoconfigure/GraphQlActivationEnvironmentPostProcessor.java 75 afae197bac923e62990079f5cd69853a4dde1891 src/main/java/dev/caskeleton/autoconfigure/GraphQlDeploymentMode.java 72 97477157ffdc72e2b41cf964e65a7ff6c74cb709 src/main/java/dev/caskeleton/autoconfigure/GraphQlOffAutoConfigurationImportFilter.java 60 2ad7108f3a7da65ad80031a3ad84651c271bc6fb src/main/java/dev/caskeleton/autoconfigure/GraphQlPlatformActuatorEndpoint.java 71 a3a2824a48c2f040bf58c3fe2bc10dfcda010b93 src/main/java/dev/caskeleton/autoconfigure/GraphQlPlatformAutoConfiguration.java 704 9f9aff73688ee5e8305dee46eb4c5a138320df65 src/main/java/dev/caskeleton/autoconfigure/GraphQlPlatformConfigurationException.java 31 8c0237214cff7d1a49aa664f0baf0e56f409dc1b src/main/java/dev/caskeleton/autoconfigure/GraphQlPlatformConfigurationReport.java 55 3cbba44d38253207d5e20ed839ef4de791b4bc81 src/main/java/dev/caskeleton/autoconfigure/GraphQlPlatformRuntime.java 43 dd6d37a76d8ecbce963f6d33ef08d8b000b98391 src/main/java/dev/caskeleton/autoconfigure/GraphQlPlatformSettings.java 307 bf93f72b05eb35e7c6bb338682f61168fa459683 src/main/java/dev/caskeleton/autoconfigure/GraphQlPlatformStartupValidator.java 185 55b71a3ccc5cbf053e58ca0316c9d35a5546b120 src/main/java/dev/caskeleton/autoconfigure/GraphQlRetiredSafetyAxis.java 62 a012a182cbf836c62382852f4aba7da5a23dbd6d src/main/java/dev/caskeleton/autoconfigure/GraphQlRootAutoConfiguration.java 33 2281a8283a6a70bfcf5bd5272630ec37a6ca5c0d src/main/java/dev/caskeleton/autoconfigure/GraphQlRuntimeTransport.java 44 434b330b37a4a8f0de417237985dd2cd42b311d8 src/main/java/dev/caskeleton/moduleboundary/GraphQlAdvancedModule.java 167 8d7b467dc93277674057822b4b9be70a1d24b9a7 src/main/java/dev/caskeleton/moduleboundary/GraphQlModuleBoundary.java 126 e86b13a08b20fa55da21c76675294c665207db53 src/main/java/dev/caskeleton/moduleboundary/GraphQlModulePurity.java 19 9a9c652043da9eb128ecf9c39d093ab9e325dbdd src/main/java/dev/caskeleton/moduleboundary/GraphQlStableModule.java 225 bc2a2210fa31d43cf623ed3c40f1b3e82f02ec1a src/main/resources/META-INF/spring.factories 4 0a4f208e8a07fb853e9e798007a3fed85c78b1ad src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 1 c8093c523d6126bc7f77bdf31e46a7b7f0ed3d26 src/main/resources/graphql/skeleton.graphqls 10 de73f5a1d2eae599e16cbd6e3315abb77297be95 src/test/java/dev/caskeleton/api/GraphQlIdentifiersTest.java 76 d6e0f92cccd62bcab06ea64790db57ab741c20ee src/test/java/dev/caskeleton/architecture/GraphQlControllerInspectorTest.java 117 62b18a7b5fc5f6ae49df4d03876ca37d6c54cc82 src/test/java/dev/caskeleton/architecture/GraphQlGeneratedResolverBoundaryTest.java 114 e5adb01dd691ef265eb0f832dc06bc9eae21a09c src/test/java/dev/caskeleton/architecture/GraphQlResolverBoundaryRulesTest.java 92 68b6e28036582d7c452cd84ed8cfd8bcb873196a src/test/java/dev/caskeleton/architecture/GraphQlResolverGenericBoundaryTest.java 189 8bb61d7384f83054472b5a0d3d68b78f6bfa3aa3 src/test/java/dev/caskeleton/architecture/fixture/compliant/FindOrderUseCase.java 12 a38b669abca65734c5c09af9e836b538119c7b0e src/test/java/dev/caskeleton/architecture/fixture/compliant/OrderGraphQlController.java 31 be295c28ebde5dc0e1469d5386247c1b489907c2 src/test/java/dev/caskeleton/architecture/fixture/compliant/OrderView.java 9 b8584addc14a314faffec67f0a44bb6b6d1c8d0a src/test/java/dev/caskeleton/architecture/fixture/violating/LeakyGraphQlController.java 33 38bac70c896e5248fdde731a32b91e856c08d68b src/test/java/dev/caskeleton/architecture/fixture/violating/OrderRepository.java 12 f91fec9cc5d1b03a5a67701dababbc386519f2a6 src/test/java/dev/caskeleton/architecture/fixture/violating/Transactional.java 17 9a96cc94002d21e9763c80d009430dd7737114c4 src/test/java/dev/caskeleton/autoconfigure/GraphQlBatchLoaderWiringTest.java 54 f84ccbd8d86b7ee09e862316093a4798868e8648 src/test/java/dev/caskeleton/autoconfigure/GraphQlDeploymentModeContractTest.java 274 d0f5181e6b0e8bbb7725bc7fc615ee0d10f2aa9a src/test/java/dev/caskeleton/autoconfigure/GraphQlObservationWiringTest.java 62 73a31121c66bfbdf10aee97e592e33e86bb0d342 src/test/java/dev/caskeleton/autoconfigure/GraphQlPlatformAutoConfigurationTest.java 236 41cc6798cabe1267dbf2dd6708139e49ee41a63f src/test/java/dev/caskeleton/autoconfigure/GraphQlPlatformStartupValidatorTest.java 123 1dcaa60e23659d433354552a0de3bb7aa94c9b8b src/test/java/dev/caskeleton/autoconfigure/GraphQlPolicyRequestPathTest.java 112 ffbb69d6ce2236a42907d39019eb0c0450ab94f5 src/test/java/dev/caskeleton/autoconfigure/GraphQlTransportNeutralityTest.java 201 aca33a89df432c626eab84c545e73eed7931f04e src/test/java/dev/caskeleton/moduleboundary/GraphQlBuildModel.java 293 d324b1bc361a492cfc362ec1d2b8e6eedf9c75c6 src/test/java/dev/caskeleton/moduleboundary/GraphQlModuleBoundaryTest.java 190 143beb792061e08b66e2a2bb2519b771a39dea79 src/test/java/dev/caskeleton/moduleboundary/GraphQlSourceGraph.java 30 file_count=60 === 8.1 조립 진입점과 컴포지션 루트의 관계 === $ cat adapter/inbound/graphql/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports dev.caskeleton.adapter.inbound.graphql.autoconfigure.GraphQlRootAutoConfiguration exit=0 $ cat adapter/inbound/graphql/src/main/resources/META-INF/spring.factories org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ dev.caskeleton.adapter.inbound.graphql.autoconfigure.GraphQlOffAutoConfigurationImportFilter org.springframework.boot.EnvironmentPostProcessor=\ dev.caskeleton.adapter.inbound.graphql.autoconfigure.GraphQlActivationEnvironmentPostProcessor exit=0 $ grep -n 'graphql' app-bootstrap/src/main/java/dev/caskeleton/bootstrap/CaSkeletonApplication.java 108: + "|dev\\.caskeleton\\.adapter\\.inbound\\.graphql\\..*" exit=0 $ grep -rn 'inbound.graphql' --include=*.java app-bootstrap/src/main sample-portfolio/src/main | wc -l 0 exit=0 $ grep -n '@Import' -A 12 adapter/inbound/graphql/src/main/java/dev/caskeleton/adapter/inbound/graphql/autoconfigure/GraphQlRootAutoConfiguration.java 23:@Import({ 24- GraphQlPlatformAutoConfiguration.class, 25- // The resolver for the schema's only field. It is a @Controller in a package the composition 26- // root's component scan excludes by regex — the exclusion that makes this capability optional — 27- // and no root imported it, so a deployment with GraphQL on served a schema declaring 28- // `_health: String!` with nothing to resolve it. Every query answered 29- // NullValueInNonNullableField. Its own tests passed throughout by registering the class 30- // themselves, which is the shape of the defect rather than a defence against it. 31- dev.caskeleton.adapter.inbound.graphql.HealthGraphqlController.class 32-}) 33-public class GraphQlRootAutoConfiguration {} exit=0 === 8.2 off 계약: 프레임워크 자동설정 차단 === $ grep -c 'org.springframework.boot.graphql.autoconfigure' adapter/inbound/graphql/src/main/java/dev/caskeleton/adapter/inbound/graphql/autoconfigure/GraphQlOffAutoConfigurationImportFilter.java 10 exit=0 $ grep -n 'fails open silently' -B 2 -A 2 adapter/inbound/graphql/src/main/java/dev/caskeleton/adapter/inbound/graphql/autoconfigure/GraphQlOffAutoConfigurationImportFilter.java 16- * one whose project beans are absent while the framework serves it anyway. 17- * 18: *

A misspelled entry fails open silently — the filter simply never matches — so the test that 19- * protects this asserts a 404 on the real port rather than checking what this method returns. 20- */ exit=0 $ grep -rn 'backend.graphql.enabled=false' --include=*.java adapter/inbound/graphql/src | wc -l 0 exit=0 $ grep -n 'void \|@DisplayName\|statusCode' app-bootstrap/src/test/java/dev/caskeleton/bootstrap/activation/GraphQlShippedAndGatedTest.java | head -14 34: static void startAllOff() { 43: static void stop() { 50: @DisplayName("the GraphQL facade is on the shipped classpath") 51: void facadeIsShipped() throws ClassNotFoundException { 70: @DisplayName("GraphQL off publishes no endpoint") 71: void graphQlOffPublishesNoEndpoint() throws IOException, InterruptedException { 75: assertThat(graphQl.statusCode()) 81: .isEqualTo(neverMapped.statusCode()); 82: assertThat(graphQl.statusCode()) 88: @DisplayName("GraphQL off holds no schema and no execution bean") 89: void graphQlOffHoldsNothing() { exit=0 === 8.3 은퇴한 설정 키를 무시가 아니라 거부 === $ grep -n 'RETIRED_KEYS' -A 10 adapter/inbound/graphql/src/main/java/dev/caskeleton/adapter/inbound/graphql/autoconfigure/GraphQlRetiredSafetyAxis.java | head -14 27: private static final Map RETIRED_KEYS = 28- Map.of( 29- "backend.graphql.production", 30- "it drove anonymous principal handling and allow-by-default authorization while the " 31- + "environment enum drove introspection, so the two could disagree", 32- "backend.graphql.environment", 33- "it drove introspection and GraphiQL while the production boolean drove authorization, " 34- + "so the two could disagree"); 35- 36- private GraphQlRetiredSafetyAxis() {} 37- -- 49: for (String key : RETIRED_KEYS.keySet().stream().sorted().toList()) { 50- if (environment.containsProperty(key)) { exit=0 === 8.4 시작 검증 규칙 수와 .imports 메타데이터 고정 === $ grep -c 'problems.add' adapter/inbound/graphql/src/main/java/dev/caskeleton/adapter/inbound/graphql/autoconfigure/GraphQlPlatformStartupValidator.java 21 exit=0 $ grep -c '@Bean' adapter/inbound/graphql/src/main/java/dev/caskeleton/adapter/inbound/graphql/autoconfigure/GraphQlPlatformAutoConfiguration.java 39 exit=0 $ grep -c '@ConditionalOn' adapter/inbound/graphql/src/main/java/dev/caskeleton/adapter/inbound/graphql/autoconfigure/GraphQlPlatformAutoConfiguration.java 43 exit=0 $ grep -n 'theAutoConfigurationIsRegisteredInTheImportsMetadata' -A 14 adapter/inbound/graphql/src/test/java/dev/caskeleton/adapter/inbound/graphql/autoconfigure/GraphQlPlatformAutoConfigurationTest.java 186: void theAutoConfigurationIsRegisteredInTheImportsMetadata() { 187- String imports = 188- readClasspathResource( 189- "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports"); 190- 191- assertThat(imports) 192- .as( 193- "the registered entry is the master-gated root, not the platform configuration it " 194- + "imports; registering the platform directly is what let a context assemble a " 195- + "GraphQL endpoint that no switch had asked for") 196- .contains(GraphQlRootAutoConfiguration.class.getName()) 197- .doesNotContain(GraphQlPlatformAutoConfiguration.class.getName() + "\n"); 198- } 199- 200- @Test exit=0