Files
clean-architecture-frontend…/docs/architecture/api-contract-schema-mapper-and-server-state.md
2026-08-01 19:39:59 +09:00

53 KiB

API contract, Schema, Mapper와 Server State platform

정본 안내 (non-authoritative for runtime capability decisions)

Runtime Config/boot, Fetch HTTP client, Router, Query/Mutation, realtime 공통 경계, Web Worker, Service Worker, offline command와 Background Sync의 구현 결정은 프론트엔드 런타임 Capability 저장소 정합형 구현 결정 폐쇄 상세 설계가 정본이다. 본 문서의 해당 서술이 정본과 충돌하면 정본을 따른다.

1. 목적

이 문서는 다음 질문을 하나의 production 계약으로 닫는다.

  • REST, GraphQL, Connect와 gRPC-Web 중 무엇을 어디에 사용하는가
  • Protobuf contract와 REST Gateway가 transport/runtime과 어떻게 분리되는가
  • request/response가 어느 지점까지 untrusted wire data인가
  • TypeScript type, generated code와 runtime validation의 역할은 무엇인가
  • DTO를 domain/application projection으로 누가 변환하는가
  • server response를 어떤 query identity와 lifecycle로 cache하는가
  • schema, mapper, transport와 cache가 바뀔 때 어떻게 배포·관측·rollback하는가

각 protocol은 서로 대체 가능한 URL 호출 문법이 아니다. transport-specific codec, proxy와 failure semantics는 adapter가 소유한다. application은 transport 종류, URL, GraphQL document, protobuf message나 TanStack Query를 직접 알지 않고 feature-owned gateway와 application input만 호출한다.

2. 상태 모델

이 문서는 browser data 설계와 동일한 primary current-status literal을 사용한다.

primary status 의미
COMPOSED production bootstrap 또는 설치된 feature 호출 경로에 concrete runtime이 실제 연결돼 있다.
AVAILABLE_NOT_COMPOSED 실행 가능한 reference runtime과 test가 있지만 production graph에는 연결하지 않았다.
DESIGNED_NOT_IMPLEMENTED 계약·불변조건·failure와 promotion 기준은 승인됐지만 해당 runtime 또는 필수 orchestration이 없다.
NOT_SELECTED 제품 요구, owner와 비용이 승인되지 않아 의도적으로 선택하지 않았다.
PLATFORM_LIMITED target browser/protocol이 요구 semantics를 공통으로 보장하지 못한다.

primary status와 다음 readiness 축을 섞지 않는다.

Selection
  NOT_SELECTED | SELECTED | REMOVING

TrafficAdmission
  DISABLED | SHADOW | CANARY | ENABLED

RuntimeHealth
  UNKNOWN | AVAILABLE | DEGRADED | UNAVAILABLE | INCOMPATIBLE

PromotionEvidence
  MISSING | PARTIAL | COMPLETE | EXPIRED

COMPOSED는 traffic이 켜졌거나 provider가 conformant라는 뜻이 아니다. AVAILABLE_NOT_COMPOSED도 제품 bundle에 dependency가 들어갔다는 뜻이 아니다.

3. 현재 capability ledger

