Files
document-haness/docs/clean-architecture-backend-template/final/evidence/raw/a16-f004-graphqloperationnamepolicy.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

90 lines
6.4 KiB
Plaintext

# 이름 요구를 읽는 세 클래스의 줄 수
GraphQlOperationNamePolicy.java : 85 줄
GraphQlOperationSelectionHandler.java : 125 줄
GraphQlRequestEnvelopeValidator.java : 152 줄
# GraphQlOperationNamePolicy 를 자기 파일 밖에서 쓰는 자리
main · GraphQlOperationNameInterceptor.java:17 private final GraphQlOperationNamePolicy policy;
main · GraphQlOperationNameInterceptor.java:24 public GraphQlOperationNameInterceptor(GraphQlOperationNamePolicy policy) {
test · GraphQlOperationNamePolicyTest.java:14 class GraphQlOperationNamePolicyTest {
test · GraphQlOperationNamePolicyTest.java:18 var policy = GraphQlOperationNamePolicy.production();
test · GraphQlOperationNamePolicyTest.java:29 GraphQlOperationNamePolicy.local()
test · GraphQlOperationNamePolicyTest.java:40 GraphQlOperationNamePolicy.local()
test · GraphQlOperationNamePolicyTest.java:50 var policy = GraphQlOperationNamePolicy.production();
test · GraphQlOperationNamePolicyTest.java:68 var policy = GraphQlOperationNamePolicy.production();
test · GraphQlOperationNamePolicyTest.java:78 var policy = GraphQlOperationNamePolicy.production();
test · GraphQlOperationNamePolicyTest.java:94 var interceptor = new GraphQlOperationNameInterceptor(GraphQlOperationNamePolicy.production());
# GraphQlOperationNameInterceptor 를 자기 파일 밖에서 쓰는 자리
test · GraphQlOperationNamePolicyTest.java:94 var interceptor = new GraphQlOperationNameInterceptor(GraphQlOperationNamePolicy.production());
# GraphQlRequestEnvelopeValidator 를 실제로 만드는 자리 전부
test · GraphQlRequestBoundsTest.java:38
test · GraphQlRequestBoundsTest.java:50
test · GraphQlRequestEnvelopeValidatorTest.java:19
test · GraphQlRequestEnvelopeValidatorTest.java:30
test · GraphQlRequestEnvelopeValidatorTest.java:41
test · GraphQlRequestEnvelopeValidatorTest.java:77
test · GraphQlRequestEnvelopeValidatorTest.java:92
test · GraphQlRequestEnvelopeValidatorTest.java:101
testFixtures · GraphQlContractFixture.java:84
# namedOperationRequired 를 읽는 프로덕션 코드
main · GraphQlRequestEnvelopeValidator.java:63 policy.namedOperationRequired(),
main · GraphQlRequestEnvelopeValidator.java:134 if (namedOperationRequired && GraphQlOperationName.parse(envelope.operationName()).isEmpty()) {
main · GraphQlOperationSelectionHandler.java:74 if (policy.namedOperationRequired() && selected.getName() == null) {
# GraphQlClientPolicy 인스턴스를 만드는 프로덕션 코드 전부
main · GraphQlPlatformAutoConfiguration.java:303 return GraphQlClientPolicy.defaults(
main · GraphQlClientPolicy.java:85 public static GraphQlClientPolicy defaults(
main · GraphQlClientPolicy.java:87 return new GraphQlClientPolicy(
그 빈을 내놓는 자리 :
GraphQlPlatformAutoConfiguration.java:300 @Bean
GraphQlPlatformAutoConfiguration.java:301 @ConditionalOnMissingBean
GraphQlPlatformAutoConfiguration.java:302 public GraphQlClientPolicy graphQlClientPolicy(GraphQlPlatformSettings properties) {
GraphQlPlatformAutoConfiguration.java:303 return GraphQlClientPolicy.defaults(
GraphQlPlatformAutoConfiguration.java:304 properties.limits().maximumPageSize(),
GraphQlPlatformAutoConfiguration.java:305 properties.limits().maximumComplexity(),
GraphQlPlatformAutoConfiguration.java:306 properties.console().introspectionEnabled());
GraphQlPlatformAutoConfiguration.java:307 }
GraphQlPlatformAutoConfiguration.java:308
defaults 가 마지막 세 성분에 넣는 값과 그 성분의 이름 :
값 GraphQlClientPolicy.java:101 introspectionAllowed,
값 GraphQlClientPolicy.java:102 false,
값 GraphQlClientPolicy.java:103 false);
이름 GraphQlClientPolicy.java:49 boolean introspectionAllowed,
이름 GraphQlClientPolicy.java:50 boolean persistedOperationOnly,
이름 GraphQlClientPolicy.java:51 boolean namedOperationRequired) {
# 배선된 핸들러가 요청 경로에 오르는 사슬
main · GraphQlPlatformAutoConfiguration.java:403 return GraphQlExecutionChain.stable(
main · GraphQlPlatformAutoConfiguration.java:404 new GraphQlOperationSelectionHandler(clientPolicy),
main · GraphQlPlatformAutoConfiguration.java:420 return new GraphQlPlatformInstrumentation(chain);
main · GraphQlExecutionChain.java:43 public static GraphQlExecutionChain stable(
GraphQlPlatformInstrumentation.java:81 chain.run(
그 사슬이 붙는 어댑터 자체의 조건 :
GraphQlRootAutoConfiguration.java:4 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
GraphQlRootAutoConfiguration.java:21 @ConditionalOnProperty(prefix = "backend.graphql", name = "enabled", havingValue = "true")
# GraphQlRequestContext.operationId 를 읽는 프로덕션 코드
main 에서 0 건
참고 — 이 모듈 main 에서 operationId() 로 잡히는 둘은 별개 타입이다 :
main · GraphQlPersistedOperationAdminService.java:68 command.operationId(),
main · GraphQlPersistedOperationInterceptor.java:50 GraphQlPersistedOperation operation = lookup.require(request.operationId());
# 미배선 정책이 이름을 검사하는 방식과 GraphQlOperationName.parse 의 계약
GraphQlOperationNamePolicy.java:54 if (namedRequired && !selection.named()) {
GraphQlOperationNamePolicy.java:55 throw new GraphQlAnonymousOperationException("named operation required");
GraphQlOperationNamePolicy.java:56 }
GraphQlOperationNamePolicy.java:57 if (selection.named() && GraphQlOperationName.parse(selection.operationName()).isEmpty()) {
GraphQlOperationNamePolicy.java:58 // Validates the bounded naming pattern; an unbounded name would defeat the reason for
GraphQlOperationNamePolicy.java:59 // requiring one at all.
GraphQlOperationNamePolicy.java:60 throw new GraphQlAnonymousOperationException("named operation required");
GraphQlOperationNamePolicy.java:61 }
GraphQlOperationName.java:37 public static Optional<GraphQlOperationName> parse(String candidate) {
GraphQlOperationName.java:38 if (candidate == null || candidate.isBlank()) {
GraphQlOperationName.java:39 return Optional.empty();
GraphQlOperationName.java:40 }
GraphQlOperationName.java:41 return Optional.of(new GraphQlOperationName(candidate));
GraphQlOperationName.java:42 }