chore: initialize from backend template 0a6dd0e

This commit is contained in:
DongHyeonka
2026-08-13 20:31:02 +09:00
commit e64e701fe5
3223 changed files with 388401 additions and 0 deletions
+120
View File
@@ -0,0 +1,120 @@
# Registry: Repository Access Capabilities
# SSOT: wiki/projects/ca-tmpl/registries/capabilities.yaml
# Schema owner: feature-contract-registry-governance
# Owner branch: feature-repository-access-permission-contract
# Last updated: 2026-06-05
#
# Notes
# - capability는 사용자 권한이 아니라 application use case가 infrastructure capability를
# 사용할 수 있는지에 대한 계약 (feature-repository-access-permission-contract).
# - enforcement default = ArchUnit annotation-based rule. compile-time annotation processor는
# alternative. runtime AOP는 forbidden.
# - capability 제거는 항상 breaking change. 추가는 additive (registry row 동반 시).
# - annotation 표기 (as-built, F1/F2 reconciled 2026-06-05): 코드 SSOT는 단일
# `@UseCaseCapability` (TYPE target, typed attribute). 노트 D2/D11의 flat
# `@UseCaseRepositoryAccess(Capability[])` 모델은 superseded. 7 capability ↔ as-built 매핑:
# READ_REPOSITORY/WRITE_REPOSITORY → repositoryAccess, TRANSACTION_REQUIRED → transactionMode,
# EXTERNAL_OUTBOUND_ALLOWED → externalOutboundAllowed, SENSITIVE_READ → sensitiveRead,
# BULK_WRITE → bulkWrite, CROSS_TENANT_ADMIN → crossTenantAdmin.
# 각 row의 annotation: 필드는 아래에서 as-built 표기로 정합됨.
capabilities:
# source: feature-repository-access-permission-contract — 판정 기준 "Required capability: READ_REPOSITORY"
# source: feature-application-port-usecase-contract — "read-only query use case는 readOnly 와 READ_REPOSITORY capability만 선언 가능"
- name: READ_REPOSITORY
scope: use_case_method
enforcement: archunit
annotation: "@UseCaseCapability(repositoryAccess = READ_REPOSITORY)"
semantics: "use case가 read-only repository operation을 호출하는 것을 허용. query use case의 기본 capability. write/sensitive/bulk 작업은 별도 capability 선언이 없으면 forbidden."
owner_branch: feature-repository-access-permission-contract
bound_to_capability: null
threshold: null
compatibility_impact: breaking
required_test: architecture-enforcement:read-repository-capability
# source: feature-repository-access-permission-contract — 판정 기준 "Required capability: WRITE_REPOSITORY"
# source: feature-application-port-usecase-contract — "write use case는 transactionMode, idempotency, repositoryAccess를 명시해야 함"
- name: WRITE_REPOSITORY
scope: use_case_method
enforcement: archunit
annotation: "@UseCaseCapability(repositoryAccess = WRITE_REPOSITORY)"
semantics: "use case가 mutating repository operation(insert/update/delete)을 호출하는 것을 허용. 단일/소량 write 기준이며 batch size > 100은 BULK_WRITE 별도 선언 필요. read-only use case에서 이 capability 없이 write repository 접근하면 fail."
owner_branch: feature-repository-access-permission-contract
bound_to_capability: null
threshold: null
compatibility_impact: breaking
required_test: architecture-enforcement:write-repository-capability
# source: feature-repository-access-permission-contract — decisions 2026-05-22
# "SENSITIVE_READ marker = registry-managed metadata table (entity FQN + field name 단위)"
- name: SENSITIVE_READ
scope: use_case_method
enforcement: archunit
annotation: "@UseCaseCapability(sensitiveRead = true)"
semantics: "PII/credential 등 sensitive field를 읽는 use case가 선언해야 하는 capability. marker는 registry-managed metadata table(entity FQN + field name 단위)에서 lookup. domain annotation 또는 JPA entity annotation 형태는 forbidden(domain에 framework 의존 회피). pseudonymized data read는 documented 시에만 예외 허용."
owner_branch: feature-repository-access-permission-contract
bound_to_capability: null
threshold: null
compatibility_impact: breaking
required_test: architecture-enforcement:sensitive-read-capability
# source: feature-repository-access-permission-contract — decisions 2026-05-22
# "BULK_WRITE threshold = N > 100 또는 batch size > 100. 미만은 일반 WRITE_REPOSITORY로 충분"
- name: BULK_WRITE
scope: use_case_method
enforcement: archunit
annotation: "@UseCaseCapability(bulkWrite = true)"
semantics: "단일 transaction 내 N > 100 또는 batch size > 100 mutating operation을 수행하는 use case가 선언해야 하는 capability. 이 미만이면 일반 WRITE_REPOSITORY로 충분. lock 점유 시간, pool 영향, retry 비용이 큰 작업을 명시화."
owner_branch: feature-repository-access-permission-contract
bound_to_capability: WRITE_REPOSITORY
threshold: 100
compatibility_impact: breaking
required_test: architecture-enforcement:bulk-write-capability
# source: feature-repository-access-permission-contract — decisions 2026-05-22
# "TRANSACTION_REQUIRED는 application-port branch의 TransactionPort contract와 연결되어야 하며 Spring @Transactional 직접 import로 충족하지 않음"
# source: feature-application-port-usecase-contract — TransactionPort Contract
- name: TRANSACTION_REQUIRED
scope: use_case_method
enforcement: archunit
annotation: "@UseCaseCapability(transactionMode = WRITE | READ_ONLY | REQUIRES_NEW)"
semantics: "use case가 TransactionPort(또는 TransactionalUseCaseRunner)를 통해 transactional boundary를 갖는 것을 강제. Spring @Transactional의 application package 직접 import는 forbidden. infrastructure가 Spring transaction implementation을 제공하고 application은 port만 호출."
owner_branch: feature-repository-access-permission-contract
bound_to_capability: null
threshold: null
compatibility_impact: breaking
required_test: architecture-enforcement:transaction-required-capability
# source: feature-repository-access-permission-contract — decisions 2026-05-22
# "EXTERNAL_OUTBOUND_ALLOWED 분류 = outbox row INSERT는 in-process(불요), polling publisher의 broker publish는 outbound(필요)"
# source: feature-application-port-usecase-contract — "outbound adapter 호출 use case에 EXTERNAL_OUTBOUND_ALLOWED가 없으면 실패"
- name: EXTERNAL_OUTBOUND_ALLOWED
scope: use_case_method
enforcement: archunit
annotation: "@UseCaseCapability(externalOutboundAllowed = true)"
semantics: "use case가 외부 HTTP/message broker로 outbound 호출을 발생시키는 것을 허용. outbox claim 분류: outbox row INSERT는 in-process이므로 본 capability 불요. polling publisher의 broker publish는 outbound이므로 필요. domain event without transport detail은 outbound 호출이 아니므로 별도 분류."
owner_branch: feature-repository-access-permission-contract
bound_to_capability: null
threshold: null
compatibility_impact: breaking
required_test: architecture-enforcement:external-outbound-capability
# source: feature-repository-access-permission-contract — decisions 2026-05-22
# "CROSS_TENANT_ADMIN capability를 capability vocabulary에 추가 (tenant branch feature-tenant-context-policy와 cross-link)"
- name: CROSS_TENANT_ADMIN
scope: use_case_method
enforcement: archunit
annotation: "@UseCaseCapability(crossTenantAdmin = true)"
semantics: "tenant 경계를 넘어 데이터에 접근/변경하는 admin use case가 선언해야 하는 capability. tenant-context-policy의 cross-tenant 정책과 cross-link되어야 하며, 단일 tenant 범위 use case에서 이 capability를 선언하면 review에서 reject. SENSITIVE_READ가 동반될 가능성이 높지만 자동 결합은 아님."
owner_branch: feature-repository-access-permission-contract
bound_to_capability: null
threshold: null
compatibility_impact: breaking
required_test: architecture-enforcement:cross-tenant-admin-capability
# Row count verification
# - feature-repository-access-permission-contract 판정 기준 "Required capability" 표에 명시된 7개:
# READ_REPOSITORY, WRITE_REPOSITORY, SENSITIVE_READ, BULK_WRITE, TRANSACTION_REQUIRED,
# EXTERNAL_OUTBOUND_ALLOWED, CROSS_TENANT_ADMIN.
# - source에 명시되지 않은 capability는 본 registry에 추가하지 않음 (추측 금지).
File diff suppressed because it is too large Load Diff
+918
View File
@@ -0,0 +1,918 @@
# Registry: Error Codes
# SSOT: wiki/projects/ca-tmpl/registries/error-codes.yaml
# Schema owner: feature-contract-registry-governance
# Category enum owner: feature-operational-error-observability-foundation
# Last updated: 2026-05-22
# Note: 이 파일은 Phase B 산출물. Phase C2(ca-tmpl 실 코드)에서 generated Java constants의 source.
#
# Schema (per row):
# code: UPPER_SNAKE_CASE
# category: VALIDATION | AUTH | AUTHZ | NOT_FOUND | CONFLICT |
# RATE_LIMIT | TRANSIENT_DEPENDENCY | PERMANENT_DEPENDENCY |
# DATA_INTEGRITY | INTERNAL
# http_status: int (async-only failures use 500 placeholder)
# retryable: bool
# retry_after_seconds: int | null (RATE_LIMIT/TRANSIENT 권고 backoff)
# owner_branch: source branch (raw/branch-notes/feature-*.md)
# owner_layer: presentation | application | domain | infrastructure | crosscut
# client_safe_message: no token / no principal raw / no internal path / no stack trace
# log_level: ERROR | WARN | INFO
# runbook_link: runbook://area/scenario OR null (client-error만 null 허용)
# compatibility_impact: none | additive | behavior-change | breaking
# required_test: owning contract test identifier
#
# Runbook policy (operational-runbook-contract L80):
# retryable=false + category ∈ {AUTH, AUTHZ, RATE_LIMIT, INTERNAL,
# TRANSIENT_DEPENDENCY, PERMANENT_DEPENDENCY} ⇒ runbook_link 필수.
# VALIDATION/NOT_FOUND/CONFLICT/DATA_INTEGRITY는 client-error로 runbook 면제 가능.
# retryable=true 인 모든 row는 runbook_link 필수.
errors:
# ============================================================
# AUTH (feature-security-operational-baseline / Decision Matrix)
# ============================================================
# source: feature-security-operational-baseline L82 — "token 누락 | 401 | AUTH_TOKEN_MISSING | AUTH"
- code: AUTH_TOKEN_MISSING
category: AUTH
http_status: 401
retryable: false
retry_after_seconds: null
owner_branch: feature-security-operational-baseline
owner_layer: presentation
client_safe_message: "Authentication required"
log_level: WARN
runbook_link: "runbook://auth/token-missing"
compatibility_impact: none
required_test: contract-verification:auth-category
# source: feature-security-operational-baseline L83 — "token malformed (parse fail) | 401 | AUTH_TOKEN_MALFORMED | AUTH"
- code: AUTH_TOKEN_MALFORMED
category: AUTH
http_status: 401
retryable: false
retry_after_seconds: null
owner_branch: feature-security-operational-baseline
owner_layer: presentation
client_safe_message: "Authentication failed"
log_level: WARN
runbook_link: "runbook://auth/token-malformed"
compatibility_impact: none
required_test: contract-verification:auth-category
# source: feature-security-operational-baseline L84 — "token expired (clock skew tolerance 60s 초과) | 401 | AUTH_TOKEN_EXPIRED | AUTH"
- code: AUTH_TOKEN_EXPIRED
category: AUTH
http_status: 401
retryable: false
retry_after_seconds: null
owner_branch: feature-security-operational-baseline
owner_layer: presentation
client_safe_message: "Authentication expired"
log_level: WARN
runbook_link: "runbook://auth/token-expired"
compatibility_impact: none
required_test: contract-verification:auth-category
# source: feature-security-operational-baseline L85 — "invalid signature | 401 | AUTH_TOKEN_INVALID_SIGNATURE | AUTH"
- code: AUTH_TOKEN_INVALID_SIGNATURE
category: AUTH
http_status: 401
retryable: false
retry_after_seconds: null
owner_branch: feature-security-operational-baseline
owner_layer: presentation
client_safe_message: "Authentication failed"
log_level: ERROR
runbook_link: "runbook://auth/token-invalid-signature"
compatibility_impact: none
required_test: contract-verification:auth-category
# source: feature-security-operational-baseline L86 — "issuer mismatch | 401 | AUTH_ISSUER_MISMATCH | AUTH"
- code: AUTH_ISSUER_MISMATCH
category: AUTH
http_status: 401
retryable: false
retry_after_seconds: null
owner_branch: feature-security-operational-baseline
owner_layer: presentation
client_safe_message: "Authentication failed"
log_level: ERROR
runbook_link: "runbook://auth/issuer-mismatch"
compatibility_impact: none
required_test: contract-verification:auth-category
# source: feature-security-operational-baseline L87 — "audience mismatch | 401 | AUTH_AUDIENCE_MISMATCH | AUTH"
- code: AUTH_AUDIENCE_MISMATCH
category: AUTH
http_status: 401
retryable: false
retry_after_seconds: null
owner_branch: feature-security-operational-baseline
owner_layer: presentation
client_safe_message: "Authentication failed"
log_level: ERROR
runbook_link: "runbook://auth/audience-mismatch"
compatibility_impact: none
required_test: contract-verification:auth-category
# source: feature-security-operational-baseline L88 — "unknown kid (JWKS 미캐시) | 401 + Retry-After 5s | AUTH_KID_UNKNOWN | AUTH"
- code: AUTH_KID_UNKNOWN
category: AUTH
http_status: 401
retryable: true # 2026-06-01: false→true. JWKS 키 회전 중 unknown kid 는 ~5s 후 JWKS refresh 로 해소 가능(transient). retry_after_seconds=5 + client_safe_message "please retry" 와 정합. 키 고정 정책으로 전환 시 false 복귀.
retry_after_seconds: 5
owner_branch: feature-security-operational-baseline
owner_layer: presentation
client_safe_message: "Authentication failed, please retry"
log_level: WARN
runbook_link: "runbook://auth/kid-unknown"
compatibility_impact: none
required_test: contract-verification:auth-category
# source: feature-security-operational-baseline L89 — "JWKS endpoint outage ... | AUTH_JWKS_UNAVAILABLE | TRANSIENT_DEPENDENCY"
- code: AUTH_JWKS_UNAVAILABLE
category: TRANSIENT_DEPENDENCY
http_status: 503
retryable: true
retry_after_seconds: 30
owner_branch: feature-security-operational-baseline
owner_layer: infrastructure
client_safe_message: "Authentication service temporarily unavailable"
log_level: ERROR
runbook_link: "runbook://auth/jwks-unavailable"
compatibility_impact: none
required_test: contract-verification:auth-category
# source: feature-security-operational-baseline L90 — "claim mapping failure ... | 401 | AUTH_CLAIM_MAPPING_FAILED | AUTH"
- code: AUTH_CLAIM_MAPPING_FAILED
category: AUTH
http_status: 401
retryable: false
retry_after_seconds: null
owner_branch: feature-security-operational-baseline
owner_layer: presentation
client_safe_message: "Authentication failed"
log_level: ERROR
runbook_link: "runbook://auth/claim-mapping-failed"
compatibility_impact: none
required_test: contract-verification:auth-category
# ============================================================
# AUTHZ (feature-security-operational-baseline)
# ============================================================
# source: feature-security-operational-baseline L91 — "valid token + 권한 부족 | 403 | AUTHZ_INSUFFICIENT_PERMISSION | AUTHZ"
- code: AUTHZ_INSUFFICIENT_PERMISSION
category: AUTHZ
http_status: 403
retryable: false
retry_after_seconds: null
owner_branch: feature-security-operational-baseline
owner_layer: presentation
client_safe_message: "Permission denied"
log_level: WARN
runbook_link: "runbook://authz/insufficient-permission"
compatibility_impact: none
required_test: contract-verification:authz-category
# source: feature-security-operational-baseline L92 — "valid token + tenant cross-access | 403 | AUTHZ_TENANT_MISMATCH | AUTHZ"
- code: AUTHZ_TENANT_MISMATCH
category: AUTHZ
http_status: 403
retryable: false
retry_after_seconds: null
owner_branch: feature-security-operational-baseline
owner_layer: presentation
client_safe_message: "Permission denied"
log_level: ERROR
runbook_link: "runbook://authz/tenant-mismatch"
compatibility_impact: none
required_test: contract-verification:authz-category
# ============================================================
# INTERNAL (feature-security-operational-baseline + container-runtime)
# ============================================================
# source: feature-security-operational-baseline L93 — "public path misconfiguration ... | 500 + P1 alert | INTERNAL_AUTH_MISCONFIGURATION | INTERNAL"
- code: INTERNAL_AUTH_MISCONFIGURATION
category: INTERNAL
http_status: 500
retryable: false
retry_after_seconds: null
owner_branch: feature-security-operational-baseline
owner_layer: crosscut
client_safe_message: "Internal server error"
log_level: ERROR
runbook_link: "runbook://auth/public-path-misconfiguration"
compatibility_impact: none
required_test: contract-verification:auth-category
# source: feature-container-runtime-contract L113 — "JVM OutOfMemoryError → ExitOnOutOfMemoryError로 137 exit, log에 error.code=JVM_OOM 명시"
- code: JVM_OOM
category: INTERNAL
http_status: 500
retryable: false
retry_after_seconds: null
owner_branch: feature-container-runtime-contract
owner_layer: infrastructure
client_safe_message: "Internal server error"
log_level: ERROR
runbook_link: "runbook://runtime/jvm-oom"
compatibility_impact: none
required_test: contract-verification:container-runtime-oom
# ============================================================
# DB / Persistence (feature-persistence-failure-baseline / SQLState Matrix)
# ============================================================
# source: feature-persistence-failure-baseline L85 — "08* | all | TRANSIENT_DEPENDENCY | DB_UNAVAILABLE | true"
- code: DB_UNAVAILABLE
category: TRANSIENT_DEPENDENCY
http_status: 503
retryable: true
retry_after_seconds: 5
owner_branch: feature-persistence-failure-baseline
owner_layer: infrastructure
client_safe_message: "Service temporarily unavailable"
log_level: ERROR
runbook_link: "runbook://db/unavailable"
compatibility_impact: none
required_test: contract-verification:persistence-mapping
# source: feature-persistence-failure-baseline L86 — "40001 | Postgres/MySQL | CONFLICT | DB_SERIALIZATION_FAILURE | true"
- code: DB_SERIALIZATION_FAILURE
category: CONFLICT
http_status: 409
retryable: true
retry_after_seconds: 1
owner_branch: feature-persistence-failure-baseline
owner_layer: infrastructure
client_safe_message: "Request conflicted with another transaction, please retry"
log_level: WARN
runbook_link: "runbook://db/serialization-failure"
compatibility_impact: none
required_test: contract-verification:persistence-mapping
# source: feature-persistence-failure-baseline L87 — "40P01 | Postgres | CONFLICT | DB_DEADLOCK | true (backoff)"
- code: DB_DEADLOCK
category: CONFLICT
http_status: 409
retryable: true
retry_after_seconds: 1
owner_branch: feature-persistence-failure-baseline
owner_layer: infrastructure
client_safe_message: "Request conflicted, please retry"
log_level: WARN
runbook_link: "runbook://db/deadlock"
compatibility_impact: none
required_test: contract-verification:persistence-mapping
# source: feature-persistence-failure-baseline L88 — "23502 | Postgres | DATA_INTEGRITY | DB_NULL_VIOLATION | false"
- code: DB_NULL_VIOLATION
category: DATA_INTEGRITY
http_status: 409
retryable: false
retry_after_seconds: null
owner_branch: feature-persistence-failure-baseline
owner_layer: infrastructure
client_safe_message: "Request violates a required field constraint"
log_level: WARN
runbook_link: null
compatibility_impact: none
required_test: contract-verification:persistence-mapping
# source: feature-persistence-failure-baseline L89 — "23503 | Postgres | DATA_INTEGRITY | DB_FK_VIOLATION | false"
- code: DB_FK_VIOLATION
category: DATA_INTEGRITY
http_status: 409
retryable: false
retry_after_seconds: null
owner_branch: feature-persistence-failure-baseline
owner_layer: infrastructure
client_safe_message: "Request references missing resource"
log_level: WARN
runbook_link: null
compatibility_impact: none
required_test: contract-verification:persistence-mapping
# source: feature-persistence-failure-baseline L90 — "23505 | Postgres | CONFLICT | DB_UNIQUE_VIOLATION | false (business mapping)"
- code: DB_UNIQUE_VIOLATION
category: CONFLICT
http_status: 409
retryable: false
retry_after_seconds: null
owner_branch: feature-persistence-failure-baseline
owner_layer: infrastructure
client_safe_message: "Resource already exists"
log_level: WARN
runbook_link: null
compatibility_impact: none
required_test: contract-verification:persistence-mapping
# source: feature-persistence-failure-baseline L91 — "23514 | Postgres | DATA_INTEGRITY | DB_CHECK_VIOLATION | false"
- code: DB_CHECK_VIOLATION
category: DATA_INTEGRITY
http_status: 409
retryable: false
retry_after_seconds: null
owner_branch: feature-persistence-failure-baseline
owner_layer: infrastructure
client_safe_message: "Request violates a value constraint"
log_level: WARN
runbook_link: null
compatibility_impact: none
required_test: contract-verification:persistence-mapping
# source: feature-persistence-failure-baseline L92 — "25P03 | Postgres | TRANSIENT_DEPENDENCY | DB_IDLE_IN_TX_TIMEOUT | true"
- code: DB_IDLE_IN_TX_TIMEOUT
category: TRANSIENT_DEPENDENCY
http_status: 503
retryable: true
retry_after_seconds: 2
owner_branch: feature-persistence-failure-baseline
owner_layer: infrastructure
client_safe_message: "Service temporarily unavailable"
log_level: ERROR
runbook_link: "runbook://db/idle-in-tx-timeout"
compatibility_impact: none
required_test: contract-verification:persistence-mapping
# source: feature-persistence-failure-baseline L93 — "57014 | Postgres | TRANSIENT_DEPENDENCY | DB_QUERY_CANCELED | false"
- code: DB_QUERY_CANCELED
category: TRANSIENT_DEPENDENCY
http_status: 503
retryable: false
retry_after_seconds: null
owner_branch: feature-persistence-failure-baseline
owner_layer: infrastructure
client_safe_message: "Request was canceled, please retry later"
log_level: WARN
runbook_link: "runbook://db/query-canceled"
compatibility_impact: none
required_test: contract-verification:persistence-mapping
# ============================================================
# Rate limit / Idempotency (feature-rate-limit-idempotency-contract)
# ============================================================
# source: feature-rate-limit-idempotency-contract — rate limit response/log 기준 / Retry-After header 기준 (scope L29, L33)
- code: RATE_LIMIT_EXCEEDED
category: RATE_LIMIT
http_status: 429
retryable: true
retry_after_seconds: 1
owner_branch: feature-rate-limit-idempotency-contract
owner_layer: presentation
client_safe_message: "Too many requests, please retry after the indicated interval"
log_level: WARN
runbook_link: "runbook://rate-limit/exceeded"
compatibility_impact: none
required_test: contract-verification:rate-limit
# source: feature-rate-limit-idempotency-contract L71 — "200ms 초과 시 409 IDEMPOTENT_IN_FLIGHT (retryable=false, client는 polling)"
- code: IDEMPOTENT_IN_FLIGHT
category: CONFLICT
http_status: 409
retryable: false
retry_after_seconds: null
owner_branch: feature-rate-limit-idempotency-contract
owner_layer: application
client_safe_message: "A previous identical request is still being processed, please poll for result"
log_level: INFO
runbook_link: null
compatibility_impact: none
required_test: contract-verification:idempotency
# source: feature-rate-limit-idempotency-contract L72 — "fingerprint mismatch (same key + different body) = 422 IDEMPOTENT_REQUEST_MISMATCH"
- code: IDEMPOTENT_REQUEST_MISMATCH
category: VALIDATION
http_status: 422
retryable: false
retry_after_seconds: null
owner_branch: feature-rate-limit-idempotency-contract
owner_layer: application
client_safe_message: "Idempotency key reused with different request body"
log_level: WARN
runbook_link: null
compatibility_impact: none
required_test: contract-verification:idempotency
# ============================================================
# File / Resource (feature-file-resource-handling-contract)
# ============================================================
# source: feature-file-resource-handling-contract L69 — "spring.servlet.multipart.max-file-size 10MB ... Spring 단의 enforcement가 실패 시 envelope 응답 보장" / 테스트 계약 "oversized upload가 generic 500으로 처리되면 실패"
- code: UPLOAD_SIZE_EXCEEDED
category: VALIDATION
http_status: 413
retryable: false
retry_after_seconds: null
owner_branch: feature-file-resource-handling-contract
owner_layer: presentation
client_safe_message: "Uploaded file exceeds maximum size"
log_level: WARN
runbook_link: null
compatibility_impact: none
required_test: contract-verification:file-upload
# source: feature-file-resource-handling-contract L72 — "allowed content-type allowlist starting set ..."
- code: UPLOAD_CONTENT_TYPE_REJECTED
category: VALIDATION
http_status: 415
retryable: false
retry_after_seconds: null
owner_branch: feature-file-resource-handling-contract
owner_layer: presentation
client_safe_message: "Uploaded content type is not allowed"
log_level: WARN
runbook_link: null
compatibility_impact: none
required_test: contract-verification:file-upload
# source: feature-file-resource-handling-contract — Decisionized Work Items "path traversal | normalized storage key only ... | traversal test"
- code: PATH_TRAVERSAL_DETECTED
category: VALIDATION
http_status: 400
retryable: false
retry_after_seconds: null
owner_branch: feature-file-resource-handling-contract
owner_layer: presentation
client_safe_message: "Invalid file path"
log_level: ERROR
runbook_link: null
compatibility_impact: none
required_test: contract-verification:file-upload
# source: feature-file-resource-handling-contract L73 — "streaming download backpressure = response timeout 60s, max stream 100MB. 초과 시 truncate + ERROR log"
- code: DOWNLOAD_STREAMING_FAILURE
category: TRANSIENT_DEPENDENCY
http_status: 503
retryable: true
retry_after_seconds: 5
owner_branch: feature-file-resource-handling-contract
owner_layer: presentation
client_safe_message: "Download failed, please retry"
log_level: ERROR
runbook_link: "runbook://file/download-streaming-failure"
compatibility_impact: none
required_test: contract-verification:file-download
# ============================================================
# API contract transport-standard codes (feature-api-contract-baseline)
# ============================================================
# NOTE: feature-api-contract-baseline owns the transport-shape failure
# classification (D8 413/414, D9 406/415, D12 405, D15 412). These rows mirror
# dev.caskeleton.shared.error.OperationalError; the D11 status-mapping
# consistency test (owner: this branch, producer) fails the build when a code's
# registry http_status and the enum httpStatus() drift apart.
# source: feature-api-contract-baseline.md D12 — "405 Method Not Allowed + Allow header 의무"
- code: METHOD_NOT_ALLOWED
category: VALIDATION
http_status: 405
retryable: false
retry_after_seconds: null
owner_branch: feature-api-contract-baseline
owner_layer: presentation
client_safe_message: "HTTP method not allowed for this resource"
log_level: INFO
runbook_link: null
compatibility_impact: none
required_test: contract-verification:api-contract-status-mapping
# source: feature-api-contract-baseline.md D9 — "406 Not Acceptable = 응답 표현 협상 실패"
- code: NOT_ACCEPTABLE
category: VALIDATION
http_status: 406
retryable: false
retry_after_seconds: null
owner_branch: feature-api-contract-baseline
owner_layer: presentation
client_safe_message: "No acceptable representation for the requested Accept header"
log_level: INFO
runbook_link: null
compatibility_impact: none
required_test: contract-verification:api-contract-status-mapping
# source: feature-api-contract-baseline.md D15 — "If-Match mismatch 시 412 Precondition Failed"
- code: PRECONDITION_FAILED
category: CONFLICT
http_status: 412
retryable: false
retry_after_seconds: null
owner_branch: feature-api-contract-baseline
owner_layer: presentation
client_safe_message: "Resource was modified by another request; refetch and retry"
log_level: INFO
runbook_link: null
compatibility_impact: none
required_test: contract-verification:api-contract-status-mapping
# source: feature-api-contract-baseline.md D8 — "request size limit 실패 분류 (413)"
- code: PAYLOAD_TOO_LARGE
category: VALIDATION
http_status: 413
retryable: false
retry_after_seconds: null
owner_branch: feature-api-contract-baseline
owner_layer: presentation
client_safe_message: "Request payload is too large"
log_level: WARN
runbook_link: null
compatibility_impact: none
required_test: contract-verification:api-contract-status-mapping
# source: feature-api-contract-baseline.md D8 형제 — "URI 길이 실패 분류 (414)"
# NOTE: enforcement is Tomcat/gateway-owned (rejected before Spring dispatch);
# this row + code exist for status-mapping consistency. End-to-end 414 contract
# test is `planned` (gateway/Tomcat maxHttpHeaderSize 8KB boundary).
- code: URI_TOO_LONG
category: VALIDATION
http_status: 414
retryable: false
retry_after_seconds: null
owner_branch: feature-api-contract-baseline
owner_layer: presentation
client_safe_message: "Request URI is too long"
log_level: WARN
runbook_link: null
compatibility_impact: none
required_test: contract-verification:api-contract-status-mapping
# source: feature-api-contract-baseline.md D9 — "415 Unsupported Media Type = 요청 본문 format 미지원"
- code: UNSUPPORTED_MEDIA_TYPE
category: VALIDATION
http_status: 415
retryable: false
retry_after_seconds: null
owner_branch: feature-api-contract-baseline
owner_layer: presentation
client_safe_message: "Request Content-Type is not supported"
log_level: INFO
runbook_link: null
compatibility_impact: none
required_test: contract-verification:api-contract-status-mapping
# ============================================================
# Tenant (feature-tenant-context-policy)
# ============================================================
# source: feature-tenant-context-policy L71 — "tenant 미지원 모드에서 X-Tenant-Id 헤더 수신 시 400 TENANT_NOT_SUPPORTED (filter 단계)"
- code: TENANT_NOT_SUPPORTED
category: VALIDATION
http_status: 400
retryable: false
retry_after_seconds: null
owner_branch: feature-tenant-context-policy
owner_layer: presentation
client_safe_message: "Tenant context is not supported by this deployment"
log_level: WARN
runbook_link: null
compatibility_impact: none
required_test: contract-verification:tenant-policy
# ============================================================
# Validation / Business rule (feature-business-rule-validation-contract)
# ============================================================
# NOTE: business-rule-validation branch는 mapping 규칙 SSOT (syntax→VALIDATION,
# policy→AUTHZ/CONFLICT, invariant→CONFLICT/VALIDATION, persistence→PERSISTENCE/CONFLICT)
# 이며 구체 code는 example로 VALIDATION_EMAIL_FORMAT만 등장
# (feature-operational-error-observability-foundation L110). 실제 도메인별 code는
# Phase D(도메인 feature 적용) 시 본 registry에 추가.
# source: feature-operational-error-observability-foundation L110 — "code: VALIDATION_EMAIL_FORMAT, // registry-registered code" (validation field error JSON shape example)
- code: VALIDATION_EMAIL_FORMAT
category: VALIDATION
http_status: 400
retryable: false
retry_after_seconds: null
owner_branch: feature-operational-error-observability-foundation
owner_layer: presentation
client_safe_message: "Invalid email format"
log_level: INFO
runbook_link: null
compatibility_impact: none
required_test: contract-verification:validation-envelope
# ============================================================
# Cache (feature-cache-consistency-contract)
# ============================================================
# source: feature-cache-consistency-contract — Decisionized Work Items "Redis unavailable | degrade only if declared | fail-fast for required cache | generic INTERNAL | unavailable mapping" / 테스트 "Redis unavailable이 degrade 가능 여부 없이 INTERNAL로 처리되면 실패"
- code: CACHE_UNAVAILABLE
category: TRANSIENT_DEPENDENCY
http_status: 503
retryable: true
retry_after_seconds: 2
owner_branch: feature-cache-consistency-contract
owner_layer: infrastructure
client_safe_message: "Service temporarily unavailable"
log_level: ERROR
runbook_link: "runbook://cache/unavailable"
compatibility_impact: none
required_test: contract-verification:cache-consistency
# source: feature-cache-consistency-contract L70 — "stampede 방지 default = single-instance Caffeine local lock, multi-instance HPA 시 Redisson RLock distributed mutex" / 테스트 "동일 key에 대해 동시 cache miss 시 backend 호출이 1회로 제한되는지 verify (stampede). 미충족 시 실패"
- code: CACHE_STAMPEDE_LOCK_TIMEOUT
category: TRANSIENT_DEPENDENCY
http_status: 503
retryable: true
retry_after_seconds: 1
owner_branch: feature-cache-consistency-contract
owner_layer: infrastructure
client_safe_message: "Service temporarily unavailable"
log_level: WARN
runbook_link: "runbook://cache/stampede-lock-timeout"
compatibility_impact: none
required_test: contract-verification:cache-consistency
# ============================================================
# Outbound HTTP (feature-outbound-http-client-baseline)
# ============================================================
# source: feature-outbound-http-client-baseline L70 — "outbound HTTP timeout default = connect 2s / read 5s / global call 10s" + scope "timeout/connect/DNS failure 분류" / 테스트 "upstream timeout은 retryable dependency failure로 분류되어야 함"
- code: DEPENDENCY_TIMEOUT
category: TRANSIENT_DEPENDENCY
http_status: 504
retryable: true
retry_after_seconds: 2
owner_branch: feature-outbound-http-client-baseline
owner_layer: infrastructure
client_safe_message: "Upstream service did not respond in time, please retry"
log_level: ERROR
runbook_link: "runbook://dependency/timeout"
compatibility_impact: none
required_test: contract-verification:outbound-http
# source: feature-outbound-http-client-baseline — scope "timeout/connect/DNS failure 분류" + L70 connect=2s timeout
- code: DEPENDENCY_CONNECT_FAILED
category: TRANSIENT_DEPENDENCY
http_status: 503
retryable: true
retry_after_seconds: 2
owner_branch: feature-outbound-http-client-baseline
owner_layer: infrastructure
client_safe_message: "Upstream service unreachable, please retry"
log_level: ERROR
runbook_link: "runbook://dependency/connect-failed"
compatibility_impact: none
required_test: contract-verification:outbound-http
# source: feature-outbound-http-client-baseline — scope "timeout/connect/DNS failure 분류"
- code: DEPENDENCY_DNS_FAILED
category: TRANSIENT_DEPENDENCY
http_status: 503
retryable: true
retry_after_seconds: 5
owner_branch: feature-outbound-http-client-baseline
owner_layer: infrastructure
client_safe_message: "Upstream service unreachable, please retry"
log_level: ERROR
runbook_link: "runbook://dependency/dns-failed"
compatibility_impact: none
required_test: contract-verification:outbound-http
# source: feature-outbound-http-client-baseline — scope "upstream 4xx/5xx 분류" / 테스트 "401/403은 credential/scope/config 문제로 분류되어야 함"
- code: DEPENDENCY_4XX_CLIENT
category: PERMANENT_DEPENDENCY
http_status: 502
retryable: false
retry_after_seconds: null
owner_branch: feature-outbound-http-client-baseline
owner_layer: infrastructure
client_safe_message: "Upstream service rejected the request"
log_level: ERROR
runbook_link: "runbook://dependency/4xx-client"
compatibility_impact: none
required_test: contract-verification:outbound-http
# source: feature-outbound-http-client-baseline — scope "upstream 4xx/5xx 분류"
- code: DEPENDENCY_5XX_SERVER
category: TRANSIENT_DEPENDENCY
http_status: 502
retryable: true
retry_after_seconds: 2
owner_branch: feature-outbound-http-client-baseline
owner_layer: infrastructure
client_safe_message: "Upstream service error, please retry"
log_level: ERROR
runbook_link: "runbook://dependency/5xx-server"
compatibility_impact: none
required_test: contract-verification:outbound-http
# source: feature-outbound-http-client-baseline L69 — "circuit breaker metric은 dependency.name, dependency.type, outcome까지만 tag로 허용" + Decisionized "circuit breaker | Resilience4j optional env"
- code: DEPENDENCY_CIRCUIT_OPEN
category: TRANSIENT_DEPENDENCY
http_status: 503
retryable: true
retry_after_seconds: 10
owner_branch: feature-outbound-http-client-baseline
owner_layer: infrastructure
client_safe_message: "Upstream service temporarily unavailable, please retry later"
log_level: WARN
runbook_link: "runbook://dependency/circuit-open"
compatibility_impact: none
required_test: contract-verification:outbound-http
# ============================================================
# Outbox (feature-domain-event-outbox-contract)
# ============================================================
# source: feature-domain-event-outbox-contract L67 — "outbox row status enum = PENDING / IN_FLIGHT / PUBLISHED / FAILED / DEAD" + scope "publish 실패 분류" / 판정 "publish 실패가 retry/DLQ/log/runbook 기준 없이 삼켜지면 실패"
- code: OUTBOX_PUBLISH_FAILED
category: TRANSIENT_DEPENDENCY
http_status: 500
retryable: true
retry_after_seconds: 30
owner_branch: feature-domain-event-outbox-contract
owner_layer: infrastructure
client_safe_message: "Internal server error"
log_level: ERROR
runbook_link: "runbook://outbox/publish-failed"
compatibility_impact: none
required_test: contract-verification:outbox-publish
# source: feature-domain-event-outbox-contract L67 — outbox status enum "DEAD" / Outbox Defaults "DLQ | background-job branch owner"
- code: OUTBOX_DEAD_LETTER
category: INTERNAL
http_status: 500
retryable: false
retry_after_seconds: null
owner_branch: feature-domain-event-outbox-contract
owner_layer: infrastructure
client_safe_message: "Internal server error"
log_level: ERROR
runbook_link: "runbook://outbox/dead-letter"
compatibility_impact: none
required_test: contract-verification:outbox-dlq
# ============================================================
# Background job / Async (feature-background-job-async-contract)
# ============================================================
# source: feature-background-job-async-contract — Decisionized "saturation | bounded executor + rejection log" / L72 "saturation policy default = AbortPolicy" / 테스트 "executor rejection이 structured log 없이 발생하면 실패"
- code: JOB_EXECUTOR_REJECTED
category: TRANSIENT_DEPENDENCY
http_status: 503
retryable: true
retry_after_seconds: 5
owner_branch: feature-background-job-async-contract
owner_layer: infrastructure
client_safe_message: "Service temporarily unavailable"
log_level: ERROR
runbook_link: "runbook://job/executor-rejected"
compatibility_impact: none
required_test: contract-verification:async-saturation
# source: feature-background-job-async-contract L69 — "기본 backoff는 exponential backoff with jitter, max attempts 3, DLQ after exhausted attempts" + scope "shutdown 중 job 처리 기준" / L73 graceful shutdown ≤19s
- code: JOB_TIMEOUT
category: TRANSIENT_DEPENDENCY
http_status: 500
retryable: true
retry_after_seconds: 10
owner_branch: feature-background-job-async-contract
owner_layer: infrastructure
client_safe_message: "Internal server error"
log_level: ERROR
runbook_link: "runbook://job/timeout"
compatibility_impact: none
required_test: contract-verification:async-timeout
# source: feature-background-job-async-contract L69 — "DLQ after exhausted attempts" + Decisionized "retry/DLQ | exp backoff jitter, max 3, DLQ exhausted | ... | infinite retry"
- code: JOB_DEAD_LETTER
category: INTERNAL
http_status: 500
retryable: false
retry_after_seconds: null
owner_branch: feature-background-job-async-contract
owner_layer: infrastructure
client_safe_message: "Internal server error"
log_level: ERROR
runbook_link: "runbook://job/dead-letter"
compatibility_impact: none
required_test: contract-verification:async-dlq
# ============================================================
# Distributed Lock (feature-distributed-lock-contract)
# ============================================================
# source: feature-distributed-lock-contract D7 — "lock 획득 실패/timeout 의 error code =
# LOCK_ACQUISITION_TIMEOUT (category CONFLICT, retryable true, client_safe true) + metric
# lock.acquisition" / D5 — "try-lock + 유한 waitTime + lease(TTL) 필수, 무한 blocking 금지".
# category CONFLICT 는 기존 enum 재사용; retryable=true — 락 보유자가 임계 구역을 빠져나오면
# 동일 요청 재시도로 해소된다(transient contention). DB_DEADLOCK / DB_SERIALIZATION_FAILURE 와
# 같은 retryable CONFLICT 계열(409). 본 코드는 distributedLockProvider 획득 timeout 전용이며
# cache stampede lock 의 CACHE_STAMPEDE_LOCK_TIMEOUT(cache-consistency, TRANSIENT_DEPENDENCY 503)
# 과 의미가 구분된다 — 후자는 캐시 백엔드 의존성 timeout, 전자는 분산 상호배제 contention.
- code: LOCK_ACQUISITION_TIMEOUT
category: CONFLICT
http_status: 409
retryable: true
retry_after_seconds: 1
owner_branch: feature-distributed-lock-contract
owner_layer: infrastructure
client_safe_message: "Resource is busy, please retry"
log_level: WARN
runbook_link: "runbook://lock/acquisition-timeout"
compatibility_impact: none
required_test: contract-verification:lock-acquisition-timeout
# ============================================================
# Migration / Startup (feature-migration-startup-contract)
# ============================================================
# source: feature-migration-startup-contract L71 — "startup exit code 표준 = ... migration 실패=70 ..." + Decisionized "startup failure log | structured log with startup.phase, error.code, error.category"
- code: MIGRATION_FAILED
category: INTERNAL
http_status: 500
retryable: false
retry_after_seconds: null
owner_branch: feature-migration-startup-contract
owner_layer: infrastructure
client_safe_message: "Internal server error"
log_level: ERROR
runbook_link: "runbook://migration/failed"
compatibility_impact: none
required_test: contract-verification:migration-startup
# source: feature-migration-startup-contract L71 — "startup exit code 표준 = env 누락/malformed=78 ..." / 테스트 "required env 누락 시 startup이 성공하면 실패"
- code: STARTUP_VALIDATION_FAILED
category: INTERNAL
http_status: 500
retryable: false
retry_after_seconds: null
owner_branch: feature-migration-startup-contract
owner_layer: infrastructure
client_safe_message: "Internal server error"
log_level: ERROR
runbook_link: "runbook://startup/validation-failed"
compatibility_impact: none
required_test: contract-verification:migration-startup
# source: feature-migration-startup-contract L71 — "startup exit code 표준 = ... required adapter disabled=72" / 테스트 "disabled required adapter로 app이 뜨면 실패"
- code: REQUIRED_ADAPTER_DISABLED
category: INTERNAL
http_status: 500
retryable: false
retry_after_seconds: null
owner_branch: feature-migration-startup-contract
owner_layer: infrastructure
client_safe_message: "Internal server error"
log_level: ERROR
runbook_link: "runbook://startup/required-adapter-disabled"
compatibility_impact: none
required_test: contract-verification:migration-startup
# source: feature-integration-adapter-templates §구현 가이드 §4 (Layer 3) + §Audit A2.
# Runtime-lifecycle fail-fast for an invoke against a DISABLED optional adapter
# (Kafka/Redis/Slack/Google Email). Deliberately distinct from the startup-lifecycle
# REQUIRED_ADAPTER_DISABLED above (exit 72): a runtime invoke ≠ a startup validation,
# so reusing the startup code would conflate two lifecycles (A2 resolution — new
# runtime code owned by this branch). retryable=false: the adapter stays disabled
# until redeploy, so retrying the same call never clears it.
- code: ADAPTER_DISABLED
category: INTERNAL
http_status: 500
retryable: false
retry_after_seconds: null
owner_branch: feature-integration-adapter-templates
owner_layer: infrastructure
client_safe_message: "Internal server error"
log_level: ERROR
runbook_link: "runbook://adapter/adapter-disabled"
compatibility_impact: none
required_test: adapter-contract:adapter-disabled-runtime-call
# source: feature-migration-startup-contract L71 — "startup exit code 표준 = ... profile mismatch=71" / 테스트 "prod profile에서 local-only 설정이 켜지면 실패"
- code: PROFILE_MISMATCH
category: INTERNAL
http_status: 500
retryable: false
retry_after_seconds: null
owner_branch: feature-migration-startup-contract
owner_layer: infrastructure
client_safe_message: "Internal server error"
log_level: ERROR
runbook_link: "runbook://startup/profile-mismatch"
compatibility_impact: none
required_test: contract-verification:migration-startup
# ============================================================
# Management / Actuator (feature-management-actuator-security-contract)
# ============================================================
# source: feature-management-actuator-security-contract — Exposure Policy "env/configprops | forbidden" "heapdump/threaddump | forbidden unless break-glass runbook" "shutdown | forbidden" / 테스트 "prod에서 env/configprops endpoint가 노출되면 실패"
- code: ACTUATOR_FORBIDDEN
category: AUTHZ
http_status: 403
retryable: false
retry_after_seconds: null
owner_branch: feature-management-actuator-security-contract
owner_layer: presentation
client_safe_message: "Permission denied"
log_level: WARN
runbook_link: "runbook://management/actuator-forbidden"
compatibility_impact: none
required_test: contract-verification:management-actuator
+220
View File
@@ -0,0 +1,220 @@
# Registry: HTTP Headers
# SSOT: wiki/projects/ca-tmpl/registries/headers.yaml
# Schema owner: feature-contract-registry-governance
# Last updated: 2026-05-22
#
# Conventions:
# - HTTP header name: kebab-case (X-Request-Id, X-Tenant-Id)
# - W3C standard headers: lowercase (traceparent, tracestate)
# - mdc_key: snake_case (foundation SSOT)
# - envelope_meta_field: camelCase (envelope SSOT)
headers:
# source: feature-operational-error-observability-foundation.md L97
# "request_id | inbound filter (생성 또는 X-Request-Id 헤더) | response header X-Request-Id"
- name: X-Request-Id
direction: both
type: ulid
required: false
generated_if_missing: true
mdc_key: request_id
envelope_meta_field: requestId
owner_branch: feature-operational-error-observability-foundation
case_style: kebab
compatibility_impact: none
required_test: contract-verification:envelope-headers
# source: feature-api-contract-baseline.md L67
# "X-Api-Version은 실험/compatibility 보조 header이며 path version과 충돌하면 path가 우선"
- name: X-Api-Version
direction: inbound
type: string
required: false
generated_if_missing: false
mdc_key: null
envelope_meta_field: null
owner_branch: feature-api-contract-baseline
case_style: kebab
compatibility_impact: additive
required_test: contract-verification:api-versioning
# source: feature-api-contract-baseline.md L77 / feature-rate-limit-idempotency-contract.md L66-67
# "idempotency header 이름은 Idempotency-Key" / "기본 scope는 (authenticatedPrincipal, idempotencyKey, useCaseName)"
- name: Idempotency-Key
direction: inbound
type: string
required: false
generated_if_missing: false
mdc_key: null
envelope_meta_field: null
owner_branch: feature-rate-limit-idempotency-contract
case_style: kebab
compatibility_impact: additive
required_test: contract-verification:idempotency-replay
# source: feature-rate-limit-idempotency-contract.md L85 / foundation L85
# "RATE_LIMIT | ... | 429 | true (Retry-After 이후)" / "retry-after 기준 없이 429를 반환하면 실패"
- name: Retry-After
direction: outbound
type: duration-seconds
required: false
generated_if_missing: false
mdc_key: null
envelope_meta_field: null
owner_branch: feature-rate-limit-idempotency-contract
case_style: kebab
compatibility_impact: additive
required_test: contract-verification:rate-limit-headers
# source: feature-rate-limit-idempotency-contract.md scope L26 (rate limit response/log 기준)
# rate-limit 응답 표면 (limit/remaining/reset 3종은 표준 rate-limit signaling)
- name: X-RateLimit-Limit
direction: outbound
type: numeric
required: false
generated_if_missing: true
mdc_key: null
envelope_meta_field: null
owner_branch: feature-rate-limit-idempotency-contract
case_style: kebab
compatibility_impact: additive
required_test: contract-verification:rate-limit-headers
# source: feature-rate-limit-idempotency-contract.md scope L26 (rate limit response/log 기준)
- name: X-RateLimit-Remaining
direction: outbound
type: numeric
required: false
generated_if_missing: true
mdc_key: null
envelope_meta_field: null
owner_branch: feature-rate-limit-idempotency-contract
case_style: kebab
compatibility_impact: additive
required_test: contract-verification:rate-limit-headers
# source: feature-rate-limit-idempotency-contract.md scope L26 (rate limit response/log 기준)
- name: X-RateLimit-Reset
direction: outbound
type: rfc3339-date
required: false
generated_if_missing: true
mdc_key: null
envelope_meta_field: null
owner_branch: feature-rate-limit-idempotency-contract
case_style: kebab
compatibility_impact: additive
required_test: contract-verification:rate-limit-headers
# source: feature-api-compatibility-deprecation-contract.md L87
# "deprecation marker | OpenAPI deprecated: true + branch note | response header optional"
- name: Deprecation
direction: outbound
type: rfc3339-date
required: false
generated_if_missing: false
mdc_key: null
envelope_meta_field: null
owner_branch: feature-api-compatibility-deprecation-contract
case_style: kebab
compatibility_impact: additive
required_test: contract-verification:deprecation-marker
# source: feature-api-compatibility-deprecation-contract.md L87
# "deprecation marker | OpenAPI deprecated: true + branch note | response header optional" (RFC 8594 Sunset)
- name: Sunset
direction: outbound
type: rfc3339-date
required: false
generated_if_missing: false
mdc_key: null
envelope_meta_field: null
owner_branch: feature-api-compatibility-deprecation-contract
case_style: kebab
compatibility_impact: additive
required_test: contract-verification:deprecation-marker
# source: feature-distributed-tracing-contract.md L64, L85
# "propagation header는 W3C traceparent default" / "HTTP | traceparent, tracestate (W3C)"
- name: traceparent
direction: both
type: string
required: false
generated_if_missing: true
mdc_key: trace_id
envelope_meta_field: traceId
owner_branch: feature-distributed-tracing-contract
case_style: kebab
compatibility_impact: none
required_test: contract-verification:trace-propagation
# source: feature-distributed-tracing-contract.md L66, L85
# "propagation format = W3C traceparent + tracestate only. B3 propagation은 forbidden"
- name: tracestate
direction: both
type: comma-separated
required: false
generated_if_missing: false
mdc_key: null
envelope_meta_field: null
owner_branch: feature-distributed-tracing-contract
case_style: kebab
compatibility_impact: none
required_test: contract-verification:trace-propagation
# source: feature-operational-error-observability-foundation.md L100
# "correlation_id | inbound header X-Correlation-Id 또는 생성 | HTTP X-Correlation-Id, message header correlation_id"
- name: X-Correlation-Id
direction: both
type: ulid
required: false
generated_if_missing: true
mdc_key: correlation_id
envelope_meta_field: correlationId
owner_branch: feature-operational-error-observability-foundation
case_style: kebab
compatibility_impact: none
required_test: contract-verification:envelope-headers
# source: feature-tenant-context-policy.md L69, L101 (foundation)
# "tenant resolution 우선순위 = ... (2) 명시적 X-Tenant-Id 헤더 (admin/internal API only)" /
# "tenant_id | tenant context (활성 시) | downstream HTTP X-Tenant-Id (with allowlist)"
- name: X-Tenant-Id
direction: both
type: ulid
required: false
generated_if_missing: false
mdc_key: tenant_id
envelope_meta_field: null
owner_branch: feature-tenant-context-policy
case_style: kebab
compatibility_impact: additive
required_test: contract-verification:tenant-header-policy
# source: feature-security-operational-baseline.md L66
# "JWT Resource Server를 baseline security model로 둠" (Bearer token via Authorization header)
- name: Authorization
direction: inbound
type: bearer-token
required: false
generated_if_missing: false
mdc_key: null
envelope_meta_field: null
owner_branch: feature-security-operational-baseline
case_style: kebab
compatibility_impact: none
required_test: contract-verification:jwt-resource-server
# source: feature-security-operational-baseline.md L83-90 (AuthN/AuthZ Decision Matrix)
# 401 응답 시 WWW-Authenticate (Bearer realm/error) — Spring Security JWT Resource Server 표준 challenge header
- name: WWW-Authenticate
direction: outbound
type: string
required: false
generated_if_missing: true
mdc_key: null
envelope_meta_field: null
owner_branch: feature-security-operational-baseline
case_style: kebab
compatibility_impact: none
required_test: contract-verification:jwt-resource-server
+294
View File
@@ -0,0 +1,294 @@
# Registry: MDC / Log Keys
# SSOT: wiki/projects/ca-tmpl/registries/mdc-keys.yaml
# Schema owner: feature-contract-registry-governance
# MDC SSOT: feature-operational-error-observability-foundation
# Last updated: 2026-05-22
#
# Conventions:
# - MDC key naming: snake_case (foundation L93 "snake_case 강제. camelCase / dot.case 금지.")
# - cardinality_safe_for_metric=true 인 key만 metric tag로 사용 가능
# - foundation L93-102 표 "MDC Key Standard (final)" 6개가 core SSOT
mdc_keys:
# source: feature-operational-error-observability-foundation.md L97
# "request_id | inbound filter (생성 또는 X-Request-Id 헤더) | response header X-Request-Id"
- key: request_id
type: ulid
source: inbound_filter
required_in: [request, dependency, security, application]
http_header_mapping: X-Request-Id
envelope_field: meta.requestId
propagation: [http, async, message]
owner_branch: feature-operational-error-observability-foundation
cardinality_safe_for_metric: false
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-mdc-keys
# source: feature-operational-error-observability-foundation.md L98
# "trace_id | Micrometer Tracing | W3C traceparent header"
- key: trace_id
type: string
source: observation_context
required_in: [request, dependency, application]
http_header_mapping: traceparent
envelope_field: meta.traceId
propagation: [http, async, message]
owner_branch: feature-operational-error-observability-foundation
cardinality_safe_for_metric: false
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-mdc-keys
# source: feature-operational-error-observability-foundation.md L99
# "span_id | Micrometer Tracing | W3C traceparent"
# NOTE: background-job-async-contract L71 "span_id는 Micrometer Observation context에서 자동 전파(MDC explicit copy 불필요)"
- key: span_id
type: string
source: observation_context
required_in: [request, dependency]
http_header_mapping: traceparent
envelope_field: null
propagation: [http, async]
owner_branch: feature-operational-error-observability-foundation
cardinality_safe_for_metric: false
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-mdc-keys
# source: feature-operational-error-observability-foundation.md L100
# "correlation_id | inbound header X-Correlation-Id 또는 생성 | HTTP X-Correlation-Id, message header correlation_id"
- key: correlation_id
type: ulid
source: inbound_filter
required_in: [request, dependency, application]
http_header_mapping: X-Correlation-Id
envelope_field: meta.correlationId
propagation: [http, async, message]
owner_branch: feature-operational-error-observability-foundation
cardinality_safe_for_metric: false
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-mdc-keys
# source: feature-operational-error-observability-foundation.md L101 + feature-tenant-context-policy.md L70
# "tenant_id | tenant context (활성 시) | downstream HTTP X-Tenant-Id (with allowlist)" /
# "tenant ID format = opaque ULID (26 chars Crockford base32)"
# NOTE: tenant L73 "tenant_id ULID 원본은 metric tag에 직접 사용 금지"
- key: tenant_id
type: ulid
source: security_context
required_in: [request, dependency, security, audit]
http_header_mapping: X-Tenant-Id
envelope_field: null
propagation: [http, async, message]
owner_branch: feature-tenant-context-policy
cardinality_safe_for_metric: false
case_style: snake
compatibility_impact: additive
required_test: contract-verification:tenant-leakage
# source: feature-operational-error-observability-foundation.md L102
# "user_principal | security context (pseudonymized only) | log only, headers forbidden"
- key: user_principal
type: string
source: security_context
required_in: [security, audit]
http_header_mapping: null
envelope_field: null
propagation: [none]
owner_branch: feature-operational-error-observability-foundation
cardinality_safe_for_metric: false
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-mdc-keys
# ── log type extensions (log-management-contract L101-109 "Log Type별 필수 필드") ──
# source: feature-log-management-contract.md L105 "request | request_id, trace_id, method, uri_template, status, duration_ms"
# NOTE: application-port-usecase-contract / business 측 operation 식별자 (uri_template과 별도 application-set)
- key: operation
type: string
source: application_set
required_in: [application, dependency]
http_header_mapping: null
envelope_field: null
propagation: [none]
owner_branch: feature-log-management-contract
cardinality_safe_for_metric: true
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-fields
# source: feature-log-management-contract.md L105 "request | request_id, trace_id, method, uri_template, status, duration_ms"
- key: method
type: string
source: inbound_filter
required_in: [request]
http_header_mapping: null
envelope_field: null
propagation: [none]
owner_branch: feature-log-management-contract
cardinality_safe_for_metric: true
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-fields
# source: feature-log-management-contract.md L105 "request | request_id, trace_id, method, uri_template, status, duration_ms"
# NOTE: metrics L86 "status_code | 7 (1xx-5xx + ok/other)" — bounded
- key: status
type: numeric
source: inbound_filter
required_in: [request]
http_header_mapping: null
envelope_field: null
propagation: [none]
owner_branch: feature-log-management-contract
cardinality_safe_for_metric: true
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-fields
# source: feature-log-management-contract.md L105-106 "request | ... duration_ms" / "dependency | ... duration_ms"
- key: duration_ms
type: numeric
source: application_set
required_in: [request, dependency]
http_header_mapping: null
envelope_field: null
propagation: [none]
owner_branch: feature-log-management-contract
cardinality_safe_for_metric: false
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-fields
# source: feature-log-management-contract.md L106 "dependency | dependency_name, dependency_type, duration_ms, outcome, error_code"
# NOTE: metrics L88 "dependency_name | 50" — bounded
- key: dependency_name
type: string
source: application_set
required_in: [dependency]
http_header_mapping: null
envelope_field: null
propagation: [none]
owner_branch: feature-log-management-contract
cardinality_safe_for_metric: true
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-fields
# source: feature-log-management-contract.md L106 "dependency | dependency_name, dependency_type, ..."
- key: dependency_type
type: string
source: application_set
required_in: [dependency]
http_header_mapping: null
envelope_field: null
propagation: [none]
owner_branch: feature-log-management-contract
cardinality_safe_for_metric: true
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-fields
# source: feature-log-management-contract.md L106 + metrics L91 "outcome (resilience4j) | 5 (SUCCESS/FAILURE/CIRCUIT_OPEN/TIMEOUT/REJECTED)"
- key: outcome
type: string
source: application_set
required_in: [dependency]
http_header_mapping: null
envelope_field: null
propagation: [none]
owner_branch: feature-log-management-contract
cardinality_safe_for_metric: true
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-fields
# source: feature-log-management-contract.md L106 "dependency | ... error_code (실패 시)"
# NOTE: metrics L89 "error_code | 100 — error registry row 상한과 정합" — bounded
- key: error_code
type: string
source: application_set
required_in: [dependency]
http_header_mapping: null
envelope_field: null
propagation: [none]
owner_branch: feature-log-management-contract
cardinality_safe_for_metric: true
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-fields
# source: feature-log-management-contract.md L107
# "security | event_type, user_principal (pseudonymized), source_ip (anonymized — last octet zeroed)"
- key: event_type
type: string
source: application_set
required_in: [security, audit]
http_header_mapping: null
envelope_field: null
propagation: [none]
owner_branch: feature-log-management-contract
cardinality_safe_for_metric: true
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-fields
# source: feature-log-management-contract.md L107 "security | ... source_ip (anonymized — last octet zeroed)"
# NOTE: metrics L93 "high-cardinality 금지 tag: ... ip_address"
- key: source_ip_anon
type: string
source: inbound_filter
required_in: [security]
http_header_mapping: null
envelope_field: null
propagation: [none]
owner_branch: feature-log-management-contract
cardinality_safe_for_metric: false
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-fields
# source: feature-log-management-contract.md L108 "audit | actor, action, target, before_hash, after_hash, occurred_at"
- key: actor
type: string
source: security_context
required_in: [audit]
http_header_mapping: null
envelope_field: null
propagation: [none]
owner_branch: feature-log-management-contract
cardinality_safe_for_metric: false
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-fields
# source: feature-log-management-contract.md L108 "audit | actor, action, target, ..."
- key: action
type: string
source: application_set
required_in: [audit]
http_header_mapping: null
envelope_field: null
propagation: [none]
owner_branch: feature-log-management-contract
cardinality_safe_for_metric: true
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-fields
# source: feature-log-management-contract.md L108 "audit | actor, action, target, ..."
- key: target
type: string
source: application_set
required_in: [audit]
http_header_mapping: null
envelope_field: null
propagation: [none]
owner_branch: feature-log-management-contract
cardinality_safe_for_metric: false
case_style: snake
compatibility_impact: none
required_test: contract-verification:log-fields
+845
View File
@@ -0,0 +1,845 @@
# Registry: Metrics
# SSOT: wiki/projects/ca-tmpl/registries/metrics.yaml
# Schema owner: feature-contract-registry-governance
# Owner branch: feature-metrics-alerting-contract
# Last updated: 2026-05-22
#
# Notes
# - Naming: Micrometer dot.case + unit suffix (.seconds | .bytes | .total).
# - Tag cardinality bounds are SSOT of feature-metrics-alerting-contract "Cardinality Bounds" table.
# - High-cardinality tags forbidden globally: user_id, request_id, raw_url, raw_query,
# raw_header_value, ip_address. These MUST NOT appear in any row.
# - tenant_id label is bounded mapping table id OR cohort bucket only (ULID raw forbidden).
# - error_code tag cardinality_limit follows error-codes.yaml row count (max 100).
metrics:
# === HTTP server (inbound) ===
# source: feature-metrics-alerting-contract — Metric/Alert Defaults
# "HTTP metric | http.server.requests with method/status/uri-template | raw URL or user id tag"
- name: http.server.requests
type: timer
unit: seconds
tags:
- name: method
cardinality_limit: 8
allowed_values: [GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, OTHER]
- name: status
cardinality_limit: 7
allowed_values: [1xx, 2xx, 3xx, 4xx, 5xx, ok, other]
- name: uri_template
cardinality_limit: 200
validation: must_be_template_not_raw_uri
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p1: "error_rate > 5% for 5m OR > 10% for 1m"
p2: "error_rate > 1% for 10m"
p3: "error_rate > 0.1% for 1h"
owner_branch: feature-metrics-alerting-contract
log_field_mapping: [method, status, uri_template]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-metrics-alerting-contract — P1/P2/P3 정량 기준 (HTTP latency p99)
# "P1: p99 > 5s 5분 / P2: p99 > 1s 10분 / P3: p99 > 500ms 30분"
- name: http.server.requests.latency
type: timer
unit: seconds
tags:
- name: method
cardinality_limit: 8
allowed_values: [GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, OTHER]
- name: uri_template
cardinality_limit: 200
validation: must_be_template_not_raw_uri
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p1: "p99 > 5s for 5m"
p2: "p99 > 1s for 10m"
p3: "p99 > 500ms for 30m"
owner_branch: feature-metrics-alerting-contract
log_field_mapping: [method, uri_template, duration_ms]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === HTTP client (outbound dependency) ===
# source: feature-metrics-alerting-contract — Metric/Alert Defaults
# "dependency metric | dependency.client.requests with dependency.name/type/outcome | endpoint with secret tag"
# source: feature-outbound-http-client-baseline — "circuit breaker metric은 dependency.name, dependency.type, outcome까지만 tag로 허용"
- name: dependency.client.requests
type: timer
unit: seconds
tags:
- name: dependency_name
cardinality_limit: 50
- name: dependency_type
cardinality_limit: 10
allowed_values: [http, grpc, db, cache, queue, broker, other]
- name: outcome
cardinality_limit: 5
allowed_values: [SUCCESS, FAILURE, CIRCUIT_OPEN, TIMEOUT, REJECTED]
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p1: "required dep unavailable for 2m"
p2: "optional dep degraded for 5m"
p3: "spike alert (10x baseline)"
owner_branch: feature-metrics-alerting-contract
log_field_mapping: [dependency_name, dependency_type, outcome, duration_ms]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-outbound-http-client-baseline — decisions
# "retry/circuit breaker 기본 라이브러리는 Resilience4j"
# source: feature-metrics-alerting-contract — "retry/CB minimum: resilience4j.retry.calls{outcome}"
- name: resilience4j.retry.calls
type: counter
unit: total
tags:
- name: name
cardinality_limit: 50
- name: outcome
cardinality_limit: 5
allowed_values: [SUCCESS, FAILURE, CIRCUIT_OPEN, TIMEOUT, REJECTED]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "retry exhaustion rate > 1% for 10m"
owner_branch: feature-outbound-http-client-baseline
log_field_mapping: [dependency_name, outcome, retry_attempt]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-metrics-alerting-contract — "resilience4j.circuitbreaker.state"
- name: resilience4j.circuitbreaker.state
type: gauge
unit: total
tags:
- name: name
cardinality_limit: 50
- name: state
cardinality_limit: 6
allowed_values: [CLOSED, OPEN, HALF_OPEN, DISABLED, FORCED_OPEN, METRICS_ONLY]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p1: "state == OPEN for required dependency for 2m"
p2: "state == OPEN for optional dependency for 5m"
owner_branch: feature-outbound-http-client-baseline
log_field_mapping: [dependency_name]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-metrics-alerting-contract — "resilience4j.circuitbreaker.calls{outcome}"
- name: resilience4j.circuitbreaker.calls
type: timer
unit: seconds
tags:
- name: name
cardinality_limit: 50
- name: outcome
cardinality_limit: 5
allowed_values: [SUCCESS, FAILURE, CIRCUIT_OPEN, TIMEOUT, REJECTED]
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p2: "CIRCUIT_OPEN rate > 1% for 10m"
owner_branch: feature-outbound-http-client-baseline
log_field_mapping: [dependency_name, outcome, duration_ms]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === DB connection pool ===
# source: feature-persistence-failure-baseline — Hikari Alert Threshold
# "pool wait p99 > 100ms 5분 지속 → P2 / pool exhaustion (active = max) > 1분 → P1"
# source: feature-metrics-alerting-contract — "hikaricp.connections.acquire{outcome='timeout'} p99 > 100ms"
- name: hikaricp.connections.acquire
type: timer
unit: seconds
tags:
- name: pool
cardinality_limit: 5
- name: outcome
cardinality_limit: 3
allowed_values: [SUCCESS, TIMEOUT, FAILURE]
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p1: "pool exhaustion (active == max) for 1m"
p2: "acquire p99 > 100ms for 5m"
owner_branch: feature-persistence-failure-baseline
log_field_mapping: [pool, outcome]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-persistence-failure-baseline — In scope "Hikari metric 노출 기준" + Hikari Alert Threshold
- name: hikaricp.connections.usage
type: timer
unit: seconds
tags:
- name: pool
cardinality_limit: 5
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p2: "usage p99 elevated > 10m"
owner_branch: feature-persistence-failure-baseline
log_field_mapping: [pool]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-persistence-failure-baseline — In scope "Hikari metric 노출 기준"
- name: hikaricp.connections.active
type: gauge
unit: total
tags:
- name: pool
cardinality_limit: 5
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p1: "active == max for 1m"
owner_branch: feature-persistence-failure-baseline
log_field_mapping: [pool]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-metrics-alerting-contract — Histogram Buckets/Percentile "DB query: same"
- name: db.query.duration
type: timer
unit: seconds
tags:
- name: operation
cardinality_limit: 20
allowed_values: [select, insert, update, delete, batch, ddl, other]
- name: outcome
cardinality_limit: 3
allowed_values: [SUCCESS, FAILURE, TIMEOUT]
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p2: "p99 > 1s for 10m"
owner_branch: feature-metrics-alerting-contract
log_field_mapping: [operation, outcome, duration_ms]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === Background job / async executor ===
# source: feature-background-job-async-contract — Decisionized Work Items "saturation policy"
# "AbortPolicy default (core=10, max=50, queue=200)"
- name: executor.saturation
type: gauge
unit: total
tags:
- name: executor_name
cardinality_limit: 10
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "queue size > 80% capacity for 5m"
p1: "rejection rate > 0 for 1m"
owner_branch: feature-background-job-async-contract
log_field_mapping: [executor_name]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-background-job-async-contract — Decisionized Work Items "saturation | bounded executor + rejection log"
- name: executor.rejected.total
type: counter
unit: total
tags:
- name: executor_name
cardinality_limit: 10
- name: policy
cardinality_limit: 3
allowed_values: [AbortPolicy, CallerRunsPolicy, DiscardPolicy]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p1: "rejection_count > 0 for 1m"
owner_branch: feature-background-job-async-contract
log_field_mapping: [executor_name, policy]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-background-job-async-contract — Decisionized Work Items "retry/DLQ | exp backoff jitter, max 3, DLQ exhausted"
- name: job.retry.total
type: counter
unit: total
tags:
- name: job_name
cardinality_limit: 50
- name: outcome
cardinality_limit: 4
allowed_values: [SUCCESS, RETRY, EXHAUSTED, DLQ]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "EXHAUSTED rate > 1% for 10m"
owner_branch: feature-background-job-async-contract
log_field_mapping: [job_name, outcome, retry_attempt]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-background-job-async-contract — "DLQ after exhausted attempts"
- name: job.dlq.total
type: counter
unit: total
tags:
- name: job_name
cardinality_limit: 50
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p1: "DLQ rate sustained > 0 for 5m"
owner_branch: feature-background-job-async-contract
log_field_mapping: [job_name]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === Distributed lock ===
# source: feature-distributed-lock-contract D7 — "metric lock.acquisition (tag: outcome =
# acquired/timeout/error) — 신규 제안" / D5 — try-lock + 유한 waitTime + lease(TTL). 분산
# 상호배제(distributedLockProvider) 획득 시도 결과를 센다. key 는 tag 로 넣지 않는다
# (무한 cardinality — 위 전역 금지 규칙). timeout outcome 은 LOCK_ACQUISITION_TIMEOUT 발생과 1:1.
- name: lock.acquisition
type: counter
unit: total
tags:
- name: outcome
cardinality_limit: 3
allowed_values: [acquired, timeout, error]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "timeout rate > 5% for 10m"
owner_branch: feature-distributed-lock-contract
log_field_mapping: [outcome]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-distributed-lock-contract §Edge / D5 (SI-LOCK-C5) — "lease 만료 후 unlock →
# ConcurrentModificationException — 삼킴 금지, 로그+metric 후 정상 흐름 복귀". Counts releases that
# found the lease already expired (the JdbcLock row was reclaimed by another instance before
# the holder called close()). A sustained nonzero rate means lease TTL is shorter than real
# critical-section duration — raise APP/lease TTL or shorten the protected work. Not an
# acquisition outcome, hence a separate counter from lock.acquisition.
- name: lock.lease.expired
type: counter
unit: total
tags: []
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "lease-expired rate sustained > 0 for 10m"
owner_branch: feature-distributed-lock-contract
log_field_mapping: []
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === Outbox publisher ===
# source: feature-domain-event-outbox-contract — Outbox Defaults
# "DB outbox table with eventId, aggregateId, eventType, payload, occurredAt, status, attemptCount, nextAttemptAt"
- name: outbox.publisher.published.total
type: counter
unit: total
tags:
- name: event_type
cardinality_limit: 50
- name: outcome
cardinality_limit: 4
allowed_values: [PUBLISHED, FAILED, DEAD, IN_FLIGHT]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "FAILED rate > 1% for 10m"
owner_branch: feature-domain-event-outbox-contract
log_field_mapping: [event_type, outcome, event_id]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-domain-event-outbox-contract — row status enum PENDING/IN_FLIGHT/PUBLISHED/FAILED/DEAD
- name: outbox.publisher.lag
type: gauge
unit: seconds
tags:
- name: event_type
cardinality_limit: 50
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "lag > 60s for 10m"
p1: "lag > 300s for 5m"
owner_branch: feature-domain-event-outbox-contract
log_field_mapping: [event_type]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-domain-event-outbox-contract — row status enum + Outbox Defaults attemptCount
- name: outbox.pending.size
type: gauge
unit: total
tags:
- name: status
cardinality_limit: 5
allowed_values: [PENDING, IN_FLIGHT, PUBLISHED, FAILED, DEAD]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "PENDING size growing for 10m"
owner_branch: feature-domain-event-outbox-contract
log_field_mapping: [status]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === Cache ===
# source: feature-cache-consistency-contract — Decisionized Work Items "cache pattern | cache-aside default"
- name: cache.gets.total
type: counter
unit: total
tags:
- name: cache_name
cardinality_limit: 50
- name: result
cardinality_limit: 3
allowed_values: [hit, miss, error]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p3: "hit_ratio < baseline 0.5x for 1h"
owner_branch: feature-cache-consistency-contract
log_field_mapping: [cache_name, result]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-cache-consistency-contract — "invalidation = after-commit only", "invalidation 실패가 조용히 무시되면 실패"
- name: cache.invalidations.total
type: counter
unit: total
tags:
- name: cache_name
cardinality_limit: 50
- name: outcome
cardinality_limit: 3
allowed_values: [SUCCESS, FAILURE, SKIPPED]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "FAILURE rate > 0 for 5m"
owner_branch: feature-cache-consistency-contract
log_field_mapping: [cache_name, outcome]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: redis-production-capability — optional bounded cache-only L1
- name: cache.local.requests.total
type: counter
unit: total
tags:
- name: cache_name
cardinality_limit: 50
- name: result
cardinality_limit: 4
allowed_values: [hit, miss, error, bypass]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p3: "bypass or error rate above baseline for 15m"
owner_branch: redis-production-capability
log_field_mapping: [cache_name, result]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: redis-production-capability — local stale-age bound
- name: cache.local.entry.age.seconds
type: timer
unit: seconds
tags:
- name: cache_name
cardinality_limit: 50
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p3: "p99 approaches configured local TTL for 30m"
owner_branch: redis-production-capability
log_field_mapping: [cache_name]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: redis-production-capability — bounded invalidation and generation reconciliation
- name: cache.local.maintenance.total
type: counter
unit: total
tags:
- name: cache_name
cardinality_limit: 50
- name: event
cardinality_limit: 14
allowed_values:
- evict_cardinality
- evict_weight
- evict_ttl
- evict_invalidation
- flush_invalidation
- reconcile_generation_changed
- reconcile_unchanged
- reconcile_error
- subscriber_disconnected
- subscriber_overflow
- subscriber_malformed
- subscriber_publish_success
- subscriber_publish_error
- other
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "reconcile_error, subscriber_overflow, or sustained disconnects for 5m"
owner_branch: redis-production-capability
log_field_mapping: [cache_name, event]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: redis-production-capability Task 16 — closed semantic operation outcomes
- name: redis.capability.operations.total
type: counter
unit: total
tags:
- name: capability
cardinality_limit: 6
allowed_values: [cache, rate_limit, idempotency, efficiency_lease, session, runtime]
- name: role
cardinality_limit: 3
allowed_values: [cache, coordination, session]
- name: operation
cardinality_limit: 24
allowed_values:
- lookup
- record
- invalidate
- refresh_claim
- refresh_release
- rate_evaluate
- idempotency_claim
- idempotency_start
- idempotency_renew
- idempotency_complete
- idempotency_fail
- idempotency_release
- idempotency_inspect
- lease_acquire
- lease_inspect
- lease_renew
- lease_release
- session_create
- session_inspect
- session_save
- session_touch
- session_revoke
- session_rotate
- route_command
- name: redis_outcome
cardinality_limit: 15
allowed_values:
- success
- hit
- miss
- denied
- contended
- conflict
- incompatible
- unavailable
- overloaded
- closed
- indeterminate
- stale
- skipped
- tombstoned
- absolute_expired
- name: certainty
cardinality_limit: 3
allowed_values: [definite, not_applied, indeterminate]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p1: "required coordination/session unavailable or indeterminate mutation sustained for 2m"
p2: "optional cache unavailable or overloaded above baseline for 5m"
owner_branch: redis-production-capability
log_field_mapping: [capability, role, operation, redis_outcome, certainty]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: redis-production-capability Task 16 — monotonic semantic operation duration
- name: redis.capability.duration.seconds
type: timer
unit: seconds
tags:
- name: capability
cardinality_limit: 6
allowed_values: [cache, rate_limit, idempotency, efficiency_lease, session, runtime]
- name: role
cardinality_limit: 3
allowed_values: [cache, coordination, session]
- name: operation
cardinality_limit: 24
allowed_values:
- lookup
- record
- invalidate
- refresh_claim
- refresh_release
- rate_evaluate
- idempotency_claim
- idempotency_start
- idempotency_renew
- idempotency_complete
- idempotency_fail
- idempotency_release
- idempotency_inspect
- lease_acquire
- lease_inspect
- lease_renew
- lease_release
- session_create
- session_inspect
- session_save
- session_touch
- session_revoke
- session_rotate
- route_command
- name: redis_outcome
cardinality_limit: 15
allowed_values:
- success
- hit
- miss
- denied
- contended
- conflict
- incompatible
- unavailable
- overloaded
- closed
- indeterminate
- stale
- skipped
- tombstoned
- absolute_expired
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p2: "p99 approaches the configured command or caller deadline for 10m"
owner_branch: redis-production-capability
log_field_mapping: [capability, role, operation, redis_outcome]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: redis-production-capability Task 16 — admission rejected before command ownership
- name: redis.capability.admission.rejected.total
type: counter
unit: total
tags:
- name: role
cardinality_limit: 3
allowed_values: [cache, coordination, session]
- name: admission
cardinality_limit: 2
allowed_values: [rejected_saturated, rejected_closed]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p1: "required role rejection sustained above zero for 2m"
p2: "optional cache saturation sustained for 5m"
owner_branch: redis-production-capability
log_field_mapping: [role, admission]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: redis-production-capability Task 16 — bounded admitted command count observation
- name: redis.capability.inflight.total
type: gauge
unit: total
tags:
- name: role
cardinality_limit: 3
allowed_values: [cache, coordination, session]
- name: state
cardinality_limit: 3
allowed_values: [idle, active, saturated]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "saturated series remains nonzero for 5m"
owner_branch: redis-production-capability
log_field_mapping: [role, state]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: redis-production-capability Task 16 — observations of exact sanitized RoleHealth
- name: redis.capability.readiness.total
type: counter
unit: total
tags:
- name: capability
cardinality_limit: 5
allowed_values: [cache, rate_limit, idempotency, efficiency_lease, session]
- name: role
cardinality_limit: 3
allowed_values: [cache, coordination, session]
- name: state
cardinality_limit: 3
allowed_values: [available, unavailable, overloaded]
- name: reason
cardinality_limit: 11
allowed_values:
- command_unavailable
- route_closed
- semantic_probe_succeeded
- semantic_read_write_failed
- semantic_program_acl_denied
- semantic_program_failed
- server_version_unsupported
- semantic_probe_in_progress
- semantic_observation_stale
- command_saturated
- recent_command_failure
- name: requirement
cardinality_limit: 2
allowed_values: [optional, required]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p1: "required coordination/session unavailable for 2m"
p2: "optional cache unavailable or overloaded for 5m"
owner_branch: redis-production-capability
log_field_mapping: [capability, role, state, reason, requirement]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: redis-production-capability Task 16 — bounded router shutdown drain result
- name: redis.capability.lifecycle.drain.total
type: counter
unit: total
tags:
- name: role
cardinality_limit: 3
allowed_values: [cache, coordination, session]
- name: drain_outcome
cardinality_limit: 3
allowed_values: [drained, forced_after_timeout, interrupted]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p1: "required role forced_after_timeout or interrupted during shutdown"
p2: "optional cache forced close during shutdown"
owner_branch: redis-production-capability
log_field_mapping: [role, drain_outcome]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === Log appender ===
# source: feature-log-management-contract — Sampling Policy (final)
# "async appender overflow default: drop oldest INFO/DEBUG with counter metric (log.appender.dropped.total)"
- name: log.appender.dropped.total
type: counter
unit: total
tags:
- name: appender
cardinality_limit: 5
- name: level
cardinality_limit: 2
allowed_values: [INFO, DEBUG]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "dropped > 0 sustained for 10m"
owner_branch: feature-log-management-contract
log_field_mapping: [appender, level]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === Distributed tracing ===
# source: feature-distributed-tracing-contract — decisions
# "trace sampling rate default = prod 1%, staging 10%, dev/local 100%"
- name: tracing.sampling.rate
type: gauge
unit: total
tags:
- name: profile
cardinality_limit: 4
allowed_values: [prod, staging, dev, local]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p3: "effective rate deviates from configured for 1h"
owner_branch: feature-distributed-tracing-contract
log_field_mapping: [profile]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === JVM baseline ===
# source: feature-metrics-alerting-contract — In scope "JVM/process metric"
- name: jvm.memory.used
type: gauge
unit: bytes
tags:
- name: area
cardinality_limit: 2
allowed_values: [heap, nonheap]
- name: id
cardinality_limit: 10
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "heap used / max > 0.85 for 10m"
owner_branch: feature-metrics-alerting-contract
log_field_mapping: [area, id]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-metrics-alerting-contract — In scope "JVM/process metric"
- name: jvm.gc.pause
type: timer
unit: seconds
tags:
- name: action
cardinality_limit: 10
- name: cause
cardinality_limit: 10
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p2: "p99 pause > 500ms for 10m"
owner_branch: feature-metrics-alerting-contract
log_field_mapping: [action, cause]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-metrics-alerting-contract — In scope "JVM/process metric"
- name: jvm.threads.live
type: gauge
unit: total
tags: []
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p3: "thread count > 2x baseline for 30m"
owner_branch: feature-metrics-alerting-contract
log_field_mapping: []
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-metrics-alerting-contract — In scope "JVM/process metric" (process uptime)
- name: process.uptime
type: gauge
unit: seconds
tags: []
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p1: "uptime reset unexpectedly < 60s (crash loop signal)"
owner_branch: feature-metrics-alerting-contract
log_field_mapping: []
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
@@ -0,0 +1,118 @@
# Repository owner test: dev.caskeleton.bootstrap.contract.ContractRegistrySchemaGovernanceTest
# Owner Gradle path: :app-bootstrap:test
# Semantic owner test: dev.caskeleton.adapter.outbound.objectstorage.readiness.ObjectStorageReadinessRegistryTest
# Semantic owner Gradle path: :adapter:outbound:objectstorage:test
schema_version: 1
claims:
- card_id: object-storage-managed-upload-single
provider_type: filesystem-local-dev
provider_version: jdk-21
destination_profile: local-managed-integrity
claimed_level: R1
evidence_revision: batch-b-local-r1
evidence_expires_on: ""
required_tasks:
- ":adapter:outbound:objectstorage:check"
limitations:
- single-process control CAS only; no multi-node linearizability
- fsync and atomic move tests do not prove power-loss durability
- local development provider is forbidden in production profiles
- card_id: object-storage-managed-upload-multipart
provider_type: filesystem-local-dev
provider_version: jdk-21
destination_profile: local-unimplemented
claimed_level: R0
evidence_revision: batch-b-contract-r0
evidence_expires_on: ""
required_tasks:
- ":application-core:check"
limitations:
- multipart publication protocol is not implemented
- card_id: object-storage-managed-download
provider_type: filesystem-local-dev
provider_version: jdk-21
destination_profile: local-managed-integrity
claimed_level: R1
evidence_revision: batch-b-local-r1
evidence_expires_on: ""
required_tasks:
- ":adapter:outbound:objectstorage:check"
limitations:
- local functional full and range reads are not production-provider qualification
- no multi-node or power-loss durability claim
- card_id: object-storage-direct-upload-single
provider_type: filesystem-local-dev
provider_version: jdk-21
destination_profile: local-unimplemented
claimed_level: R0
evidence_revision: batch-b-contract-r0
evidence_expires_on: ""
required_tasks:
- ":application-core:check"
limitations:
- direct grant provider and public inbound endpoint are not implemented
- card_id: object-storage-direct-upload-multipart
provider_type: filesystem-local-dev
provider_version: jdk-21
destination_profile: local-unimplemented
claimed_level: R0
evidence_revision: batch-b-contract-r0
evidence_expires_on: ""
required_tasks:
- ":application-core:check"
limitations:
- direct multipart session and public inbound endpoint are not implemented
- card_id: object-storage-direct-download
provider_type: filesystem-local-dev
provider_version: jdk-21
destination_profile: local-unimplemented
claimed_level: R0
evidence_revision: batch-b-contract-r0
evidence_expires_on: ""
required_tasks:
- ":application-core:check"
limitations:
- direct download grant and public inbound endpoint are not implemented
- card_id: object-storage-quarantine-publication
provider_type: filesystem-local-dev
provider_version: jdk-21
destination_profile: local-unimplemented
claimed_level: R0
evidence_revision: batch-b-contract-r0
evidence_expires_on: ""
required_tasks:
- ":application-core:check"
limitations:
- scanner handoff and verdict fencing are not implemented
- card_id: object-storage-retention
provider_type: filesystem-local-dev
provider_version: jdk-21
destination_profile: local-unimplemented
claimed_level: R0
evidence_revision: batch-b-contract-r0
evidence_expires_on: ""
required_tasks:
- ":application-core:check"
limitations:
- retention and legal-hold provider enforcement are not implemented
- privileged purge composition remains intentionally empty
- card_id: object-storage-reconciliation
provider_type: filesystem-local-dev
provider_version: jdk-21
destination_profile: local-unimplemented
claimed_level: R0
evidence_revision: batch-b-contract-r0
evidence_expires_on: ""
required_tasks:
- ":application-core:check"
limitations:
- local create resolution is single-process functional evidence only
- production response-loss and multi-node reconciliation are not implemented
+323
View File
@@ -0,0 +1,323 @@
# Registry: Secrets Classification
# SSOT: wiki/projects/ca-tmpl/registries/secrets-classification.yaml
# Schema owner: feature-contract-registry-governance
# Owner branch: feature-secrets-config-source-contract
# Last updated: 2026-05-22
#
# Conventions:
# - 3-tier classification (feature-secrets-config-source-contract 2026-05-22):
# public-config | sensitive-config | secret
# - `secret` rows: prod_default 항상 null. dev fake 식별자는 `__LOCAL_DEV_` prefix
# (feature-secrets-config-source-contract 2026-05-22: "dev/local sentinel value prefix = __LOCAL_DEV_").
# - prod profile에서 `__LOCAL_DEV_` prefix 발견 시 startup fail
# (feature-secrets-config-source-contract 2026-05-22).
# - Masking 기본 = `full_except_last_4` (feature-secrets-config-source-contract 2026-05-22:
# "full mask except last 4 chars for non-secret tokens"). 진짜 secret(password/private key)은 `full`.
# - Naming suffix는 보조 신호 (feature-secrets-config-source-contract: "_TOKEN, _KEY, _PASSWORD").
# - public-config 항목은 env-keys.yaml에서 직접 정의되며 본 파일에는 reference row만 둠.
secrets:
# === Tier 3: secret (true secret — password/private-key/HMAC-salt) ===
- name: APP_DATASOURCE_PASSWORD
# source: feature-secrets-config-source-contract 2026-05-22
# "DB credential은 dual-bind 60s" + "__LOCAL_DEV_FAKE_DB_PASSWORD" 예시
classification: secret
source: secret-manager
rotation_policy: dual-bind-60s
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: feature-secrets-config-source-contract
masking_rule: full
compatibility_impact: breaking
required_test: secrets-contract:db-password-no-leak-in-actuator
- name: APP_SECURITY_JWT_SIGNING_KEY
# source: feature-secrets-config-source-contract 2026-05-22
# "JWT signing key는 24h overlap window 유지 (security branch와 cross-link)"
# + feature-security-operational-baseline "rotation overlap window = 새 kid 도입 → 24h 동안 old kid 병행"
classification: secret
source: secret-manager
rotation_policy: overlap-24h
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: feature-secrets-config-source-contract
masking_rule: full
compatibility_impact: breaking
required_test: secrets-contract:jwt-signing-key-rotation-overlap
- name: APP_SECURITY_OAUTH_CLIENT_SECRET
# source: feature-secrets-config-source-contract 2026-05-22
# "secret classification은 ... naming pattern은 보조(suffix _TOKEN, _KEY, _PASSWORD)"
# + feature-security-operational-baseline "JWT Resource Server를 baseline security model" (OAuth 자격 증명 분류)
classification: secret
source: secret-manager
rotation_policy: restart-only
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: feature-secrets-config-source-contract
masking_rule: full
compatibility_impact: breaking
required_test: secrets-contract:oauth-client-secret-no-leak
- name: APP_EXTERNAL_API_KEY
# source: feature-secrets-config-source-contract 2026-05-22
# "external API key는 application restart 시 reload"
# (per-dependency suffix는 adapter 등록 시 추가; 본 row는 baseline 분류 정의)
classification: secret
source: secret-manager
rotation_policy: restart-only
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: feature-secrets-config-source-contract
masking_rule: full_except_last_4
compatibility_impact: breaking
required_test: secrets-contract:external-api-key-no-leak
- name: APP_CACHE_REDIS_PASSWORD
# source: feature-secrets-config-source-contract 2026-05-22
# 3-tier classification "secret" + feature-integration-adapter-templates "Redis | disabled optional module"
# (Redis enabled + auth 사용 시 secret으로 분류)
classification: secret
source: secret-manager
rotation_policy: restart-only
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: feature-secrets-config-source-contract
masking_rule: full
compatibility_impact: breaking
required_test: secrets-contract:redis-password-no-leak
- name: APP_CACHE_REDIS_TRUST_PEM
# Public CA bundle content, but integrity-sensitive and supplied by the mounted environment.
classification: sensitive-config
source: mounted-env
rotation_policy: restart-only
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: redis-production-capability
masking_rule: full
compatibility_impact: additive
required_test: secrets-contract:redis-trust-reference-no-leak
- name: APP_CACHE_REDIS_KEY_HMAC_SECRET
# Stable cache-key HMAC material. It is distinct from the Redis authentication credential.
classification: secret
source: secret-manager
rotation_policy: dual-read-restart-only
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: codex-phase-a-ci-recovery
masking_rule: full
compatibility_impact: breaking
required_test: secrets-contract:redis-key-hmac-no-leak
- name: APP_RATE_LIMIT_REDIS_PASSWORD
# Dedicated coordination-role Redis credential. It is never inherited from cache Redis.
classification: secret
source: secret-manager
rotation_policy: restart-only
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: redis-distributed-rate-limit
masking_rule: full
compatibility_impact: additive
required_test: secrets-contract:rate-limit-redis-password-no-leak
- name: APP_RATE_LIMIT_REDIS_TRUST_PEM
# Coordination-role CA bundle content; integrity-sensitive but not credential material.
classification: sensitive-config
source: mounted-env
rotation_policy: restart-only
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: redis-production-capability
masking_rule: full
compatibility_impact: additive
required_test: secrets-contract:rate-limit-redis-trust-reference-no-leak
- name: APP_RATE_LIMIT_REDIS_KEY_HMAC_SECRET
# Stable private-key derivation material for rate-limit subjects and policy revisions.
classification: secret
source: secret-manager
rotation_policy: dual-read-restart-only
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: redis-distributed-rate-limit
masking_rule: full
compatibility_impact: additive
required_test: secrets-contract:rate-limit-redis-key-hmac-no-leak
- name: APP_SESSION_REDIS_PASSWORD
# Dedicated session-role ACL credential; never shared implicitly with cache or coordination.
classification: secret
source: secret-manager
rotation_policy: restart-only
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: redis-production-capability
masking_rule: full
compatibility_impact: additive
required_test: secrets-contract:session-redis-password-no-leak
- name: APP_SESSION_REDIS_TRUST_PEM
# Session-role CA bundle content; integrity-sensitive but not credential material.
classification: sensitive-config
source: mounted-env
rotation_policy: restart-only
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: redis-production-capability
masking_rule: full
compatibility_impact: additive
required_test: secrets-contract:session-redis-trust-reference-no-leak
- name: APP_SESSION_REDIS_KEY_HMAC_SECRET
# Stable private derivation material for pseudonymous Redis session keys.
classification: secret
source: secret-manager
rotation_policy: dual-read-restart-only
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: redis-production-capability
masking_rule: full
compatibility_impact: additive
required_test: secrets-contract:session-redis-key-hmac-no-leak
- name: APP_IDEMPOTENCY_REDIS_KEY_HMAC_SECRET
# Owner-safe request-replay keys must not expose tenant/scope/request identifiers.
classification: secret
source: secret-manager
rotation_policy: cold-cutover-restart-only
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: redis-production-capability-completion
masking_rule: full
compatibility_impact: additive
required_test: secrets-contract:idempotency-redis-key-hmac-no-leak
- name: APP_LEASE_REDIS_KEY_HMAC_SECRET
# Efficiency-lease resource and owner scopes use a dedicated derivation key.
classification: secret
source: secret-manager
rotation_policy: cold-cutover-restart-only
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: redis-production-capability-completion
masking_rule: full
compatibility_impact: additive
required_test: secrets-contract:lease-redis-key-hmac-no-leak
- name: APP_PRIVACY_PSEUDONYMIZATION_SALT
# source: feature-data-retention-privacy-contract 2026-05-22
# "pseudonymization key = HMAC-SHA-256 with rotating salt. salt rotation interval = 90일.
# rotation 시 old salt 90일 retain (lookup 가능)."
# + feature-tenant-context-policy "tenant identifier는 raw PII가 아니어야 하며 ... pseudonymized id"
classification: secret
source: secret-manager
rotation_policy: salt-rotation-90d
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: feature-data-retention-privacy-contract
masking_rule: full
compatibility_impact: breaking
required_test: secrets-contract:pseudonymization-salt-rotation
# === Tier 2: sensitive-config (token-bearing URL or id with exposure restriction) ===
- name: APP_NOTIFICATION_SLACK_WEBHOOK_URL
# source: feature-integration-adapter-templates 2026-05-22
# "Slack | disabled optional module | notification failure policy"
# Slack webhook URL은 token을 path에 포함하므로 sensitive-config (URL 형태이지만 secret과 동급 취급)
classification: sensitive-config
source: secret-manager
rotation_policy: manual
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: feature-secrets-config-source-contract
masking_rule: full_except_last_4
compatibility_impact: breaking
required_test: secrets-contract:slack-webhook-no-leak
- name: APP_SECURITY_GOOGLE_OAUTH_CLIENT_ID
# source: feature-secrets-config-source-contract 2026-05-22
# "sensitive-config" tier (id이지만 노출 제한)
# + feature-integration-adapter-templates "Google Email | disabled optional module"
classification: sensitive-config
source: mounted-env
rotation_policy: manual
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: feature-secrets-config-source-contract
masking_rule: full_except_last_4
compatibility_impact: behavior-change
required_test: secrets-contract:google-oauth-client-id-masked
- name: APP_DATASOURCE_USERNAME
# source: feature-secrets-config-source-contract 2026-05-22 — "sensitive-config" tier
# (DB user는 password와 함께 노출되면 위험하므로 sensitive-config)
classification: sensitive-config
source: mounted-env
rotation_policy: dual-bind-60s
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: feature-secrets-config-source-contract
masking_rule: full_except_last_4
compatibility_impact: breaking
required_test: secrets-contract:datasource-username-masked-in-actuator
- name: APP_DATASOURCE_URL
# source: feature-secrets-config-source-contract 2026-05-22 — JDBC URL은 host/db 포함하므로 sensitive-config
# (env-keys.yaml에서는 public-config 처리; 본 파일에서는 노출 통제 관점에서 sensitive로 재분류 — masking 기준 명시 목적)
classification: sensitive-config
source: mounted-env
rotation_policy: restart-only
prod_default: null
dev_sentinel_prefix: __LOCAL_DEV_
owner_branch: feature-secrets-config-source-contract
masking_rule: full_except_last_4
compatibility_impact: breaking
required_test: secrets-contract:datasource-url-masked-in-actuator
# === Tier 1: public-config (reference only — full row in env-keys.yaml) ===
- name: APP_PROFILE
# source: feature-env-driven-runtime-configuration — public-config tier reference
classification: public-config
source: application-yml
owner_branch: feature-env-driven-runtime-configuration
masking_rule: none
reference: env-keys.yaml#APP_PROFILE
- name: APP_NAME
# source: feature-env-driven-runtime-configuration — public-config tier reference
classification: public-config
source: application-yml
owner_branch: feature-env-driven-runtime-configuration
masking_rule: none
reference: env-keys.yaml#APP_NAME
- name: SERVER_PORT
# source: feature-env-driven-runtime-configuration — Spring native, public-config tier reference
classification: public-config
source: application-yml
owner_branch: feature-env-driven-runtime-configuration
masking_rule: none
reference: env-keys.yaml#SERVER_PORT
- name: SPRING_PROFILES_ACTIVE
# source: feature-env-driven-runtime-configuration — Spring native, public-config tier reference
classification: public-config
source: application-yml
owner_branch: feature-env-driven-runtime-configuration
masking_rule: none
reference: env-keys.yaml#SPRING_PROFILES_ACTIVE
- name: OTEL_EXPORTER_OTLP_ENDPOINT
# source: feature-distributed-tracing-contract — public-config tier reference
classification: public-config
source: application-yml
owner_branch: feature-distributed-tracing-contract
masking_rule: none
reference: env-keys.yaml#OTEL_EXPORTER_OTLP_ENDPOINT