capability primary current status 현재 증거 목표 또는 잔여
installed REST reference vertical COMPOSED operation registry → request schema → HTTP → envelope/payload schema → mapper → application input → Query 화면 경로 아래 REST hardening delta와 실제 제품 provider 계약
shared REST JSON executor COMPOSED path/search/body codec projection, shared deadline/retry-sleep budget, AbortSignal, bounded auth recovery, exact envelope/media/status, safe failure와 diagnostics 204/304/412 execution join과 actual provider conformance
REST v2 security/execution baseline COMPOSED collision-aware operation composition, path placeholder↔codec key exact join, prefix-preserving HTTPS/loopback provider, named bearer/CSRF profile와 credential-mode ceiling, auth fail-before-fetch, bounded JSON, outbound correlation/status·physical-attempt 관측 cookie-CSRF/CORS provider evidence, 204/304/412 conditional execution과 compatibility artifact
GraphQL provider-neutral reference adapter DESIGNED_NOT_IMPLEMENTED source/dependency/codegen/runtime 없음 persisted-operation-only transport, GraphQL response decoder, mapper binding과 contract harness
product GraphQL composition NOT_SELECTED endpoint/schema/persisted manifest/owner 없음 제품 query가 REST보다 GraphQL aggregation을 정당화할 때 선택
GraphQL batching, subscription, @defer/@stream NOT_SELECTED 없음 각각 독립 ADR, proxy/browser lifecycle과 cache semantics 필요
provider-neutral Browser RPC V3 contract/runtime AVAILABLE_NOT_COMPOSED operation/profile/schema/mapper/encoder/transport exact join, typed application port, bounded unary retry/deadline/abort, server-stream idle/total/message/terminal/generation fence와 fail-closed unavailable adapter test selected descriptor/generated client와 protocol-specific bounded transport를 붙이고 actual provider/browser conformance
gRPC-Web unary reference adapter DESIGNED_NOT_IMPLEMENTED source/dependency/generated message 없음 fixed method registry, protobuf codec, trailers/status/deadline와 proxy conformance
gRPC-Web server-stream reference adapter DESIGNED_NOT_IMPLEMENTED source 없음 bounded frame/idle/total budget, sequence/resume application protocol과 stream port
product gRPC-Web composition NOT_SELECTED service descriptor/proxy/owner 없음 browser-facing gRPC-Web gateway가 실제 이점을 줄 때 선택
gRPC-Web client-streaming/bidi guarantee PLATFORM_LIMITED gRPC-Web browser baseline이 해당 semantics를 제공하지 않음 REST upload, WebSocket/WebTransport 또는 별도 protocol을 선택
Protobuf schema/codegen governance DESIGNED_NOT_IMPLEMENTED .proto, Buf config, descriptor와 generated output 없음 authenticated source, immutable descriptor, deterministic codegen과 compatibility evidence
Connect-Web unary/server-stream reference adapter DESIGNED_NOT_IMPLEMENTED @connectrpc/*, @bufbuild/protobuf, generated service와 provider 없음 exact Connect/gRPC-Web transport row, bounded decode와 actual browser/provider conformance
product Connect protocol composition NOT_SELECTED service/provider/owner 없음 Protobuf-first backend의 selected browser operation이 있을 때만 선택
Connect browser client-streaming/bidi guarantee PLATFORM_LIMITED Connect protocol 기능과 browser request-stream 지원은 다름 별도 duplex/application protocol 선택
Protobuf REST Gateway reference contract/harness DESIGNED_NOT_IMPLEMENTED HttpRule/transcoder/OpenAPI/provider fixture 없음 selected kind의 deterministic/provider conformance
product Protobuf REST Gateway composition NOT_SELECTED route/provider/owner 없음 curated BFF, grpc-gateway 또는 Envoy transcoder 중 하나와 public HTTP contract 승인
feature runtime request/response Schema COMPOSED Zod request/payload schemas와 installed schema registry가 reference feature에 연결 byte/depth/node ceiling, unknown-field profile, schema artifact/digest와 multi-protocol source governance
schema/mapper v2 reference baseline COMPOSED collision-aware schema codec/mapper contribution install, operation schema/mapper reference resolution, request reject/response strip 방향, bounded collection, typed no-throw mapping result와 operation별 cast-free result guard actual codec fingerprint, source provenance와 multi-protocol compatibility policy
generated contract artifact governance DESIGNED_NOT_IMPLEMENTED generated-api recipe만 있고 generator/provider 선택 없음 OpenAPI/GraphQL/proto source authentication, pinned generation, drift/breaking gate와 N/N-1
feature boundary Mapper COMPOSED installed mapper metadata composer와 response-schema exact join 뒤 typed no-throw MappingResult → immutable domain/application view 실행 numeric/date/null/enum canonical rules와 generated-artifact join
TanStack Query memory Server State COMPOSED QueryClient, cancellation, stale-degraded UI, session-generation cancel/clear fence와 invalidation coordinator account identity projection과 bounded topic↔namespace many-to-many registry
reference bound-query/server-state profile COMPOSED bound definition, strict canonical input, scope-private opaque identity, active lease/LRU/collision/entry-byte ceiling, per-profile policy와 result admission account projection, conditional HTTP execution join과 pagination composition
mutation duplicate coordinator baseline COMPOSED QueryClient runtime/scope 단위 exact semantic input identity로 identical만 join하고 distinct input을 합치지 않으며 late scope result를 폐기 logical-key serialization과 effect certainty/reconcile
optimistic ordered-layer runtime AVAILABLE_NOT_COMPOSED out-of-order commit/rollback, authoritative external update 재적용과 expired-scope 제거 test 제품 mutation의 deterministic membership/revision contract 승인 뒤 definition에 연결
conditional validator CAS sidecar AVAILABLE_NOT_COMPOSED scope/representation/cache revision exact binding, ETag validation과 bounded capacity test; session 전환 clear는 production infrastructure에 연결 HTTP If-None-Match/304 query transaction과 query removal lifecycle join
bounded cursor chain runtime AVAILABLE_NOT_COMPOSED page invariant, cursor loop, snapshot drift, page/item/byte/cursor ceiling과 abort test backend CursorPage DTO/next cursor 계약 후 reference/infinite-query binding
cross-context server-state invalidation COMPOSED singular opaque topic 기반 invalidate-only coordinator와 session-generation local reset account projection과 bounded topic↔namespace many-to-many registry
normalized GraphQL entity cache NOT_SELECTED 없음 TanStack operation-result cache로 해결되지 않는 측정된 요구가 있을 때 별도 선택
persisted query cache reference DESIGNED_NOT_IMPLEMENTED, product NOT_SELECTED Web Storage persistence는 금지, IndexedDB persister 없음 VD-13의 scope/retention/restore gate를 별도 통과
offline mutation queue NOT_SELECTED foreground mutation만 존재 backend idempotency/cursor/conflict protocol과 durable command owner 필요

현재 REST reference는 Response.json()이 아니라 byte-bounded reader를 사용하고, external auth owner는 allowlisted header patch만 반환한다. 인증 통합 실패는 fetch 전에 닫히며 correlation, success status와 physical attempt가 terminal observation에 반영된다. 다만 이 baseline을 conditional response, complete pagination, provider conformance나 GraphQL/gRPC runtime의 증거로 재사용하지 않는다. 마찬가지로 Browser RPC V3 공통 coordinator의 AVAILABLE_NOT_COMPOSED 판정은 vendor wire adapter의 구현 판정이 아니다. @connectrpc/*, official grpc-web, generated message와 descriptor가 없는 현재 상태에서 Connect/gRPC-Web 각 row는 계속 DESIGNED_NOT_IMPLEMENTED다.

4. 최상위 경계

presentation
  -> feature application input
       -> feature use case
            -> feature gateway port
                 -> operation registry
                      -> REST adapter
                      -> GraphQL adapter
                      -> Connect adapter
                      -> gRPC-Web adapter
                 -> bounded wire decoder
                 -> runtime schema / semantic validation
                 -> boundary mapper
            -> immutable application projection
  -> server-state query adapter
       -> registry-owned query identity and policy
       -> mapped application result only

금지 경로:

page -> fetch / GraphQL SDK / generated Connect/gRPC client
page -> raw URL / query document / protobuf message
transport DTO -> domain or presentation public type
Response / GraphQL response / generated message -> Query cache
Query cache -> authorization or business conflict authority

application port는 use-case 의미를 표현한다. 예를 들어 listResources(filters), createResource(command)는 허용하지만 executeGraphql(document, variables), grpcCall(service, method, bytes)request(url, options)는 허용하지 않는다.

5. Protocol-neutral operation contract

각 외부 호출은 build-time registry의 discriminated row 하나로 고정한다. application caller는 operationId와 schema가 허용한 input만 제출한다.

ApiOperationContractV3
  registryVersion
  operationId
  owner
  protocol = REST | GRAPHQL_HTTP | CONNECT_HTTP | GRPC_WEB
  semantics = QUERY | COMMAND | SERVER_STREAM
  authProfileId
  csrfProfileId
  replayPolicy = SAFE | IDEMPOTENT | KEYED_COMMAND | NON_REPLAYABLE
  idempotencyKeyPolicy = NONE | REQUIRED
  requestSchemaId
  responseSchemaId
  mapperId
  errorProfileId
  deadlineProfileId
  retryProfileId
  serverStateProfileId | null
  invalidationTopicRefs[] = { topicId, topicVersion }
  dataClassification
  compatibility
    globalApiContractVersion
    protocolArtifactId
    minimumServerVersion
    retirementEpoch | null
  protocolBinding

protocolBinding은 transport별 closed union이다.

REST
  method
  relativePathTemplate
  requestProjection
  requestMediaProfile
  responseMediaProfile
  conditionalProfile

GRAPHQL_HTTP
  endpointId
  graphqlHttpProfileRevision
  persistedEnvelopeProfileId
  responseStatusMediaProfileId
  persistedOperationId
  persistedOperationSha256
  operationType
  partialDataPolicy

GRPC_WEB
  endpointId
  clientRuntimeId
  grpcWebWireSpecRevision
  transportProfile
  responseHttpStatusProfileId
  fullyQualifiedService
  method
  rpcKind = UNARY | SERVER_STREAM
  requestMessageId
  responseMessageId

CONNECT_HTTP
  endpointId
  clientRuntimeId
  connectProtocolRevision
  encoding = PROTO_JSON | PROTO_BINARY
  requestMethod = POST | GET
  fullyQualifiedService
  method
  rpcKind = UNARY | SERVER_STREAM
  descriptorArtifactId
  descriptorDigest

registry validation은 다음을 build/boot 전에 거절한다.

  • 중복 operation/mapper/profile ID
  • protocol과 맞지 않는 binding field
  • 등록되지 않은 schema, mapper, auth, deadline, retry와 cache profile
  • QUERY인데 replay policy가 SAFE | IDEMPOTENT가 아님
  • KEYED_COMMAND인데 idempotency key policy가 REQUIRED가 아니거나 backend dedupe/reconcile profile이 없음
  • NON_REPLAYABLE인데 network/401 replay가 enabled
  • COMMAND인데 cache profile이 query data owner로 지정됨
  • SERVER_STREAM인데 ordinary query cache profile을 사용
  • opening retry가 enabled인데 replay policy가 SAFE | IDEMPOTENT가 아님
  • KEYED_COMMAND | NON_REPLAYABLE server stream인데 opening retry가 enabled거나 explicit resume/reconcile/dedupe profile이 없음
  • SERVER_STREAM인데 protocol=CONNECT_HTTP | GRPC_WEBrpcKind=SERVER_STREAM 조합이 아님. REST SSE와 GraphQL subscription을 이 registry 의미로 암묵 등록하지 않음
  • unsafe REST method 또는 GraphQL mutation인데 CSRF/replay/key 결정이 없음
  • gRPC-Web client/bidi method
  • Connect browser client/bidi method 또는 descriptor의 NO_SIDE_EFFECTS가 없는 Connect GET
  • absolute URL, runtime GraphQL document 또는 caller-provided service/method
  • implementation hard ceiling보다 큰 timeout, byte, frame, page와 retry 값
  • GraphQL operation↔provider의 HTTP revision/envelope/status-media profile 또는 Connect/gRPC-Web operation↔provider의 runtime/wire/status/capability tuple mismatch

현재 installed reference operation은 REST v2 metadata를 사용한다. operation, runtime schema codec과 mapper contribution은 object spread가 아니라 각각의 collision-aware composer로 설치되며 duplicate ID를 덮어쓰기 전에 거절한다. boot-time binding 검증은 path placeholder와 codec key, provider/auth/CSRF profile, path/request/response schema와 mapper input schema를 exact resolve한 뒤 immutable registry를 발행한다. GraphQL/Connect/gRPC-Web discriminant와 protocol-specific binding은 해당 reference adapter가 아직 없으므로 source에 구현됐다고 표현하지 않는다.

현재 API_CONTRACT_VERSION은 runtime config와 release manifest의 문자열 일치 gate다. 목표 contract set은 REST/OpenAPI artifact, GraphQL schema/persisted manifest, protobuf descriptor, runtime schema/mapper registry digest를 포함한 bounded manifest를 만들고 global compatibility version과 함께 release tuple에 binding한다. 문자열 일치만 actual backend compatibility 증거로 사용하지 않는다.

6. 공통 실행 lifecycle

lookup exact operation
  -> freeze session/account/runtime generation
  -> validate and canonicalize application input
  -> derive exact query/command identity
  -> allocate total operation deadline
  -> encode transport request from registry binding
  -> attach credential/CSRF through approved owner
  -> execute bounded attempt
  -> bounded response/frame decode
  -> validate transport envelope/status
  -> validate operation DTO/message semantics
  -> map to immutable application projection
  -> re-check scope/generation
  -> return Result
  -> query adapter may admit mapped value to memory cache

현재 v2 auth owner는 Request를 반환하지 않고 transport가 만든 immutable request binding에 대해 allowlisted credential patch만 제공한다. 최소한 transport는 attach 뒤에도 URL, origin, method, body digest, content headers, idempotency와 conditional binding이 바뀌지 않았음을 다시 검증한다. auth-required operation은 session state가 unauthenticated/integration-failed이거나 credential attachment가 실패하면 fetch 0회로 닫는다. 동시 401 recovery는 session owner의 single-flight 한 번만 공유하며 replay-safe operation만 동일 logical deadline/idempotency binding으로 한 번 재실행한다.

모든 async boundary와 terminal cache write 전에 captured generation을 확인한다. logout/account switch 뒤 끝난 response, mapper와 stream frame은 old runtime 결과로 폐기한다.

deadline은 attempt마다 새로 시작하지 않는다.

total budget
  = credential attach
  + network attempts
  + retry delay
  + body/frame read
  + schema validation
  + mapper

각 phase에 별도 하위 ceiling을 둘 수 있지만 전체 deadline을 늘릴 수 없다. caller abort, runtime teardown, timeout과 provider cancellation은 서로 다른 safe failure로 정규화한다.

7. Transport 선택 기준

요구 기본 선택 이유
resource/command, HTTP cache/conditional semantics, 파일 handoff REST Web/BFF·CDN·운영 도구와 자연스럽고 failure/status가 명확함
여러 aggregate를 한 화면 shape로 읽고 client별 selection이 유의미 persisted GraphQL query allowlisted operation으로 over/under-fetch를 줄일 수 있음
Protobuf-first backend의 내부 web UI, unary 또는 bounded server stream Connect-Web/Connect 우선 평가 generated descriptor와 Fetch 기반 browser RPC를 재사용
기존 gRPC-Web proxy/conformance 자산 selected gRPC-Web runtime runtime별 binary/text/stream capability를 exact profile로 고정
ProtoJSON/HttpRule 자체가 승인된 public HTTP contract generated REST Gateway 검토 envelope/status/cache/idempotency를 별도 증명
현재 REST envelope·ETag·Range·제품 DTO가 중요 curated REST BFF 유지 generated transcoder가 제품 HTTP 의미를 자동 제공하지 않음
browser client/bidi streaming Connect/gRPC-Web 사용 금지 protocol 자체 기능과 browser 공통 지원을 혼동하지 않음
arbitrary ad-hoc query GraphQL 사용 금지 cost, authorization, cache identity와 operation governance를 우회
단순 CRUD인데 GraphQL/gRPC dependency만 추가 REST 유지 복잡도와 bundle/proxy 비용을 정당화하지 못함

한 feature가 여러 protocol을 사용할 수 있지만 한 operationId는 한 protocol에만 binding한다. query read를 shadow 비교하는 경우에도 secondary 결과는 사용자와 cache에 반영하지 않는다. command는 protocol 장애를 이유로 자동 failover/replay 하지 않는다.

8. REST 설계 요약

REST 상세 결정은 VD-23이 소유한다. 공통 baseline은 다음과 같다.

  • base origin과 relative path template은 composition/registry가 소유한다.
  • provider base URL은 HTTPS와 exact origin/path-prefix를 고정하고 userinfo, query와 fragment를 금지한다. path join은 선택한 base prefix를 보존하며 leading slash가 prefix를 조용히 제거하지 않는다.
  • method는 closed union이며 path/search/header/body는 각 runtime schema를 지난다.
  • replay semantics는 SAFE, IDEMPOTENT, KEYED_COMMAND, NON_REPLAYABLE로 method와 교차 검증한다.
  • caller-provided URL, header, credentials, redirect와 cache option을 금지한다.
  • cookie session이면 unsafe method에 approved CSRF owner가 필요하다.
  • SAFE | IDEMPOTENT | KEYED_COMMAND 중 exact retry profile과 실제 provider replay evidence가 있는 operation만 network retry한다.
  • keyed retry와 401 recovery는 같은 logical idempotency key를 유지한다.
  • total deadline, attempts, backoff와 Retry-After는 implementation ceiling 안이다.
  • JSON/error body는 present/valid Content-Length advisory preflight와 actual decoded-byte bounded stream reader 뒤 parse한다. encoded transfer cap은 BFF/proxy/CDN가 집행한다.
  • status, content type, response media profile과 envelope 조합을 exact하게 검증한다.
  • 204, 304, 412, 422와 problem/envelope profile은 operation이 명시한 경우만 허용한다.
  • strong ETag는 cache identity가 아니라 exact representation revalidation metadata다. validator를 diagnostics에 기록하지 않는다. Last-Modified는 별도 weak/time validator profile이 승인되기 전 이번 target에 포함하지 않는다.
  • cursor는 opaque하며 filter/sort/scope와 binding한다. arbitrary URL을 next link로 따라가지 않는다.
  • browser HTTP cache와 application ETag/TanStack revalidation owner 중 하나를 operation별로 선택한다. 두 cache의 freshness를 서로 추측해 합치지 않는다.
  • request/response body, URL query, authorization, CSRF, idempotency key와 raw backend copy를 log/telemetry에 넣지 않는다.

9. GraphQL 설계 요약

GraphQL 상세 결정은 VD-26이 소유한다. reference target은 persisted operation only다.

  • production bundle은 arbitrary GraphQL document string을 runtime에 받지 않는다.
  • build artifact가 operation name, stable ID, SHA-256, variables/result schema, schema digest와 owner를 manifest로 만든다.
  • BFF/router는 allowlist에 없는 ID/hash와 cost/depth limit 초과를 거절한다.
  • endpoint는 fixed HTTPS registry ID이고 POST가 기본이다.
  • selected provider가 지원하는 GraphQL-over-HTTP revision과 persisted-envelope extension을 profile에 고정한다. ID/hash-only request를 generic 표준 envelope로 가장하지 않는다.
  • Accept: application/graphql-response+json을 우선하고 final URL/media/body cap 뒤에는 허용 HTTP status의 GraphQL envelope를 bounded decode한 다음 status/body matrix를 교차 검증한다. legacy application/json은 별도 profile이다.
  • public cacheable query의 GET은 별도 threat/cache review 뒤에만 허용한다.
  • variables는 request schema와 byte/depth/node ceiling을 통과한다.
  • HTTP status와 GraphQL data/errors/extensions를 두 단계로 검증한다.
  • default partialDataPolicy=REJECT; 승인 operation만 typed completeness metadata와 함께 partial을 application으로 투영할 수 있다.
  • error message, path value와 arbitrary extensions를 노출하지 않고 registered safe code/category만 AppFailure로 mapping한다.
  • APQ miss에서 full document를 자동 전송하지 않는다. manifest/version mismatch로 fail-closed하고 coherent frontend/router artifact를 복구한다.
  • batching은 auth, deadline, cancel, observation과 partial failure owner가 별도 승인되기 전 NOT_SELECTED다.
  • subscription, @defer, @stream은 ordinary query adapter에 암묵적으로 넣지 않는다.
  • Apollo/urql normalized cache는 기본 dependency가 아니다. mapped operation result의 memory owner는 TanStack Query다.

10. Browser Protobuf RPC와 REST Gateway 설계 요약

축과 선택 기준의 상세 계약은 Protobuf browser transport와 REST Gateway가 소유한다. Protobuf는 IDL/serialization, Connect와 gRPC-Web은 browser wire protocol, Connect-Web/official grpc-web은 client runtime, REST Gateway는 HTTP 노출 방식이다. 네 이름을 하나의 대안 목록이나 하나의 auto-negotiating executor로 합치지 않는다.

10.1 gRPC-Web

gRPC-Web 상세 결정은 VD-27이 소유한다. reference target은 unary와 bounded server-stream만 다룬다.

  • checked-in/generated artifact는 pinned proto descriptor/module digest에 묶는다.
  • vendor generated client/message는 feature adapter 내부에만 존재한다.
  • fully-qualified service/method와 endpoint는 registry가 고정한다.
  • client runtime과 gRPC-Web wire-spec revision을 operation/provider에 고정한다. official grpc-web runtime 기준 binary profile은 unary에만 사용하고 server stream은 grpcwebtext에 binding한다.
  • Connect-Web의 createGrpcWebTransport()는 Fetch 기반 binary/JSON unary와 server stream profile이며 grpcwebtext profile이 아니다. official XHR runtime의 capability matrix를 이 runtime에 적용하지 않는다. platform-authored custom binary streaming도 세 browser와 actual proxy의 incremental evidence가 있는 별도 runtime profile만 허용한다.
  • frame header, message length, compression flag, total bytes와 frame count를 bounded decoder가 검증한다.
  • HTTP status와 terminal status source를 함께 검사한다. terminal status source는 body trailer frame 또는 zero-body trailers-only response header 중 정확히 하나이며 중복/충돌을 거절한다.
  • grpc-message, binary error details와 metadata는 allowlist projection 없이 application에 반환하지 않는다.
  • deadline은 grpc-timeout과 local total deadline의 더 짧은 값이며 AbortSignal이 fetch/stream reader를 cancel한다.
  • unary SAFE | IDEMPOTENT | KEYED_COMMAND 중 provider evidence가 있는 operation만 retry한다. stream reconnect는 retry가 아니라 server-owned sequence/resume-token을 가진 별도 application protocol이다.
  • idle deadline, total deadline, max frame/message/count/buffer를 모두 둔다.
  • client-streaming/bidi는 지원한다고 가장하지 않는다.
  • Envoy/BFF/Connect/gRPC-Web proxy의 CORS, exposed trailers, content type, auth와 maximum message 설정을 actual provider conformance로 검증한다.
  • int64/uint64는 JavaScript number로 변환하지 않고 safe integer 범위를 증명하거나 decimal string/adapter-private bigint로 mapping한다.

10.2 Connect-Web과 Connect protocol

Connect 상세 결정은 VD-29가 소유한다.

  • createConnectTransport()createGrpcWebTransport()는 같은 package의 서로 다른 wire protocol이다. decoder/status/terminal profile을 공유하지 않는다.
  • Connect unary의 JSON/binary와 POST를 operation row에 고정한다.
  • GET은 unary + NO_SIDE_EFFECTS descriptor + non-sensitive bounded input + exact URL/cache/CORS profile에서만 별도 승인한다.
  • Connect server stream은 final EndStream envelope를 확인하기 전 성공이 아니다.
  • stock runtime의 whole-body decode와 streaming compression 한계를 exact package version evidence로 확인한다. proxy cap이나 custom bounded transport가 없으면 production raw-byte ceiling을 완료로 표시하지 않는다.
  • interceptor의 resolved onion order, auth 이후 final invariant, total deadline, exactly-one retry owner와 cancel handle을 manifest에 고정한다.
  • @connectrpc/connect-query를 기본 도입하지 않는다. generated service/message는 adapter-private이고 mapped application value만 기존 TanStack Query에 들어간다.

10.3 Protobuf contract와 REST Gateway

Protobuf/REST Gateway 상세 결정은 VD-30이 소유한다.

  • authenticated proto/Buf source, descriptor, generator/runtime/plugin version과 generated digest를 coherent release artifact로 고정한다.
  • JSON 노출은 최소 WIRE_JSON compatibility를 요구하고 canonical HttpRule route manifest와 generated OpenAPI를 별도 semantic diff한다.
  • current reference REST envelope에는 curated BFF를 유지한다.
  • direct grpc-gateway/Envoy transcoder는 ProtoJSON, method/path/query/body, status/error/CORS/cache contract가 그대로 제품 API로 승인된 unary operation에만 적용한다.
  • gateway는 idempotency store, CursorPage snapshot, ETag/304/412, file Range나 안전한 domain error vocabulary를 자동 제공하지 않는다.
  • REST server streaming은 generated gateway의 부수 동작으로 활성화하지 않고 framing/terminal/cache를 소유하는 별도 ADR 없이는 NOT_SELECTED다.

11. Schema trust boundary

TypeScript type과 generated code는 compile-time convenience이지 runtime proof가 아니다. trust transition은 다음 순서를 지킨다.

untrusted bytes/frames
  -> bounded transport decoder
  -> transport envelope/status proof
  -> operation DTO/message runtime or semantic proof
  -> ValidatedWireValue (adapter-private)
  -> boundary mapper
  -> immutable application projection

schema profile은 최소 다음을 고정한다. browser가 직접 집행하는 decoded ceiling과 provider/BFF/proxy가 집행하는 wire/encoded ceiling의 owner를 분리한다.

schemaId
schemaVersion
boundary
protocol
sourceArtifactId + sourceDigest
unknownFieldPolicy
  providerMaxEncodedBytes
  maxDecodedBytes
maxDepth
maxNodes
maxStringBytes
maxCollectionItems
compatibilityPolicy
owner

unknown-field 기본 정책:

경계 정책
request, config, capability, control envelope REJECT_UNKNOWN
evolvable ordinary response DTO STRIP_UNKNOWN 후 mapper에 전달
discriminant/security/authorization 의미를 가진 union unknown variant 거절
unknown data 보존 adapter 내부 forward proxy가 아닌 한 금지

현재 reference request/path DTO는 .strict()로 unknown field를 거절하고, ordinary response DTO는 .strip() projection으로 additive server field를 cache/domain 경계 밖에 버린다. discriminant/security union을 포함한 다른 operation은 각 compatibility profile에 따라 별도로 결정한다.

12. Mapper 경계

mapper는 transport가 아니라 feature contract가 소유한다.

MapperDefinition
  mapperId
  inputSchemaId
  outputContractId
  mapperVersion
  collectionPolicy
  temporalPolicy
  numericPolicy
  nullabilityPolicy
  owner

mapper는 pure, deterministic, side-effect-free이며 다음 union을 반환한다.

MappingResult<T>
  = { ok: true, value: T }
  | { ok: false, error: MAPPING_CONTRACT_VIOLATION }

현재 reference mapper는 예상 가능한 drift를 throw하지 않고 closed MappingResult failure로 반환한다. registry 실행 경계는 예상하지 못한 mapper throw도 fail-closed mapping failure로 바꾸며 raw DTO, value, path와 backend message를 버린다.

공통 scalar 규칙:

  • opaque ID는 trim/재해석하지 않는 bounded branded string이다.
  • ISO timestamp는 offset/precision 정책을 검증한 뒤 application instant로 변환한다. locale date string과 invalid date normalization을 금지한다.
  • int64, decimal money와 high-precision value는 JSON number로 받지 않는다.
  • null, absent와 empty string/list는 schema와 domain에서 별도 의미로 결정한다.
  • unknown enum은 domain이 explicit UNKNOWN을 소유한 경우만 mapping한다.
  • collection mapping은 count/byte ceiling 안에서 fail-fast하고 partial array를 cache하지 않는다.
  • mapper는 network, clock, storage, QueryClient, locale formatter와 telemetry를 호출하지 않는다.

13. Server State Cache 경계

TanStack Query는 transport response cache가 아니라 mapped application projection의 memory lifecycle owner다.

cache에 허용:

  • immutable plain application projection
  • registered query identity로 찾을 수 있는 bounded collection/page
  • UI가 stale/refresh 상태를 계산하는 library metadata

cache에 금지:

  • Response, raw JSON/GraphQL envelope, generated protobuf message
  • auth/CSRF/idempotency token, request header와 arbitrary URL
  • raw ETag, trace/span, backend error/details
  • File/Blob/stream/native handle
  • domain service, class instance, function, Promise와 AbortSignal

query profile은 caller가 raw option을 전달하는 대신 registry에서 선택한다.

ServerStateProfileV1
  profileId
  queryKeyCodecId
  scopePersistencePolicyId
  staleTimeMs
  gcTimeMs
  refetchOnFocus
  refetchOnReconnect
  networkMode
  maxResultBytes
  maxCollectionItems
  paginationProfileId | null
  revalidationProfileId | null
  invalidationTopicRefs[] = { topicId, topicVersion }
  placeholderPolicy
  owner

query key는 validated/canonical application input과 scope projection으로 만든다. REST URL, GraphQL document/hash, protobuf bytes와 generated message serialization은 query key가 아니다. transport 교체가 use-case identity를 바꾸지 않으면 같은 application query family를 유지할 수 있지만, old/new representation을 한 cache entry에 shadow write하지 않는다.

network retry는 transport adapter가 소유하고 Query retry는 기본 false다. refresh failure에서 유효한 previous data는 stale-degraded로 유지한다. schema, mapper, scope, authorization와 contract mismatch는 stale data를 계속 노출해도 되는지 query profile이 명시해야 하며 기본은 security-sensitive scope에서 즉시 숨김/clear다.

VD-13이 scope/persistence profile, normative key layout, account/session generation과 late-result fence를 소유한다. 이 문서는 그 profile을 exact join하고 operation/cache policy, pagination, revalidation과 mutation coherence를 소유한다.

14. Pagination과 conditional revalidation

cursor pagination은 다음 binding을 갖는다.

PaginationBinding
  query family fingerprint
  canonical filters/sort
  scope fingerprint
  server snapshot/revision policy
  page size ceiling
  opaque next cursor
  • cursor를 decode하거나 URL로 취급하지 않는다.
  • hasMore === (nextCursor !== null)을 codec에서 강제한다.
  • single-page cache는 runtime-scoped cursor fingerprint를 semantic key에 포함하고, infinite query만 cursor를 root key에서 제외해 bounded pageParam으로 둔다.
  • max pages/items/estimated bytes를 넘으면 더 불러오지 않는다.
  • 동일 cursor 반복, loop와 non-progress page를 contract failure로 닫는다.
  • offset pagination의 insert/delete drift를 자동 deduplicate로 숨기지 않는다.
  • page merge는 mapper가 보장한 stable identity가 있을 때만 deterministic하다.
  • previous filters의 page를 새 filter key에 재사용하지 않는다.

REST 304는 cached data가 있다는 뜻이 아니라 representation이 바뀌지 않았다는 transport 결과다. exact query fingerprint, scope/generation과 cached mapped value에 binding된 validator record가 모두 있을 때만 freshness를 갱신한다. cached value가 없거나 binding이 다르면 unconditional request를 한 번 수행하거나 closed failure로 끝낸다.

GraphQL persisted operation과 gRPC-Web unary는 기본적으로 application-level validator가 없다. backend가 revision을 제공하면 response schema/mapper가 opaque revision을 application revalidation policy로 투영해야 하며 HTTP/gRPC metadata를 임의로 ETag처럼 해석하지 않는다.

15. Mutation coherence

mutation과 query cache는 server commit authority가 아니다.

validate command
  -> derive logical key + exact command equality/opaque identity token
  -> runtime/scope coordinator applies concurrency + duplicate admission
  -> separately acquire invalidation-topic hint-coalescing lease
  -> cancel exact affected query reads
  -> capture bounded base cache revision and inverse patch
  -> install own ordered optimistic layer with revision CAS
  -> transport derives backend idempotency binding from operation policy
  -> execute command once with transport-owned retry policy
  -> success: registered exact seed/compare-and-apply + list/aggregate invalidation
  -> rejection: remove or invert only own layer with revision CAS
  -> uncertainty/CAS miss: preserve other commits + invalidate/authoritative refetch
  -> release invalidation lease + concurrency admission
  • duplicate submit 정책은 JOIN_IDENTICAL, REJECT_DUPLICATE, ALLOW_INDEPENDENT 중 operation별로 고정하고, 동일성은 전체 validated semantic input의 runtime-private exact equality guard와 opaque identity token으로 판정한다.
  • 같은 hook instance의 Promise dedupe를 server idempotency로 간주하지 않는다.
  • logical key/identity admission은 local ordering이고 invalidation-topic lease는 remote hint coalescing일 뿐이다. 둘 다 backend idempotency authority가 아니다.
  • optimistic patch는 raw DTO나 generated message를 만들지 않는다.
  • snapshot item/byte ceiling을 넘으면 optimistic update를 하지 않고 pending UX만 제공한다.
  • 409/GraphQL conflict code/gRPC ABORTED는 동일한 safe conflict vocabulary로 mapping하되 server revision과 merge policy는 feature use case가 소유한다.
  • server가 commit한 뒤 local invalidation 실패를 command 실패로 되돌리지 않는다. cache health를 degraded로 기록하고 bounded refetch/recovery를 예약한다.
  • command의 자동 protocol failover는 중복 side effect 위험 때문에 금지한다.

16. Server streaming과 cache

gRPC-Web server stream, GraphQL subscription과 incremental delivery는 ordinary queryFn과 다르다.

현재 installed API operation registry는 terminal REST operation만 소유한다. GraphQL HTTP와 gRPC-Web unary/server-stream은 각 reference adapter가 구현될 때 protocol discriminant와 전용 binding으로 확장한다. SSE, WebSocket과 Web Push는 VD-28 realtime registry가 소유하며 bounded polling은 registered terminal REST QUERY의 scheduling policy이지 새 protocol이나 automatic failover가 아니다. GraphQL @defer/@stream은 선택될 경우에도 한 HTTP operation의 finite incremental response이며 subscription과 같은 장기 realtime stream이 아니다.

ServerStreamPort
  open(frozen request, signal)
  -> AsyncIterable<Result<MappedEvent>>
  -> close()
  • frame/event마다 schema, mapper, scope와 generation을 재검증한다.
  • sequence, duplicate, gap과 resume token은 backend application protocol이다.
  • bounded queue, high-water mark, overflow, idle/total deadline을 선언한다.
  • stream event는 registered reducer로 immutable snapshot을 만들거나 query invalidation hint만 발행한다.
  • partial event를 ordinary query success로 cache하지 않는다.
  • stream 종료/재connect를 TanStack Query retry로 처리하지 않는다.

GraphQL subscription은 현재 NOT_SELECTED이고, gRPC-Web server-stream은 DESIGNED_NOT_IMPLEMENTED다.

gRPC-Web ServerStreamPort는 operation-bound outbound stream result일 수 있다. API adapter가 protobuf frame/message decode, semantic schema와 boundary mapper를 끝낸 뒤 제품이 runtime-wide notification projection을 명시적으로 선택한 branch에서만 mapped event를 VD-28 common coordinator/FeatureEventInput에 전달한다. protobuf를 REALTIME_EVENT_V1 JSON으로 감싸지 않고, 첫 event 전 opening replay와 이후 resume 규칙은 VD-27이 계속 소유한다.

17. Backend/provider 계약

구현 owner, 권장 topology, 현재 reference endpoint/envelope, idempotency store, Cursor/ETag/revision과 protocol별 handoff checklist는 Backend API와 Server State contract가 소유한다. 아래 표는 frontend 설계가 요구하는 경계 요약이다.

경계 backend/provider가 제공할 계약
공통 authorization, contract version/artifact compatibility, encoded transfer와 decoded payload의 bounded owner, stable error code, correlation/trace projection, idempotency와 rate-limit semantics
REST exact method/path/media/status/envelope, CSRF strategy, idempotency retention, cursor binding, ETag/If-None-Match 또는 revision, retry-safe status와 CORS/cache policy
GraphQL schema registry, persisted-operation manifest, allowlist/cost/depth enforcement, safe error extension vocabulary, operation retirement과 N/N-1 router rollout
Connect proto/descriptor/codegen source, exact Connect-Web runtime/encoding/method, EndStream/status/error, timeout/cancel/compression/CORS와 browser/server conformance
gRPC-Web proto/descriptor source, Buf/protoc compatibility policy, gRPC-Web proxy, exact service/method, message/frame ceiling, status/trailer/CORS exposure와 stream resume protocol
Protobuf REST Gateway selected gateway kind/version, HttpRule/ProtoJSON/OpenAPI artifact, path/query/body/status/error/header mapping, edge→upstream cancellation과 N/N-1 conformance
Schema authenticated source artifact, additive/breaking classification, deprecation window, fixtures and source digest
Mapper domain meaning, temporal/numeric/null/enum semantics와 stable identity
Cache revision/conflict/idempotency/invalidation semantics; frontend TTL은 authorization 대체가 아님

frontend가 제공하는 Zod schema, generated type과 cache invalidation은 backend authorization, validation, idempotency와 conflict resolution을 대체하지 않는다.

18. Security와 privacy

  • API base/GraphQL/Connect/gRPC-Web endpoint는 HTTPS registry ID로 고정한다.
  • caller가 URL, header, GraphQL document, service/method와 metadata를 제출하지 못한다.
  • auth owner가 credential을 붙이고 application/query/cache에는 token을 노출하지 않는다.
  • credential attachment 뒤 URL/method/origin/body digest와 registry-owned header binding을 재검증한다. auth integration unavailable 상태에서 request를 보내지 않는다.
  • cookie session의 unsafe request는 CSRF token/header 또는 same-site BFF 정책을 operation profile과 provider conformance로 증명한다.
  • GET/GraphQL variables에 sensitive filter를 넣는 operation은 별도 review 없이 만들지 않는다.
  • response byte/depth/node/string/collection/frame cap으로 resource exhaustion을 막는다.
  • GraphQL cost/depth와 gRPC message cap은 server/proxy에서도 강제한다.
  • mapper와 cache는 prototype/accessor/class/native object를 받아들이지 않는다.
  • PII/business ID를 query key, diagnostics label, persisted cache physical key에 직접 넣지 않는다. 필요한 identity는 opaque partition/token policy를 쓴다.
  • command identity token/logical mutation key는 runtime-local control data이며 diagnostics, cross-context wire와 persistence에 넣지 않는다.
  • raw request/response, GraphQL variables/errors, protobuf bytes/metadata, ETag, cursor, idempotency key와 validation value를 관측 데이터에 넣지 않는다.

19. Observability

허용된 bounded aggregate:

  • operation registry ID, protocol, semantics
  • outcome/error kind, HTTP status group 또는 gRPC status code allowlist
  • GraphQL full/partial/rejected outcome
  • attempt/deadline/duration/encoded-byte/result-item/frame bucket
  • schema/mapper profile ID와 compatibility outcome
  • query hit/miss/stale/refetch/eviction bucket
  • mutation optimistic/rollback/conflict/invalidation outcome
  • provider/browser/runtime version의 low-cardinality bucket

금지:

  • URL/path parameter/search/body/header
  • GraphQL document, variables, response path와 raw error message
  • protobuf message/metadata/trailer raw value
  • resource/account/tenant ID, cursor, validator, digest와 cache value

하나의 logical operation은 terminal observation 하나를 만든다. attempt span은 sampling된 내부 detail로만 남기며 terminal success/failure count를 중복시키지 않는다.

20. Failure와 fallback

실패 기본 결과
registry/schema/mapper 누락 network 전 fail-closed, operation traffic disable
incompatible contract artifact product mount 또는 해당 capability admission 차단
response cap/decode/schema mismatch body/reader cancel, cache write 금지, provider incompatibility
mapper violation cache write 금지, safe contract failure
REST retry exhaustion stale 허용 profile만 previous data 유지
GraphQL persisted operation missing full document fallback 금지, coherent artifact rollback
GraphQL partial data default reject; explicit profile만 completeness와 함께 사용
Connect missing/duplicate EndStream 또는 oversize whole body call cancel, cache write 금지, provider/runtime incompatible
gRPC-Web proxy/trailer mismatch reader cancel, provider unavailable/incompatible
REST Gateway HttpRule/OpenAPI/runtime drift affected route admission 차단, coherent gateway artifact rollback
server stream gap/overflow snapshot 폐기 또는 authoritative refetch
account/generation mismatch late result 폐기, old-scope cache write 금지
invalidation failure after commit command 성공 유지, cache degraded + recovery refetch

GraphQL, Connect 또는 gRPC-Web failure를 REST로 자동 전환하지 않는다. 사전에 등록된 read-only shadow/fallback operation이 있고 동일 authorization/mapper/result contract를 conformance suite로 증명한 경우만 selector가 새 logical query를 시작할 수 있다.

21. Rollout과 removal

ADR + registry schema accepted
  -> deterministic codec/schema/mapper fixture
  -> provider-neutral adapter and fake
  -> negative boundary/removal gate
  -> AVAILABLE_NOT_COMPOSED
  -> product/provider/operation selection
  -> bootstrap composition behind TrafficAdmission=DISABLED
  -> COMPOSED
  -> shadow/read-only conformance
  -> browser/provider/operations evidence
  -> PromotionEvidence=COMPLETE
  -> CANARY
  -> ENABLED

REST v2 local baseline은 installed reference operation에 연결됐다. 실제 provider traffic은 operation/profile 단위의 conformance와 canary를 거쳐야 하며, conditional/pagination은 backend 계약 없이 enabled하지 않는다. GraphQL/Connect/gRPC-Web/codegen/gateway dependency는 실제 selected operation이 없으면 production inventory에 없어야 한다.

removal:

  1. 신규 operation admission을 닫는다.
  2. query는 cancel하고 command/stream은 bounded drain 또는 explicit abort한다.
  3. 해당 invalidation listener, auth attachment와 provider를 close한다.
  4. current scope의 mapped memory cache를 clear한다.
  5. operation/schema/mapper/query profile과 generated artifact를 제거한다.
  6. dependency, config, proxy route, test fixture와 production module inventory가 함께 제거됐음을 증명한다.
  7. backend persisted-operation/method retirement은 N/N-1 client window 뒤에 한다.

22. Test와 promotion evidence

Deterministic

  • operation registry closed union/reference/orphan/duplicate
  • request canonicalization과 query-key identity
  • timeout/total deadline/retry/idempotency/auth recovery
  • response byte/depth/node/collection cap
  • schema unknown-field, scalar, null/enum/numeric/date matrix
  • mapper success/failure/no raw value leakage
  • query stale/gc/refetch/pagination/mutation/rollback/generation fence

Contract

  • REST OpenAPI/envelope/status/media/cursor/conditional/idempotency
  • GraphQL schema + persisted manifest + variables/result/error/partial policy
  • proto descriptor + breaking check + gRPC status/trailer/frame fixture
  • Connect unary/stream JSON/binary/GET/EndStream/CORS/deadline fixture
  • HttpRule route manifest + ProtoJSON/OpenAPI/status/error/header mapping fixture
  • 같은 fixture를 fake, emulator/staging과 actual provider에 실행

Browser/integration

  • bootstrap → feature → transport → schema → mapper → Query → UI
  • AbortSignal/navigation/logout/account switch
  • CORS/cookie/CSRF/redirect/content-encoding
  • HTTP/2/proxy/CDN/Connect EndStream/gRPC-Web trailer behavior
  • offline/reconnect/focus와 stale-degraded UI

Fault

  • truncated/oversize/malformed response
  • slow credential/network/body/schema/mapper phase
  • 401 recovery, 429, retry exhaustion과 total deadline
  • GraphQL partial/error/persisted-operation drift
  • Connect missing/early/duplicate EndStream, whole-body overflow와 compression mismatch
  • gRPC missing/conflicting terminal status source, corrupt/compressed/oversize frame와 stream gap
  • REST Gateway route/OpenAPI/runtime rewrite drift와 abort propagation loss
  • late response, duplicate mutation, optimistic rollback과 invalidation failure

Operations

  • operation kill switch
  • contract artifact N/N-1 rollout과 rollback
  • provider incompatibility containment
  • cache scope reset와 stale-data decision
  • generated client/GraphQL/Connect/gRPC-Web/REST Gateway removal drill

fake와 generated compile success만으로 actual provider, browser나 operations evidence를 COMPLETE로 표시하지 않는다.

23. 설계 우선 work package

package 목표
API-01 REST v2 operation registry, total deadline, bounded decoder와 conditional/pagination contract
API-02 multi-protocol schema artifact/digest governance와 typed Mapper result
API-03 strict ServerStateProfile, query-key codec, pagination/revalidation와 mutation policy
API-04 persisted-operation-only GraphQL reference adapter와 conformance harness
API-05 gRPC-Web unary/server-stream reference adapter와 proxy harness
API-06 Connect-Web unary/server-stream reference adapter와 provider harness
API-07 Protobuf governance와 selected REST Gateway conformance
API-08 atomic composition, readiness, kill switch, runbook와 provider/browser evidence

권장 순서는 API-01 → API-02 → API-03이다. API-04~07은 제품 선택과 backend/provider 계약이 생긴 branch만 독립적으로 시작한다. GraphQL, Connect, gRPC-Web과 REST Gateway를 “미래 대비” 목적으로 모두 기본 bundle에 설치하지 않는다.

24. 완료 기준

  • 모든 installed operation은 protocol/schema/mapper/cache/error/deadline owner가 있다.
  • application/presentation public type에 DTO, GraphQL SDK와 generated protobuf가 없다.
  • untrusted byte부터 mapped projection까지 모든 ceiling과 trust transition이 닫혀 있다.
  • query key와 실제 request input이 동일 canonical source에서 파생된다.
  • transport retry와 Query retry가 중복되지 않는다.
  • command idempotency, optimistic patch와 conflict/invalidation owner가 명시돼 있다.
  • account/logout/release generation 뒤 late result가 cache에 들어가지 않는다.
  • actual REST/GraphQL/Connect/gRPC-Web/Gateway provider에 같은 semantic conformance fixture를 실행한다.
  • contract drift, kill switch, rollback과 optional dependency removal drill이 통과한다.
  • raw payload/URL/document/message/metadata/validator가 log와 cache에 없다.
  • COMPOSED와 production-ready/provider-conformant를 같은 의미로 쓰지 않는다.

25. 관련 문서