2891 lines
234 KiB
Markdown
2891 lines
234 KiB
Markdown
---
|
||
title: CA Skeleton Operational Contract
|
||
source_type: project-note
|
||
status: raw
|
||
confidence: unknown
|
||
tags: [project-note, ca-skeleton, ca-tmpl, clean-architecture, observability, error-handling]
|
||
related_projects: [ca-skeleton, ca-tmpl]
|
||
last_reviewed: 2026-05-26
|
||
diagrams: [ca-skeleton/architecture-modules-2026-05-26, ca-skeleton/architecture-runtime-topology-2026-05-26, ca-skeleton/sequence-request-flow-mermaid, ca-skeleton/sequence-outbox-publish-mermaid, ca-skeleton/sequence-tenant-context-mermaid]
|
||
architecture_review: 2026-05-26
|
||
status_label: active
|
||
project_revision: 1
|
||
url:
|
||
semantic_surface_exclusions:
|
||
- artifact-registry|legacy hub has no project-local Artifact Registry; harness/source/typed-contracts.json is authoritative until migration
|
||
- contract-gate-registry|legacy hub has no project-local Contract/Gate Registry; harness/source/typed-contracts.json is authoritative until migration
|
||
- flow-stage-registry|legacy hub has no project-local Flow/Stage Registry; harness/source/typed-contracts.json is authoritative until migration
|
||
---
|
||
|
||
# CA Skeleton Operational Contract
|
||
|
||
> 이 문서는 도메인/비즈니스 로직을 제거한 Clean Architecture skeleton에서 기본 제공해야 하는 운영 실패/관측성/경계 검증 계약의 canonical SSOT입니다.
|
||
> Phase A/B/C1/D1/D2 모두 2026-05-22 완료. 본 문서는 ca-tmpl 운영 계약의 canonical SSOT. Phase C2는 2026-05-27 `feature-skeleton-package-blueprint-contract` 범위에서 일부 진입: package/module blueprint와 architecture guardrail은 별도 ca-tmpl git repo에서 local verification 완료. 나머지 registry/generated constants/sample fixture/outbox/security 등 Phase C2 항목은 계속 pending.
|
||
>
|
||
> **경로 표기 규약**: 본 문서가 reference하는 `ca-tmpl/docs/...` 경로는 별도 git repo (`/home/donghyeon/workspace/ca-tmpl/`)의 `docs/` 디렉터리를 의미. registry yaml과 runbook stub은 운영 artifact라 LLM Wiki(`wiki/projects/`)에 두지 않고 ca-tmpl repo에 위치. 본 canonical contract 문서만 LLM Wiki에 잔존.
|
||
>
|
||
> 자세한 phase 진척과 closure는 §28 Review Remediation Ledger 참조.
|
||
|
||
---
|
||
|
||
## 1. 목표
|
||
|
||
이 skeleton의 목표는 많은 adapter를 미리 구현하는 것이 아닙니다.
|
||
|
||
```text
|
||
어떤 adapter를 붙여도
|
||
같은 방식으로 실패를 분류하고
|
||
같은 방식으로 로그와 trace를 남기며
|
||
같은 방식으로 응답을 반환하고
|
||
같은 테스트 계약으로 깨짐을 감지하는 구조
|
||
```
|
||
|
||
도메인/비즈니스 로직은 제거합니다. 대신 운영 실패 분류, 경계 validation, mapper, structured response, structured logging, distributed tracing, env-driven configuration, repository access permission, adapter failure contract, API schema, transaction/concurrency, runtime lifecycle, sample domain fixture, domain onboarding, use case/port contract, domain modeling guardrails, business rule validation, domain event/outbox, metrics/alerting, secret/config source, management endpoint security, tenant policy, file/resource handling, cache consistency, background job/async, API compatibility, CI quality gate, build/release supply chain, container runtime, operational runbook, data retention/privacy, developer experience 기준을 기본 제공해야 합니다.
|
||
|
||
<!-- section-id: implementation-boundaries -->
|
||
## 2. 하지 않는 것
|
||
|
||
- `ProblemDetail` 사용 안 함. 자체 structured envelope 응답을 사용.
|
||
- 특정 비즈니스 도메인 예외를 기본 제공하지 않음.
|
||
- 단, skeleton 계약 검증을 위한 sample domain fixture는 둠. 이 sample은 비즈니스 기능이 아니라 contract 검증 도구임.
|
||
- Kafka/Redis/Slack/Google Email을 기본 dependency로 무겁게 탑재하지 않음.
|
||
- raw exception, SQL, token, request/response body를 클라이언트 응답이나 기본 로그에 노출하지 않음.
|
||
- `wiki/interview/`, `wiki/portfolio/`, `wiki/blog/`로 직접 파생하지 않음. 먼저 `wiki/projects/` canonical 문서로 승급.
|
||
|
||
## 3. Structured API Response Contract
|
||
|
||
성공 응답:
|
||
|
||
```text
|
||
success: true
|
||
data: <payload>
|
||
meta.requestId
|
||
meta.traceId
|
||
meta.correlationId
|
||
```
|
||
|
||
실패 응답:
|
||
|
||
```text
|
||
success: false
|
||
error.code
|
||
error.category
|
||
error.message
|
||
error.retryable
|
||
error.details
|
||
meta.requestId
|
||
meta.traceId
|
||
meta.correlationId
|
||
```
|
||
|
||
`error.details`는 validation field error처럼 클라이언트가 수정할 수 있는 안전한 정보만 담습니다.
|
||
|
||
클라이언트 응답에 금지:
|
||
|
||
- exception class name
|
||
- stack trace
|
||
- SQL / SQL parameter
|
||
- token / password / secret
|
||
- raw request body
|
||
- raw response body
|
||
- upstream raw error body
|
||
- internal dependency endpoint
|
||
|
||
## 4. Boundary Validation & Mapper Contract
|
||
|
||
모든 경계는 mapper와 validation 책임을 가집니다.
|
||
|
||
### request -> application
|
||
|
||
- HTTP DTO validation 수행.
|
||
- malformed body, missing parameter, type mismatch, unsupported media type 분류.
|
||
- request DTO를 application command/query로 변환하는 mapper 필수.
|
||
- controller에서 domain object 직접 생성 금지.
|
||
|
||
### application -> domain
|
||
|
||
- command/query invariant 검증.
|
||
- use case policy 검증.
|
||
- repository access capability 검증.
|
||
- domain에는 normalized input만 전달.
|
||
|
||
### domain -> application
|
||
|
||
- domain invariant violation은 application error로 번역.
|
||
- domain object를 response DTO로 직접 노출 금지.
|
||
|
||
### application -> response
|
||
|
||
- response mapper에서 public field만 노출.
|
||
- nullable / empty / default value 정책을 mapper 책임으로 둠.
|
||
- internal diagnostic context를 response payload에 섞지 않음.
|
||
|
||
### filter / interceptor
|
||
|
||
- requestId, traceId, correlationId 생성/전파.
|
||
- MDC key 초기화와 정리.
|
||
- response header propagation.
|
||
- filter에서 business error를 생성하지 않음.
|
||
|
||
## 5. Exception Ownership Contract
|
||
|
||
### presentation
|
||
|
||
- Spring MVC 기본 예외 처리.
|
||
- validation, authentication, authorization, access denied 처리.
|
||
- unreadable body, unsupported media type, no handler, type mismatch 처리.
|
||
- client-safe structured response 생성.
|
||
|
||
### application
|
||
|
||
- use case policy violation 처리.
|
||
- repository access permission violation 처리.
|
||
- external dependency result 해석.
|
||
- domain exception을 application error로 번역.
|
||
|
||
### domain
|
||
|
||
- business invariant violation만 표현.
|
||
- infrastructure exception, HTTP/JPA/Security exception을 알지 않음.
|
||
|
||
### infrastructure
|
||
|
||
- DB/JPA, outbound HTTP, cache, messaging, notification provider 예외를 operational error로 변환.
|
||
- raw exception이 presentation까지 새면 contract 위반.
|
||
|
||
## 6. Operational Error Category
|
||
|
||
기본 category (**`error.category` enum — foundation SSOT, 10개**, [[raw/branch-notes/feature-operational-error-observability-foundation]] D10):
|
||
|
||
- `VALIDATION`
|
||
- `AUTH`
|
||
- `AUTHZ`
|
||
- `NOT_FOUND`
|
||
- `CONFLICT`
|
||
- `RATE_LIMIT`
|
||
- `TRANSIENT_DEPENDENCY`
|
||
- `PERMANENT_DEPENDENCY`
|
||
- `DATA_INTEGRITY`
|
||
- `INTERNAL`
|
||
|
||
> **2026-06-01 정합 (F1)**: 이전 13-category 목록(`AUTHENTICATION`/`AUTHORIZATION`/`PERSISTENCE`/`DEPENDENCY`/`SECURITY`/`MESSAGE`/`CACHE`/`NOTIFICATION` 포함)은 **stale** 이었다. §21 Error Registry 요약(L810/L814) 의 resolved 10-enum 및 foundation branch D10 과 §8 Structured Log 가 모두 10-enum 을 사용하므로 본 §6 을 정합. 명명 매핑(§21 L814, "Phase A 4차 audit Conflict 13 해소"): `AUTHENTICATION→AUTH`, `AUTHORIZATION→AUTHZ`, `PERSISTENCE→{DATA_INTEGRITY, TRANSIENT_DEPENDENCY}`, `DEPENDENCY→{TRANSIENT_DEPENDENCY, PERMANENT_DEPENDENCY}`, `SECURITY→AUTHZ`(repository access denial), `MESSAGE/CACHE/NOTIFICATION→TRANSIENT_DEPENDENCY`(transient infra failure). **per-code 의 정확한 category 는 `ca-tmpl/docs/registries/error-codes.yaml` 가 authoritative** (§21 category 분포: TRANSIENT_DEPENDENCY 15 · AUTH 8 · INTERNAL 8 · VALIDATION 6 · CONFLICT 4 · AUTHZ 3 · DATA_INTEGRITY 3 · RATE_LIMIT 1 · PERMANENT_DEPENDENCY 1 · NOT_FOUND 0).
|
||
|
||
기본 code (각 code 의 category 는 위 10-enum + error-codes.yaml authoritative — 아래 목록의 옛 category 명은 위 매핑으로 해석):
|
||
|
||
- `VALIDATION_FAILED`
|
||
- `MAPPING_FAILED` (2026-05-29 추가, `VALIDATION` category — mapper-internal 실패: record canonical constructor `IllegalArgumentException` wrap, MapStruct NPE, ACL normalization 실패. `MappingException` 으로 명시적 wrap 필수. 도출: [[raw/branch-notes/feature-boundary-validation-mapping-contract]] D10 + §구현 가이드 §3)
|
||
- `BATCH_PARTIAL_FAILURE` (2026-05-29 추가, `VALIDATION` category — bulk endpoint 의 부분/전체 실패. HTTP 200 + envelope.success=false. `BulkEnvelope.partial(...)` 라우팅. 도출: [[raw/branch-notes/feature-boundary-validation-mapping-contract]] D14 + §구현 가이드 §1)
|
||
- `AUTHENTICATION_FAILED`
|
||
- `AUTHORIZATION_FAILED`
|
||
- `RESOURCE_NOT_FOUND`
|
||
- `CONFLICT`
|
||
- `DATA_INTEGRITY_VIOLATION`
|
||
- `DB_UNAVAILABLE`
|
||
- `DB_QUERY_FAILED`
|
||
- `EXTERNAL_BAD_REQUEST`
|
||
- `EXTERNAL_UNAUTHORIZED`
|
||
- `EXTERNAL_FORBIDDEN`
|
||
- `EXTERNAL_TIMEOUT`
|
||
- `EXTERNAL_UNAVAILABLE`
|
||
- `MESSAGE_PUBLISH_FAILED`
|
||
- `CACHE_UNAVAILABLE`
|
||
- `NOTIFICATION_SEND_FAILED`
|
||
- `REPOSITORY_ACCESS_DENIED`
|
||
- `INTERNAL_ERROR`
|
||
|
||
> **§6 는 ca-tmpl 전체 error vocabulary 의 SSOT**. 개별 branch-note (예: `feature-boundary-validation-mapping-contract`) 의 §구현 가이드 §1 (error code 표) 은 본 §6 의 *부분 view*. branch-note §구현 가이드에 본 §6 vocabulary 외의 *도메인 특화 code* (`USER_NOT_FOUND`, `POST_NOT_FOUND`, `DUPLICATE_EMAIL` 등) 작성 금지 — ca-tmpl skeleton 은 도메인 없이 만드는 영역이므로 도메인 특화 code 는 별도 프로젝트가 도메인 얹을 때 추가하는 영역.
|
||
>
|
||
> **코드 vocabulary 추가 절차**: 신규 code (예: `MAPPING_FAILED`, `BATCH_PARTIAL_FAILURE`) 는 본 §6 등록이 *선행 조건*. branch-note 의 §구현 가이드에서 code 를 *사용* 하기 전에 본 §6 에 추가. 등록 전 사용 시 branch-note 에 `provisional` 표시.
|
||
|
||
## 7. Non-Retryable 기준
|
||
|
||
retryable 기본값:
|
||
|
||
- DB connection unavailable
|
||
- transient lock failure
|
||
- query timeout
|
||
- upstream 429
|
||
- upstream 5xx
|
||
- connect timeout
|
||
- read timeout
|
||
- DNS temporary failure
|
||
- message publish temporary failure
|
||
- cache unavailable when degradation is allowed
|
||
|
||
non-retryable 기본값:
|
||
|
||
- validation failure
|
||
- authentication failure
|
||
- authorization failure
|
||
- malformed token
|
||
- invalid signature
|
||
- unsupported media type
|
||
- deterministic conflict
|
||
- upstream 400 caused by invalid request
|
||
- repository access permission violation
|
||
|
||
## 8. Structured Log Contract
|
||
|
||
JSON log 기본 필드:
|
||
|
||
- `timestamp`
|
||
- `level`
|
||
- `app`
|
||
- `profile`
|
||
- `logger`
|
||
- `message`
|
||
- `traceId`
|
||
- `requestId`
|
||
- `correlationId`
|
||
- `operation`
|
||
- `error.code`
|
||
- `error.category`
|
||
- `error.retryable`
|
||
- `dependency.name`
|
||
- `dependency.type`
|
||
- `duration_ms`
|
||
|
||
> **2026-06-01 명명 정합 (F2/D19)**: JSON 로그의 **필드 명은 mdc-keys.yaml 의 snake_case 가 authoritative** — 즉 위 `traceId`/`requestId`/`correlationId` 는 실제 로그에서 `trace_id`/`request_id`/`correlation_id`/`span_id` (snake) 로 출력된다(§21 L855 MDC core 6 + log extension 13 모두 snake). camelCase 표기는 **§3 응답 envelope** (`meta.traceId` …) 의 표현이며, kebab-case 는 **HTTP header** (`X-Request-Id`) 표현이다. 동일 식별자의 계층별 표현 매핑(snake↔camel↔kebab)은 foundation branch D19 ([[raw/branch-notes/feature-operational-error-observability-foundation]] §구현 가이드 §3) 가 SSOT. envelope camelCase 표기 자체의 owner 는 §25 의 schema-serialization.
|
||
|
||
로그 종류:
|
||
|
||
- request log
|
||
- application log
|
||
- dependency log
|
||
- security event log
|
||
- audit log
|
||
|
||
로그 금지:
|
||
|
||
- PII
|
||
- secrets
|
||
- token
|
||
- password
|
||
- authorization header
|
||
- raw request body
|
||
- raw response body
|
||
- SQL parameter
|
||
|
||
기본 level 기준:
|
||
|
||
- client validation 4xx: INFO 또는 WARN
|
||
- auth/authz failure: WARN
|
||
- dependency failure: ERROR
|
||
- internal 5xx: ERROR
|
||
|
||
### Distributed Tracing Contract
|
||
|
||
- trace context는 inbound HTTP, outbound HTTP, async job, message publish/consume 경계에서 전파해야 함.
|
||
- `traceId`는 관측성 상관관계의 최상위 식별자이고, `requestId`는 inbound HTTP 요청 단위 식별자이며, `correlationId`는 business-neutral workflow 식별자로 사용.
|
||
- baggage에는 PII, token, user raw identifier, request body derived value를 넣지 않음.
|
||
- async/job/message boundary에서는 부모 trace context가 없을 경우 새 trace를 만들고 `correlationId`는 유지.
|
||
- sampling, exporter, propagation header는 env로 제어.
|
||
- log에는 `traceId`, `spanId`, `requestId`, `correlationId`를 같은 이름으로 남김.
|
||
|
||
## 9. Env-driven Runtime Configuration
|
||
|
||
서버별 운영 전환이 env로 가능해야 합니다.
|
||
|
||
기본 env:
|
||
|
||
- `APP_NAME`
|
||
- `APP_PROFILE`
|
||
- `ERROR_EXPOSE_DETAILS`
|
||
- `ERROR_EXPOSE_VALIDATION_DETAILS`
|
||
- `LOG_FORMAT`
|
||
- `LOG_LEVEL`
|
||
- `LOG_BODY_ENABLED`
|
||
- `LOG_PII_GUARD_ENABLED`
|
||
- `TRACE_ENABLED`
|
||
- `REQUEST_ID_HEADER`
|
||
- `CORRELATION_ID_HEADER`
|
||
- `DB_URL`
|
||
- `DB_USERNAME`
|
||
- `DB_PASSWORD`
|
||
- `DB_POOL_MAX_SIZE`
|
||
- `DB_CONNECTION_TIMEOUT_MS`
|
||
- `HTTP_CONNECT_TIMEOUT_MS`
|
||
- `HTTP_READ_TIMEOUT_MS`
|
||
- `HTTP_RETRY_ENABLED`
|
||
- `HTTP_CIRCUIT_BREAKER_ENABLED`
|
||
- `KAFKA_ENABLED`
|
||
- `REDIS_ENABLED`
|
||
- `SLACK_ENABLED`
|
||
- `GOOGLE_EMAIL_ENABLED`
|
||
- `SECURITY_JWT_ISSUER`
|
||
- `SECURITY_JWT_AUDIENCE`
|
||
- `CORS_ALLOWED_ORIGINS`
|
||
|
||
기준:
|
||
|
||
- local/dev/staging/prod env matrix 작성.
|
||
- 잘못된 env 값은 가능한 한 startup에서 fail-fast.
|
||
- prod에서 body logging 기본 금지.
|
||
- prod에서 error detail 노출 기본 금지.
|
||
|
||
## 10. Repository Access Permission Contract
|
||
|
||
Read/write repository 분리는 기본 전제입니다. 추가로 use case 단위 capability 정책을 둡니다.
|
||
|
||
use case capability:
|
||
|
||
- `READ_REPOSITORY`
|
||
- `WRITE_REPOSITORY`
|
||
- `SENSITIVE_READ`
|
||
- `BULK_WRITE`
|
||
- `TRANSACTION_REQUIRED`
|
||
- `EXTERNAL_OUTBOUND_ALLOWED`
|
||
|
||
기준:
|
||
|
||
- use case에 허용 capability를 선언.
|
||
- 선언되지 않은 repository capability 사용은 contract violation.
|
||
- repository access permission violation은 일반 internal error가 아니라 skeleton contract violation으로 분류.
|
||
- 테스트로 capability 위반을 감지.
|
||
|
||
## 11. Adapter Failure Contract
|
||
|
||
### Persistence
|
||
|
||
- Data integrity violation
|
||
- lock conflict
|
||
- query timeout
|
||
- DB unavailable
|
||
- JPA system failure
|
||
- SQL/parameter 로그 금지
|
||
|
||
> **추후 branch 분해 대상 (deferred, 아직 owner branch 없음)** — [[raw/branch-notes/feature-persistence-failure-baseline]] §Audit & Findings 에서 OUT_OF_BRANCH_SCOPE 로 분리된 2건. failure-baseline branch In-scope(실패 분류) 밖이라 별도 branch 가 필요하나 미생성:
|
||
> - **disaster recovery restore drill** (D7): backup 존재가 아니라 restore drill 통과 기준 (§18 Data Retention/Privacy `backup/restore 책임 경계` + Operational Runbook 와 연계). 내부 RTO/RPO 정책 — 외부 공식 근거 없음.
|
||
> - **read replica lag threshold** (D8): replica 기본 미사용, 활성화 시 max lag threshold + stale-read 허용 endpoint 명시. 부모에 replica 전용 계약 섹션 부재 — 신설 필요.
|
||
> 착수 시 `/branch feature-disaster-recovery-restore-drill` · `/branch feature-read-replica-lag-contract` 로 전개.
|
||
|
||
### Outbound HTTP
|
||
|
||
- RestClient 기본.
|
||
- 400/401/403/404/409/429/5xx/timeout/DNS/connect failure 분류.
|
||
- dependency log field 필수.
|
||
- body logging 기본 금지.
|
||
|
||
### Security
|
||
|
||
- JWT Resource Server 기준.
|
||
- missing token, malformed token, expired token, invalid signature, issuer mismatch, audience mismatch, claim mapping failure 분리.
|
||
- token/PII 로그 금지.
|
||
|
||
### Optional Adapters
|
||
|
||
- Kafka: publish/consume/deserialization/retry/DLQ/idempotency/correlationId 기준.
|
||
- Redis: cache miss는 장애 아님. unavailable은 degrade 가능 여부로 분류.
|
||
- Slack/Email: notification failure가 core use case를 막을지 명시.
|
||
|
||
## 12. Test Contract
|
||
|
||
테스트로 강제할 계약:
|
||
|
||
- structured error response schema
|
||
- validation details exposure policy
|
||
- raw exception leakage 방지
|
||
- structured log field 존재
|
||
- PII/token/body 미기록
|
||
- retryable classification
|
||
- requestId/traceId/correlationId propagation
|
||
- env profile matrix smoke test
|
||
- repository capability violation detection
|
||
- adapter failure mapping
|
||
|
||
## 13. API Contract Surface
|
||
|
||
응답 envelope만으로는 API contract가 완성되지 않습니다. 다음 표면도 skeleton 기준으로 고정해야 합니다.
|
||
|
||
- API versioning path/header 기준.
|
||
- pagination / sorting / filtering 요청/응답 표준.
|
||
- idempotency key header와 command 중복 처리 기준.
|
||
- request size limit과 payload too large 실패 분류.
|
||
- multipart/file upload 실패 분류.
|
||
- content negotiation 실패 분류.
|
||
- enum/date/timezone/BigDecimal JSON 직렬화 기준.
|
||
- unknown JSON field 허용/거부 기준.
|
||
- OpenAPI schema와 실제 응답 contract 일치 검증.
|
||
|
||
## 14. Transaction / Concurrency Contract
|
||
|
||
쓰기 use case와 persistence adapter는 concurrency 실패 기준을 가져야 합니다.
|
||
|
||
- transaction boundary는 application use case 책임으로 두되 Spring `@Transactional` 직접 import는 금지하고 `TransactionPort` 또는 `TransactionalUseCaseRunner`로 추상화.
|
||
- read-only use case는 read-only transaction 기준을 가짐.
|
||
- optimistic lock, pessimistic lock, deadlock, lock timeout 분류.
|
||
- duplicate command와 idempotent command 구분.
|
||
- command retry 시 중복 write 방지 기준.
|
||
- outbox pattern 도입 기준.
|
||
- transaction required repository capability와 실제 transaction boundary 일치 검증.
|
||
|
||
<!-- section-id: runtime-flow -->
|
||
## 15. Runtime / Lifecycle Contract
|
||
|
||
서버 운영에서 business logic 없이도 발생하는 lifecycle 실패를 다룹니다.
|
||
|
||
- actuator health/readiness/liveness 기준.
|
||
- graceful shutdown 기준.
|
||
- startup validation 기준.
|
||
- migration failure 처리 기준.
|
||
- scheduled job 실패 기준.
|
||
- async executor/thread pool rejection 기준.
|
||
- memory/disk/temp file/resource exhaustion 분류.
|
||
- JVM timezone/system clock 기준.
|
||
|
||
## 16. Schema / Serialization Contract
|
||
|
||
DTO와 JSON schema가 암묵적으로 흘러가지 않도록 serialization 기준을 둡니다.
|
||
|
||
- date/time은 timezone 정책을 명시.
|
||
- money/decimal은 scale/rounding 정책을 명시.
|
||
- enum은 unknown value 처리 기준을 명시.
|
||
- null/empty/missing field 의미를 구분.
|
||
- response field rename은 API versioning과 연결.
|
||
- OpenAPI schema drift를 테스트로 감지.
|
||
|
||
## 17. Sample Domain Fixture
|
||
|
||
도메인/비즈니스 로직은 제거하지만, skeleton 계약 검증을 위한 sample domain은 둡니다.
|
||
|
||
기본 sample:
|
||
|
||
```text
|
||
sample-portfolio
|
||
```
|
||
|
||
sample domain이 검증해야 할 것:
|
||
|
||
- create/read/update/delete 흐름.
|
||
- request DTO -> command/query -> domain -> persistence -> response mapper.
|
||
- validation failure.
|
||
- not found.
|
||
- conflict.
|
||
- optimistic lock.
|
||
- pagination.
|
||
- repository capability.
|
||
- idempotent create/update.
|
||
- outbound adapter 호출 금지/허용 use case.
|
||
|
||
기준:
|
||
|
||
- sample은 `sample` package/module/profile 아래 격리.
|
||
- 실제 프로젝트에서 제거 가능해야 함.
|
||
- sample은 business feature가 아니라 skeleton contract fixture임.
|
||
- sample domain 결과를 portfolio/blog/interview로 직접 파생하지 않음.
|
||
- sample-portfolio은 worklog create/read/update/close 흐름, status transition, assignee/owner policy, optimistic lock, idempotent create, pagination, repository capability를 검증하기 위한 최소 fixture로 둠.
|
||
|
||
## 18. Control Plane Contract
|
||
|
||
운영자는 API 응답과 로그만 보지 않습니다. 서버를 배포, 감시, 보호, 장기간 유지보수하기 위한 제어면도 skeleton 기준에 포함합니다.
|
||
|
||
### Metrics / Alerting
|
||
|
||
- HTTP latency/error rate metric.
|
||
- dependency latency/error rate metric.
|
||
- DB pool metric.
|
||
- JVM/process metric.
|
||
- retry/circuit breaker metric.
|
||
- alert severity는 `P1`, `P2`, `P3`를 기본값으로 사용.
|
||
|
||
### Secrets / Config Source
|
||
|
||
- env와 secret manager 사용 범위.
|
||
- local `.env` 허용 범위.
|
||
- prod secret 노출 금지.
|
||
- config dump 금지.
|
||
- secret rotation 절차와 rotation 후 startup validation 기준.
|
||
|
||
### Management / Actuator Security
|
||
|
||
- actuator endpoint allowlist.
|
||
- health detail exposure 기준.
|
||
- metrics endpoint 인증 기준.
|
||
- management port 분리 여부.
|
||
- prod에서 env/configprops 노출 금지.
|
||
|
||
### Tenant Context Policy
|
||
|
||
- multi-tenancy 지원 여부를 명시.
|
||
- tenant header 허용/금지 기준.
|
||
- tenant scoped repository 기준.
|
||
- tenant leakage 테스트 기준.
|
||
|
||
### File / Resource Handling
|
||
|
||
- upload size limit.
|
||
- temp file cleanup.
|
||
- download streaming failure.
|
||
- content type sniffing 금지.
|
||
- path traversal 방지.
|
||
|
||
### Cache Consistency
|
||
|
||
- cache aside 기준.
|
||
- stale cache 허용 범위.
|
||
- cache stampede 방지.
|
||
- key naming / TTL / invalidation 실패 기준.
|
||
|
||
### Background Job / Async Boundary
|
||
|
||
- async exception handling.
|
||
- executor saturation.
|
||
- scheduled job overlap.
|
||
- job id/correlationId.
|
||
- retry/backoff.
|
||
- shutdown 중 job 처리.
|
||
|
||
### API Compatibility / Deprecation
|
||
|
||
- breaking change 정의.
|
||
- response field removal 금지 기준.
|
||
- deprecated field 정책.
|
||
- migration window 기준.
|
||
|
||
### CI Quality Gates
|
||
|
||
- format/lint/test/contract test/OpenAPI drift check/security scan이 CI에서 분리된 gate로 실행되어야 함.
|
||
- branch merge 전 실패 가능 gate와 warning-only gate를 구분.
|
||
- contract violation은 warning-only로 두지 않음.
|
||
- optional adapter test는 adapter enabled matrix에서만 실행.
|
||
|
||
### Build / Release / Supply Chain
|
||
|
||
- dependency version locking 기준.
|
||
- container image base와 non-root runtime 기준.
|
||
- SBOM 생성 여부.
|
||
- vulnerability severity별 release block 기준.
|
||
- rollback 가능한 artifact versioning 기준.
|
||
|
||
### Container Runtime
|
||
|
||
- JVM memory/container limit 기준.
|
||
- timezone/locale 기준.
|
||
- healthcheck command 기준.
|
||
- graceful shutdown signal 기준.
|
||
- writable filesystem 최소화 기준.
|
||
|
||
### Operational Runbook
|
||
|
||
- alert 발생 시 확인할 dashboard/log query/runbook link 기준.
|
||
- dependency 장애, DB unavailable, auth failure spike, 5xx spike, queue lag, cache unavailable별 1차 대응 기준.
|
||
- degrade 가능한 장애와 즉시 fail-fast해야 하는 장애를 구분.
|
||
|
||
### Data Retention / Privacy
|
||
|
||
- application log, security event log, audit log 보존 기간 기준.
|
||
- PII redaction과 pseudonymization 기준.
|
||
- backup/restore 책임 경계.
|
||
- sample data와 real data 혼동 방지 기준.
|
||
|
||
### Developer Experience
|
||
|
||
- local bootstrap command 기준.
|
||
- `.env.example` 필수 key 기준.
|
||
- Testcontainers 또는 local dependency 대체 기준.
|
||
- smoke test command 기준.
|
||
- sample profile 실행/비활성화 기준.
|
||
|
||
## 19. Domain Application Readiness Contract
|
||
|
||
이 skeleton은 도메인/비즈니스 로직을 포함하지 않지만, 실제 도메인을 얹을 때 바로 같은 구조로 개발할 수 있어야 합니다.
|
||
|
||
### Domain Feature Slice
|
||
|
||
새 도메인 기능은 최소 slice 단위로 추가합니다.
|
||
|
||
```text
|
||
presentation request/response DTO
|
||
request mapper
|
||
application command/query
|
||
use case
|
||
input port / output port
|
||
domain model / value object / domain rule
|
||
persistence model / repository adapter
|
||
response mapper
|
||
contract test
|
||
architecture rule
|
||
```
|
||
|
||
기준:
|
||
|
||
- controller가 use case 외부의 domain/persistence type을 직접 알면 실패.
|
||
- application use case는 input port를 구현하고 output port에만 의존.
|
||
- infrastructure adapter는 output port를 구현.
|
||
- domain은 Spring/JPA/HTTP/security/logging type을 알지 않음.
|
||
- 새 feature는 sample-portfolio의 구조를 복제하되 sample package에 의존하지 않음.
|
||
|
||
### Use Case / Port Contract
|
||
|
||
- command use case와 query use case를 구분.
|
||
- write use case는 transaction/capability/idempotency 기준을 명시.
|
||
- read use case는 pagination/filtering/sorting과 sensitive read capability를 명시.
|
||
- outbound dependency가 필요한 use case는 `EXTERNAL_OUTBOUND_ALLOWED` capability를 명시.
|
||
- use case method는 raw DTO, entity, HTTP request, JPA repository를 직접 받지 않음.
|
||
|
||
### Domain Modeling Guardrails
|
||
|
||
- entity, value object, domain service, domain event를 구분.
|
||
- value object는 생성 시점에 자기 불변식을 검증.
|
||
- aggregate 외부에서 내부 상태를 임의 변경하지 못하게 함.
|
||
- domain rule은 presentation validation이나 JPA constraint에만 의존하지 않음.
|
||
- domain exception은 business invariant만 표현하고 operational error code를 직접 알지 않음.
|
||
|
||
### Business Rule Validation
|
||
|
||
- syntax/shape validation은 request DTO에서 처리.
|
||
- use case policy validation은 application에서 처리.
|
||
- business invariant는 domain에서 처리.
|
||
- persistence uniqueness/integrity는 infrastructure에서 operational error로 변환하되, 필요한 경우 application/domain policy로 사전 검증.
|
||
- 같은 규칙을 여러 경계에 중복 구현할 때는 목적을 명시.
|
||
|
||
### Domain Event / Outbox
|
||
|
||
- domain event는 domain fact만 표현하고 transport detail을 모름.
|
||
- integration event 발행은 application/infrastructure 경계에서 변환.
|
||
- transactional publish가 필요하면 outbox 기준을 사용.
|
||
- event handler 실패는 retryable/non-retryable과 DLQ/runbook 기준을 가짐.
|
||
- event payload에는 PII/secrets/raw body를 넣지 않음.
|
||
|
||
### Sample Removal / Project Adoption
|
||
|
||
- `sample-portfolio`은 새 프로젝트 생성 시 제거 가능해야 함.
|
||
- 제거 후에도 operational/error/log/env/test/architecture contract는 남아야 함.
|
||
- 새 도메인은 `sample-portfolio`을 import하지 않고 구조만 참고.
|
||
- sample 제거 smoke test를 둬서 skeleton core와 sample fixture 결합을 감지.
|
||
|
||
## 20. Skeleton Blueprint Contract
|
||
|
||
실제 구현자는 문서의 원칙뿐 아니라 module boundary와 package 위치를 함께 알아야 합니다. Phase C2 기본값은 **Gradle multi-module + Clean Architecture / Hexagonal boundary** 입니다. module boundary가 1차 강제선이고, module 내부 package는 2차 책임 분류입니다. 단일 모듈 구조는 demo/readme용 축소형으로만 허용하며, 아래 responsibility mapping을 보존해야 합니다.
|
||
|
||
### 20-0. Implementation status (2026-05-27)
|
||
|
||
`feature-skeleton-package-blueprint-contract` 범위는 ca-tmpl repo에서 B안 기준으로 local implementation 완료. 구현 범위는 Gradle module include, module build dependency matrix, package anchor, reference blog package 이동, ArchUnit/Gradle guardrail, README/agent rule update이다. 검증은 `./gradlew verifyCleanArchitectureDependencies`, `./gradlew :app-bootstrap:test --tests '*CleanArchitectureTest'`, `./gradlew :adapter-web:test --tests '*SettingsTest'`, `./gradlew test` 통과로 `locally-verified` 처리한다.
|
||
|
||
제외/잔여: `sample-portfolio`은 fixture anchor만 있고 실제 worklog sample은 미구현. `application/port/in` 및 `application/port/out` package anchor는 존재하지만 reference blog repository port는 아직 `domain/repository`에 남아 있다 (`feature-application-port-usecase-contract` branch에서 `application/port/out`으로 이동). Spring Modulith verifier는 도입하지 않았다. 운영 배포가 아니므로 `prod-verified` 항목은 없다.
|
||
|
||
```text
|
||
settings.gradle
|
||
rootProject.name = 'ca-skeleton'
|
||
include 'app-bootstrap'
|
||
include 'domain-core'
|
||
include 'application-core'
|
||
include 'adapter-web'
|
||
include 'adapter-persistence'
|
||
include 'adapter-outbound'
|
||
include 'shared-contract'
|
||
include 'sample-portfolio'
|
||
|
||
app-bootstrap/
|
||
src/main/java/{basePackage}/bootstrap/
|
||
CaSkeletonApplication
|
||
config/
|
||
src/test/java/{basePackage}/bootstrap/
|
||
smoke/
|
||
|
||
shared-contract/
|
||
src/main/java/{basePackage}/shared/
|
||
response/
|
||
error/
|
||
headers/
|
||
logging/
|
||
tracing/
|
||
metrics/
|
||
registry/
|
||
annotation/
|
||
src/test/java/{basePackage}/shared/
|
||
contract/
|
||
|
||
domain-core/
|
||
src/main/java/{basePackage}/domain/
|
||
# framework-neutral POJO domain model (production)
|
||
src/test/java/{basePackage}/domain/
|
||
|
||
application-core/
|
||
src/main/java/{basePackage}/application/
|
||
usecase/
|
||
command/
|
||
query/
|
||
capability/ # @UseCaseRepositoryAccess, Idempotency enum
|
||
transaction/ # TransactionPort, TransactionalUseCaseRunner
|
||
src/test/java/{basePackage}/application/
|
||
|
||
adapter-web/
|
||
src/main/java/{basePackage}/
|
||
adapter/web/
|
||
dto/
|
||
exception/
|
||
auth/
|
||
presentation/ # presentation-specific (e.g., grpc)
|
||
src/test/java/{basePackage}/adapter/web/
|
||
|
||
adapter-persistence/
|
||
src/main/java/{basePackage}/adapter/persistence/
|
||
# entity/repository/mapper/migration sub-packages 도메인 추가 시 생성
|
||
src/test/java/{basePackage}/adapter/persistence/
|
||
|
||
adapter-outbound/
|
||
src/main/java/{basePackage}/adapter/outbound/
|
||
# httpclient/messaging/cache/notification sub-packages 도메인 추가 시 생성
|
||
src/test/java/{basePackage}/adapter/outbound/
|
||
|
||
shared-contract/
|
||
src/main/java/{basePackage}/shared/
|
||
tracing/
|
||
metrics/
|
||
request/
|
||
logging/
|
||
headers/
|
||
response/ # envelope, BulkEnvelope
|
||
error/ # OperationalError, error codes
|
||
src/test/java/{basePackage}/shared/
|
||
|
||
app-bootstrap/
|
||
src/main/java/{basePackage}/
|
||
# Spring Boot Application + bean wiring
|
||
src/test/java/{basePackage}/
|
||
|
||
sample-portfolio/
|
||
src/main/java/{basePackage}/sample/portfolio/
|
||
domain/
|
||
worklog/ # WorkLog domain entity + value objects (Period, WorkCategory, etc.)
|
||
application/
|
||
command/ # CreateWorkLogCommand, UpdateWorkLogCommand, DeleteWorkLogCommand
|
||
query/ # GetWorkLogQuery, ListWorkLogsQuery, GetRepoStatsQuery
|
||
port/ # outbound port (e.g., RepoStatsPort)
|
||
exception/ # WorkLogNotFoundException
|
||
worklog/ # use case implementations (Create/Get/List/Update/Delete/GetRepoStats)
|
||
adapter/
|
||
web/
|
||
controller/ # WorkLogController
|
||
dto/
|
||
request/ # CreateWorkLogRequest, UpdateWorkLogRequest, ...
|
||
response/ # WorkLogResponse, RepoStatsResponse, ...
|
||
mapper/ # WorkLogWebMapper
|
||
error/ # DomainExceptionHandler, PortfolioErrorCode
|
||
persistence/
|
||
entity/ # WorkLogEntity
|
||
repository/ # WorkLogJpaRepository, WorkLogRepositoryAdapter
|
||
mapper/ # WorkLogPersistenceMapper
|
||
config/ # JpaConfig
|
||
outbound/
|
||
repostats/ # external API adapter (RepoStatsPortClient + ACL mapper)
|
||
src/test/java/{basePackage}/sample/portfolio/
|
||
domain/
|
||
application/
|
||
adapter/
|
||
```
|
||
|
||
기준:
|
||
|
||
- `domain-core`는 framework-neutral POJO domain model만 담고 Spring / JPA / HTTP DTO / Redis / Kafka / client library를 알지 않음.
|
||
- `application-core`는 use case, command/query, inbound/outbound port, policy validation을 담고 `domain-core`와 `shared-contract`에만 의존함.
|
||
- `adapter-web`은 controller, HTTP DTO, mapper, filter, presentation exception mapping을 담고 application port를 호출함.
|
||
- `adapter-persistence`는 JPA entity, Spring Data repository, persistence mapper, migration integration을 담고 application outbound port를 구현함.
|
||
- `adapter-outbound`는 outbound HTTP, messaging, cache, notification adapter 구현체를 담고 application outbound port를 구현함.
|
||
- `shared-contract`는 response envelope, error code, header/MDC/metric registry, tracing/logging contract, 공통 annotation처럼 skeleton-wide operational contract만 담고 business/domain concept를 담지 않음.
|
||
- `app-bootstrap`은 runtime composition root이며 Spring Boot application, bean wiring, profile config를 담음. domain policy 구현을 담지 않음.
|
||
- `sample-portfolio`은 contract 검증 fixture이며 production feature가 아님. production module이 `sample-portfolio`을 import하거나 dependency로 선언하면 실패.
|
||
- package/module 위치가 다르면 architecture rule 문서에 responsibility mapping을 명시해야 함.
|
||
|
||
Module dependency rule:
|
||
|
||
| Module | May depend on | Must not depend on |
|
||
| --- | --- | --- |
|
||
| `domain-core` | (none) or `shared-contract` value-only types | Spring, JPA, HTTP DTO, Redis/Kafka/client libraries, adapter modules |
|
||
| `application-core` | `domain-core`, `shared-contract` | `adapter-*`, `app-bootstrap`, Spring Web/JPA implementation APIs |
|
||
| `adapter-web` | `application-core`, `domain-core`, `shared-contract` | `adapter-persistence`, `adapter-outbound` direct implementation coupling |
|
||
| `adapter-persistence` | `application-core`, `domain-core`, `shared-contract` | `adapter-web`, `app-bootstrap` |
|
||
| `adapter-outbound` | `application-core`, `domain-core`, `shared-contract` | `adapter-web`, `app-bootstrap` |
|
||
| `app-bootstrap` | all runtime modules | domain policy implementation |
|
||
| `sample-portfolio` | all runtime modules only as fixture consumer | production module importing `sample-portfolio` |
|
||
|
||
## 21. Contract Registry
|
||
|
||
100점 기준에서는 중요한 문자열과 enum이 문서 곳곳에 흩어지면 안 됩니다. 본 섹션의 7개 registry는 raw markdown 결정 사항과 별도로 implementation artifact yaml(`ca-tmpl/docs/registries/` 하위)에서 단일 source of truth로 관리합니다. **yaml은 Phase B 산출물이며, ca-tmpl 실 코드 단계(Phase C2)에서 generated constants의 source가 됩니다.** 본 섹션의 inline 요약은 reader 편의용이며 정확한 row 정의는 yaml을 참조합니다.
|
||
|
||
### SSOT yaml 위치
|
||
|
||
| registry | yaml 파일 | row 수 (2026-05-22) | owner branch |
|
||
| --- | --- | --- | --- |
|
||
| Error Codes | `ca-tmpl/docs/registries/error-codes.yaml` | 49 (skeleton-level; NOT_FOUND/도메인별 VALIDATION row는 도메인 도입 시 추가) | `feature-operational-error-observability-foundation` (category enum SSOT) |
|
||
| Env Keys | `ca-tmpl/docs/registries/env-keys.yaml` | 51 | `feature-env-driven-runtime-configuration` |
|
||
| Secrets Classification | `ca-tmpl/docs/registries/secrets-classification.yaml` | 15 | `feature-secrets-config-source-contract` |
|
||
| HTTP Headers | `ca-tmpl/docs/registries/headers.yaml` | 15 | `feature-api-contract-baseline` (cross-owner: idempotency, tracing, tenant, compat, security) |
|
||
| MDC / Log Keys | `ca-tmpl/docs/registries/mdc-keys.yaml` | 19 (foundation core 6 + log extension 13) | `feature-operational-error-observability-foundation` |
|
||
| Metrics | `ca-tmpl/docs/registries/metrics.yaml` | 25 | `feature-metrics-alerting-contract` |
|
||
| Repository Access Capabilities | `ca-tmpl/docs/registries/capabilities.yaml` | 7 | `feature-repository-access-permission-contract` |
|
||
|
||
총 196 rows. 모든 row에 source branch + line 인용 yaml comment 포함. 추측 row 0건 (source-grounded only).
|
||
|
||
### Error Registry 요약 (yaml 정합)
|
||
|
||
- `error.category` enum (foundation SSOT, 10개): VALIDATION / AUTH / AUTHZ / NOT_FOUND / CONFLICT / RATE_LIMIT / TRANSIENT_DEPENDENCY / PERMANENT_DEPENDENCY / DATA_INTEGRITY / INTERNAL
|
||
- 카테고리별 row 분포: TRANSIENT_DEPENDENCY 15 · AUTH 8 · INTERNAL 8 · VALIDATION 6 · CONFLICT 4 · AUTHZ 3 · DATA_INTEGRITY 3 · RATE_LIMIT 1 · PERMANENT_DEPENDENCY 1 · NOT_FOUND 0 (도메인 도입 시 추가)
|
||
- row schema: `code` (UPPER_SNAKE_CASE), `category`, `http_status`, `retryable`, `retry_after_seconds`, `owner_branch`, `owner_layer`, `client_safe_message`, `log_level`, `runbook_link`, `compatibility_impact`, `required_test`
|
||
- runbook 정책: `retryable=true` 모두 + `category ∈ {AUTH, AUTHZ, RATE_LIMIT, INTERNAL, TRANSIENT_DEPENDENCY, PERMANENT_DEPENDENCY}` 이면서 `retryable=false`인 row는 `runbook_link` 필수. client-error(`VALIDATION/NOT_FOUND/CONFLICT/DATA_INTEGRITY` + `retryable=false`)는 면제.
|
||
- 명명 정합: `AUTHENTICATION`→`AUTH`, `AUTHORIZATION`→`AUTHZ`, `PERSISTENCE`→`DATA_INTEGRITY`/`TRANSIENT_DEPENDENCY` 매핑 (Phase A 4차 audit Conflict 13 해소).
|
||
|
||
### Response Envelope 요약
|
||
|
||
envelope schema는 `feature-operational-error-observability-foundation` SSOT. 필수 field:
|
||
|
||
| field | required | rule |
|
||
| --- | --- | --- |
|
||
| `success` | yes | boolean only |
|
||
| `data` | success only | public payload, domain/entity 직접 노출 금지 |
|
||
| `error.code` | failure only | error-codes.yaml row의 code |
|
||
| `error.category` | failure only | foundation enum 10개 중 하나 |
|
||
| `error.message` | failure only | client-safe, raw exception/stack/SQL/token 금지 |
|
||
| `error.retryable` | failure only | error-codes.yaml의 retryable값과 일치 |
|
||
| `error.details` | optional | validation field error shape(`field`, `rejectedValue`(masked), `code`, `message`) |
|
||
| `meta.requestId` | yes (camelCase) | mdc-keys.yaml의 `request_id` (snake) ↔ envelope camel mapping |
|
||
| `meta.traceId` | yes | tracing disabled에서도 opaque id 유지 + `sampled=false` |
|
||
| `meta.correlationId` | yes | mdc `correlation_id` mapping |
|
||
| `meta.page` | paged only | `page`, `size`, optional `total`, sort 정보 (성능 함정 회피, cursor pagination은 별도 endpoint) |
|
||
| `meta.idempotency.replayed` | idempotent replay only | replay 응답 명시 |
|
||
|
||
### Header Registry 요약 (headers.yaml)
|
||
|
||
- naming: HTTP 표준은 kebab-case (`X-Request-Id`, `X-Tenant-Id`, `X-Api-Version`, `Idempotency-Key`, `Retry-After`, `Deprecation`, `Sunset`, `X-RateLimit-Limit/Remaining/Reset`), W3C trace context는 lowercase (`traceparent`, `tracestate`), security 표준 (`Authorization`, `WWW-Authenticate`).
|
||
- direction 분포: inbound 3 · outbound 7 · both 5.
|
||
- mdc_key 매핑 (mdc-keys.yaml과 cross-link): `X-Request-Id↔request_id`, `X-Correlation-Id↔correlation_id`, `traceparent↔trace_id`, `X-Tenant-Id↔tenant_id`.
|
||
- envelope_meta_field 매핑: `meta.requestId`, `meta.traceId`, `meta.correlationId`.
|
||
|
||
### Secrets Registry 요약 (env-keys.yaml, secrets-classification.yaml)
|
||
|
||
- env-keys: 51 row, prefix `APP_` (Spring native env는 prefix 없이 별도 row, 예: `SPRING_PROFILES_ACTIVE`, `SERVER_PORT`). 15개 영역: profile/identity · datasource/pool · outbound HTTP · tracing · log · security/CORS · JWT · tenant · cache/Redis · messaging · notification adapter · file upload · runtime/lifecycle · async executor · sample.
|
||
- secrets-classification: 15 row, 3-tier:
|
||
- **secret** 6: DB_PASSWORD, JWT_SIGNING_KEY, OAUTH_CLIENT_SECRET, EXTERNAL_API_KEY, REDIS_PASSWORD, PSEUDONYMIZATION_SALT
|
||
- **sensitive-config** 4: SLACK_WEBHOOK_URL, GOOGLE_OAUTH_CLIENT_ID, DATASOURCE_USERNAME, DATASOURCE_URL
|
||
- **public-config** reference 5: APP_PROFILE, APP_NAME, SERVER_PORT, SPRING_PROFILES_ACTIVE, OTEL_EXPORTER_OTLP_ENDPOINT (본 yaml은 reference만, env-keys.yaml에서 정의)
|
||
- rotation 정책: `restart-only` (default) · `dual-bind-60s` (DB credential) · `overlap-24h` (JWT signing key, idempotency TTL invariant) · `salt-rotation-90d` (pseudonymization salt) · `manual` (webhook/OAuth client ID)
|
||
- masking: secret은 `full_except_last_4`, 기타 none. prod profile에서 `__LOCAL_DEV_` prefix value 발견 시 startup fail.
|
||
- reload: `no-runtime-reload` (env-driven branch SSOT, secret rotation은 restart validation 또는 dual-bind 책임).
|
||
|
||
### Metrics Registry 요약 (mdc-keys.yaml, metrics.yaml)
|
||
|
||
- MDC keys: snake_case 강제 (foundation SSOT). core 6: `request_id`, `trace_id`, `span_id`, `correlation_id`, `tenant_id`, `user_principal` (pseudonymized only). log extension 13: `operation`, `method`, `status`, `duration_ms`, `dependency_name`, `dependency_type`, `outcome`, `error_code`, `source_ip_anon` (last octet zeroed), `actor`, `action`, `target`, `event_type`.
|
||
- propagation matrix: http(5)/async(5)/message(4)/none(14). background-job-async TaskDecorator 단일 owner가 async/message boundary propagation 책임. `user_principal`은 log only, header/baggage forbidden.
|
||
- metrics: Micrometer dot.case + unit suffix(`.seconds`/`.bytes`/`.total`). cardinality bounds 강제: status_code≤7, uri_template≤200, dependency_name≤50, error_code≤100 (error-codes.yaml row 상한과 정합), tenant_id≤1000 (raw ULID 금지, mapping id 또는 cohort bucket), outcome≤5. **high-cardinality tag forbidden**: user_id, request_id, raw_url, raw_query, raw_header_value, ip_address.
|
||
- percentile: HTTP/DB/dependency timer는 p50/p90/p95/p99. histogram bucket은 SLO-driven (잠정 SLO p99 = 1s).
|
||
- alert severity P1/P2/P3 정량 기준은 metrics.yaml의 `alert_severity_thresholds` field. 잠정 SLO 기반.
|
||
|
||
### Capability Registry 요약 (capabilities.yaml)
|
||
|
||
7개 capability:
|
||
|
||
| capability | enforcement | notes |
|
||
| --- | --- | --- |
|
||
| `READ_REPOSITORY` | ArchUnit | 일반 read |
|
||
| `WRITE_REPOSITORY` | ArchUnit | create/update/delete |
|
||
| `SENSITIVE_READ` | ArchUnit (marker는 registry-managed metadata) | PII/secret-like field read |
|
||
| `BULK_WRITE` | ArchUnit (threshold N > 100) | batch mutation |
|
||
| `TRANSACTION_REQUIRED` | ArchUnit + TransactionPort cross-link | Spring `@Transactional` 직접 import forbidden |
|
||
| `EXTERNAL_OUTBOUND_ALLOWED` | ArchUnit | outbound HTTP/message/notification. outbox row INSERT는 in-process(불요), polling publisher의 broker publish는 outbound(필요) |
|
||
| `CROSS_TENANT_ADMIN` | ArchUnit | tenant 활성 시 cross-tenant 접근 명시 선언 |
|
||
|
||
enforcement: ArchUnit annotation-based rule SSOT. compile-time annotation processor alternative, **runtime AOP forbidden**.
|
||
|
||
### Registry 변경 절차
|
||
|
||
1. raw 결정은 branch note의 결정 사항 / Decisionized Work Items 표에 먼저 작성.
|
||
2. SSOT yaml의 row 추가/수정. row 위 yaml comment에 source branch + line 인용.
|
||
3. compatibility_impact 분류 (none / additive / behavior-change / breaking).
|
||
4. 관련 contract test 추가/수정.
|
||
5. ca-tmpl 실 코드(Phase C2)의 generated constants 재생성 (build task).
|
||
6. branch note의 TODO 항목 drain (registry-governance step 6).
|
||
|
||
registry 기준:
|
||
|
||
- 새 error/env/header/log/metric/capability를 추가할 때 registry yaml 없이 branch TODO만 추가하면 실패.
|
||
- registry 항목은 test contract와 연결되어야 함 (`required_test` field).
|
||
- registry 변경은 backward compatibility와 migration 영향을 기록해야 함 (`compatibility_impact` field).
|
||
- yaml row의 source comment가 branch note 라인 인용 없이 추가되면 review fail.
|
||
|
||
## 22. Sample-portfolio Contract Matrix
|
||
|
||
`sample-portfolio`은 기능 예제가 아니라 skeleton 계약 검증 fixture입니다.
|
||
|
||
| scenario | layer path | verifies | expected failure if broken |
|
||
| --- | --- | --- | --- |
|
||
| create worklog success | request DTO -> command -> use case -> domain -> repository -> response | mapper, command validation, write capability, transaction, envelope | controller가 domain/entity를 직접 생성하거나 반환 |
|
||
| create worklog validation failure | presentation -> error handler | validation details, client-safe error, no raw exception | malformed request가 500 또는 raw exception으로 노출 |
|
||
| create worklog idempotent replay | presentation/application/persistence | `Idempotency-Key`, duplicate write 방지, replay meta | retry 시 worklog 중복 생성 |
|
||
| get worklog success | query use case -> read port -> response mapper | query/read capability, response mapper | persistence entity가 response로 노출 |
|
||
| get worklog not found | application -> error registry | `RESOURCE_NOT_FOUND`, 404, retryable false | not found가 500 또는 DB exception으로 노출 |
|
||
| list worklogs pagination | query -> repository -> response meta | pagination meta, sorting/filtering contract | pagination 정보가 data payload에 섞임 |
|
||
| update worklog conflict | domain/application | conflict classification, status transition rule | invalid transition이 성공하거나 500 발생 |
|
||
| close worklog optimistic lock | persistence/application | optimistic lock -> conflict/retry policy | lock failure가 raw JPA exception으로 노출 |
|
||
| unauthorized worklog update | security/application | auth/authz separation, no PII log | 401/403 분류 혼동 또는 token log |
|
||
| outbound forbidden use case | application capability | `EXTERNAL_OUTBOUND_ALLOWED` enforcement | capability 없이 외부 adapter 호출 |
|
||
| sample disabled startup | runtime/profile | sample prod 비활성화 | prod profile에서 sample endpoint 노출 |
|
||
| sample removal smoke | build/test | core contract와 sample fixture 분리 | sample 제거 후 app/context/contract test 실패 |
|
||
|
||
sample-portfolio minimum model:
|
||
|
||
| model | required fields | purpose |
|
||
| --- | --- | --- |
|
||
| `WorkLogId` | 26-char uppercase Crockford base32 ULID (예: `01ARZ3NDEKTSV4RRFFQ69G5FAV`, regex `^[0-9A-HJKMNP-TV-Z]{26}$`) — [[raw/branch-notes/feature-resource-identifier-contract]] D19 SSOT | value object / path variable mapping |
|
||
| `WorkLogTitle` | normalized non-empty string | request validation + domain invariant |
|
||
| `WorkLogStatus` | `OPEN`, `IN_PROGRESS`, `CLOSED` | enum serialization + transition conflict |
|
||
| `WorkLogVersion` | numeric version | optimistic locking |
|
||
| `WorkLogOwner` | pseudonymized principal id | authorization/log privacy |
|
||
| `IdempotencyKey` | opaque key | duplicate write prevention |
|
||
|
||
sample-portfolio rule:
|
||
|
||
- `OPEN -> IN_PROGRESS -> CLOSED`만 허용.
|
||
- `CLOSED` worklog은 update 불가.
|
||
- owner 또는 allowed assignee만 update 가능.
|
||
- create는 idempotent command로 처리.
|
||
- list는 pagination/sorting/filtering contract를 사용.
|
||
- sample package는 production package에서 import 금지.
|
||
|
||
## 23. Branch Canonical Promotion Criteria
|
||
|
||
branch note는 아래 산출물이 있어야 `wiki/projects` canonical 문서로 승급할 수 있습니다.
|
||
|
||
| artifact | required | rule |
|
||
| --- | --- | --- |
|
||
| Decision table | yes | 기본값/예외/금지/실패 조건 포함 |
|
||
| Work item contract | yes | 각 TODO가 Decision/Allowed/Forbidden/Registry/Test/Failure/Canonical target으로 재작성되어야 함 |
|
||
| Registry update | if token changed | error/env/header/log/metric/capability 변경 시 필수 |
|
||
| Sample-portfolio verification | if applicable | sample scenario 또는 sample removal로 검증 |
|
||
| Contract test mapping | yes | 어떤 테스트가 깨지는지 명시 |
|
||
| Architecture rule mapping | boundary related only | package/import/dependency 위반 기준 명시 |
|
||
| Runbook/log/metric mapping | operational related only | 운영자가 확인할 field와 alert 연결 |
|
||
| Adoption note | yes | 실제 도메인 feature가 따라야 할 규칙 명시 |
|
||
| Out-of-scope note | yes | branch가 책임지지 않는 영역 명시 |
|
||
|
||
promotion failure:
|
||
|
||
- TODO가 “기준 작성” 수준으로만 남아 있으면 승급 실패.
|
||
- TODO가 Work Item Contract 필드를 채우지 않으면 승급 실패.
|
||
- registry 영향이 있는데 registry update가 없으면 승급 실패.
|
||
- sample-portfolio 또는 sample removal 검증 경로가 없으면 승급 실패.
|
||
- 실제 도메인 feature adoption 기준이 없으면 승급 실패.
|
||
|
||
<!-- section-id: project-work-items -->
|
||
## 8.0 실행계획
|
||
|
||
> Project contract v2의 branch handoff SSOT. 기존 §24 목록에는 dependency가 없으므로 revision 1에서는 `-`로 보존하며, 각 완료 조건은 §23의 promotion contract 6필드와 해당 branch gate 통과로 고정한다.
|
||
|
||
| Work Item ID | branch slug | 완료 조건 (측정가능) | Applies Decisions | Dependencies | Status |
|
||
|---|---|---|---|---|---|
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-001` | `feature-operational-error-observability-foundation` | error·observability 6필드 contract와 contract test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-ERROR-ENVELOPE-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-002` | `feature-boundary-validation-mapping-contract` | boundary·mapping 6필드 contract와 negative fixture가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MAPPING-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-003` | `feature-log-management-contract` | log field·masking contract와 verification test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-ERROR-ENVELOPE-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-004` | `feature-env-driven-runtime-configuration` | env configuration 6필드 contract와 invalid-config test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-FRAMEWORK-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-005` | `feature-repository-access-permission-contract` | repository access rule과 forbidden fixture가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-TRANSACTION-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-006` | `feature-persistence-failure-baseline` | persistence failure mapping과 integration test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-DATABASE-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-TESTCONTAINERS-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-007` | `feature-outbound-http-client-baseline` | timeout·retry·circuit-breaker contract test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-RESILIENCE-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-TESTCONTAINERS-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-008` | `feature-security-operational-baseline` | security failure·header contract와 negative test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-FRAMEWORK-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-009` | `feature-integration-adapter-templates` | optional adapter template가 core broker abstraction을 침범하지 않는다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-EVENT-BROKER-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-010` | `feature-contract-verification-test-suite` | release-blocking contract suite가 OpenAPI drift를 검출한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-OPENAPI-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-TEST-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-011` | `feature-api-contract-baseline` | /v1 API와 envelope/OpenAPI contract test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-API-VERSIONING-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-OPENAPI-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-012` | `feature-transaction-concurrency-contract` | transaction·concurrency failure fixture가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-TRANSACTION-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-DATABASE-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-013` | `feature-runtime-health-lifecycle-contract` | startup·readiness·shutdown lifecycle test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MIGRATION-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-014` | `feature-sample-domain-contract-fixture` | sample domain fixture가 module contract를 검증하고 제거 smoke가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-015` | `feature-schema-serialization-contract` | JSON·date·decimal serialization contract test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-JSON-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-016` | `feature-rate-limit-idempotency-contract` | principal·tenant key scope와 replay/rate-limit test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-IDEMPOTENCY-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-RATE-LIMIT-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-017` | `feature-migration-startup-contract` | Flyway 실패·진행 중 readiness가 healthy가 아님을 검증한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MIGRATION-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-MIGRATION-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-018` | `feature-architecture-enforcement-rules` | forbidden module/import fixture가 ArchUnit gate에서 실패한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-ARCHTEST-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-019` | `feature-metrics-alerting-contract` | metric key·cardinality·alert contract test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-ERROR-ENVELOPE-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-020` | `feature-secrets-config-source-contract` | secret source·classification·leakage negative test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-FRAMEWORK-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-021` | `feature-management-actuator-security-contract` | management endpoint exposure·authorization test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-FRAMEWORK-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-022` | `feature-tenant-context-policy` | tenant propagation·clear negative fixture가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-FRAMEWORK-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-023` | `feature-file-resource-handling-contract` | file size·type·storage boundary test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-024` | `feature-cache-consistency-contract` | after-commit invalidation·stampede failure fixture가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-DATABASE-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-025` | `feature-background-job-async-contract` | duplicate scheduler/outbox execution 방지 test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-SCHEDULER-LOCK-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-EVENT-BROKER-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-026` | `feature-api-compatibility-deprecation-contract` | /v1 compatibility·deprecation contract test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-API-VERSIONING-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-027` | `feature-distributed-tracing-contract` | request·trace correlation contract test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-ERROR-ENVELOPE-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-028` | `feature-ci-quality-gates-contract` | architecture·contract·OpenAPI blocking gate가 분리 실행된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-OPENAPI-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-TEST-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-029` | `feature-build-release-supply-chain-contract` | Gradle release·SBOM·signature artifact가 생성된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-BUILD-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-030` | `feature-container-runtime-contract` | non-root·memory·health container contract test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-CONTAINER-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-031` | `feature-operational-runbook-contract` | 각 failure category에 trigger·diagnosis·recovery drill이 연결된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-BOOTSTRAP-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-032` | `feature-data-retention-privacy-contract` | retention·deletion·masking contract test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-033` | `feature-developer-experience-contract` | fresh environment에서 ./gradlew bootstrap이 성공한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-BOOTSTRAP-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-BUILD-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-034` | `feature-domain-feature-onboarding-contract` | 신규 domain slice가 module·test checklist를 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-035` | `feature-application-port-usecase-contract` | application port와 transaction runner architecture test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-TRANSACTION-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-036` | `feature-domain-modeling-guardrails` | domain model forbidden dependency fixture가 실패한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-037` | `feature-business-rule-validation-contract` | validation ownership·mapper failure contract test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MAPPING-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-ERROR-ENVELOPE-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-038` | `feature-domain-event-outbox-contract` | broker-agnostic outbox와 duplicate execution test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-EVENT-BROKER-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-SCHEDULER-LOCK-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-039` | `feature-sample-removal-adoption-contract` | sample 제거 후 production module smoke test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-040` | `feature-skeleton-package-blueprint-contract` | Gradle module graph가 declared layout과 일치한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-BUILD-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-041` | `feature-contract-registry-governance` | registry single-owner·schema·OpenAPI drift gate가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-ERROR-ENVELOPE-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-OPENAPI-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-042` | `feature-test-taxonomy-fixture-contract` | test level별 fixture가 실행되고 container 사용 정책을 지킨다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-TESTCONTAINERS-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-TEST-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-043` | `feature-implementation-readiness-scorecard` | readiness 각 항목이 binary evidence link로 판정된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-BOOTSTRAP-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-044` | `feature-webhook-outbound-contract` | signature·replay·retry·observability contract test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-RESILIENCE-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-045` | `feature-streaming-response-contract` | 지원 protocol과 timeout·failure contract test가 고정된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-API-VERSIONING-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-RESILIENCE-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-046` | `feature-resource-identifier-contract` | ULID format·PostgreSQL uuid persistence·SecureRandom test가 통과한다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-DATABASE-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-RANDOM-001@1` | - | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-047` | `feature-application-query-bypass-contract` | query bypass의 허용 경계·mapping·transaction 영향과 검증 test가 명시된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-TRANSACTION-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MAPPING-001@1` | `WI-CA-SKELETON-OPERATIONAL-CONTRACT-035`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-012`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-024`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-007`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-006` | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-048` | `feature-authentication-authorization-contract` | authentication·authorization ownership, error mapping, forbidden dependency test가 명시된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-ERROR-ENVELOPE-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-FRAMEWORK-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-ARCHTEST-001@1` | `WI-CA-SKELETON-OPERATIONAL-CONTRACT-008`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-005`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-018`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-014`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-022`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-001` | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-049` | `feature-cachestore-multi-backend-router` | cache backend 선택·fallback·failure routing과 contract test가 명시된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-RESILIENCE-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-FRAMEWORK-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-TEST-001@1` | `WI-CA-SKELETON-OPERATIONAL-CONTRACT-024` | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-050` | `feature-database-connection-pool-contract` | connection pool 설정·lifecycle·metric·failure gate가 명시된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-DATABASE-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-RESILIENCE-001@1` | `WI-CA-SKELETON-OPERATIONAL-CONTRACT-004`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-006`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-035`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-019` | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-051` | `feature-dependency-vulnerability-management-contract` | scanner·severity·suppression·update·license 정책과 CI failure gate가 명시된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-BUILD-001@1` | `WI-CA-SKELETON-OPERATIONAL-CONTRACT-028`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-030`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-029` | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-052` | `feature-distributed-lock-contract` | lock provider·lease·transaction commit ordering과 failure test가 명시된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-SCHEDULER-LOCK-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-TRANSACTION-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-DATABASE-001@1` | `WI-CA-SKELETON-OPERATIONAL-CONTRACT-004`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-025`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-024`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-017`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-018` | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-053` | `feature-messaging-multibroker-router` | broker 선택·routing·fallback과 core transport-neutrality test가 명시된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-EVENT-BROKER-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1` | `WI-CA-SKELETON-OPERATIONAL-CONTRACT-038` | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-054` | `feature-notification-provider-spi` | notification provider SPI·routing·failure contract와 test가 명시된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-RESILIENCE-001@1` | `WI-CA-SKELETON-OPERATIONAL-CONTRACT-053`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-049` | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-055` | `feature-persistence-auditing-contract` | persistence audit actor·time·mapping·transaction contract test가 명시된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-TRANSACTION-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MAPPING-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-DATABASE-001@1` | `WI-CA-SKELETON-OPERATIONAL-CONTRACT-056`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-048`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-006`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-012`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-017` | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-056` | `feature-runtime-context-propagation-contract` | runtime context capture·propagation·cleanup과 architecture/contract test가 명시된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-LANGUAGE-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-FRAMEWORK-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-TEST-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-ARCHTEST-001@1` | `WI-CA-SKELETON-OPERATIONAL-CONTRACT-002`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-001`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-025`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-027`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-022` | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-057` | `feature-sample-portfolio-public-access` | sample public endpoint allowlist와 authenticated endpoint negative test가 명시된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-FRAMEWORK-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-TEST-001@1` | `WI-CA-SKELETON-OPERATIONAL-CONTRACT-048`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-021` | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-058` | `feature-startup-failure-log-suppression` | suppressible startup failure 조건과 retained actionable error test가 명시된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-BOOTSTRAP-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-ERROR-ENVELOPE-001@1` | `WI-CA-SKELETON-OPERATIONAL-CONTRACT-001`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-017` | `planned` |
|
||
| `WI-CA-SKELETON-OPERATIONAL-CONTRACT-059` | `feature-static-analysis-quality-contract` | static analysis 도구·threshold·CI failure mapping과 fixture가 명시된다 | `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-BUILD-001@1`, `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-TEST-001@1` | `WI-CA-SKELETON-OPERATIONAL-CONTRACT-028`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-029`, `WI-CA-SKELETON-OPERATIONAL-CONTRACT-018` | `planned` |
|
||
|
||
## 24. Branch 실행 계획
|
||
|
||
> **Legacy reference (v1).** 아래 link 목록과 공통 promotion 설명은 이력·navigation용이다. stable branch ID·decision pin·dependency의 SSOT는 위 Work Item Registry다.
|
||
|
||
모든 branch note는 아래 품질 기준을 만족해야 합니다.
|
||
|
||
```text
|
||
Decision: 기본 선택값이 있는가?
|
||
Allowed: 허용되는 변형이 명확한가?
|
||
Forbidden: 금지 사항이 명확한가?
|
||
Required config/log/test: 구현자가 빠뜨리면 안 되는 필드가 있는가?
|
||
Failure condition: 어떤 상태면 build/review에서 실패인지 명확한가?
|
||
Wiki extraction target: canonical 문서로 승급될 위치가 정해져 있는가?
|
||
```
|
||
|
||
TODO는 작업 목록이 아니라 미완성 계약입니다. 각 TODO는 branch 완료 전에 아래 Work Item Contract로 재작성되어야 합니다.
|
||
|
||
| field | required | rule |
|
||
| --- | --- | --- |
|
||
| Decision | yes | 구현자가 선택해야 하는 기본값 |
|
||
| Allowed | yes | 허용되는 예외와 조건 |
|
||
| Forbidden | yes | 절대 금지되는 구현/문서 상태 |
|
||
| Required registry update | conditional | error/env/header/log/metric/capability 변경 시 필수 |
|
||
| Required contract test | yes | 계약 위반 시 실패해야 하는 테스트 |
|
||
| Failure condition | yes | review/build에서 실패로 판정할 상태 |
|
||
| Canonical extraction target | yes | `wiki/projects` 승급 위치 |
|
||
|
||
- [[raw/branch-notes/feature-operational-error-observability-foundation]]
|
||
- [[raw/branch-notes/feature-boundary-validation-mapping-contract]]
|
||
- [[raw/branch-notes/feature-log-management-contract]]
|
||
- [[raw/branch-notes/feature-env-driven-runtime-configuration]]
|
||
- [[raw/branch-notes/feature-repository-access-permission-contract]]
|
||
- [[raw/branch-notes/feature-persistence-failure-baseline]]
|
||
- [[raw/branch-notes/feature-outbound-http-client-baseline]]
|
||
- [[raw/branch-notes/feature-security-operational-baseline]]
|
||
- [[raw/branch-notes/feature-integration-adapter-templates]]
|
||
- [[raw/branch-notes/feature-contract-verification-test-suite]]
|
||
- [[raw/branch-notes/feature-api-contract-baseline]]
|
||
- [[raw/branch-notes/feature-transaction-concurrency-contract]]
|
||
- [[raw/branch-notes/feature-runtime-health-lifecycle-contract]]
|
||
- [[raw/branch-notes/feature-sample-domain-contract-fixture]]
|
||
- [[raw/branch-notes/feature-schema-serialization-contract]]
|
||
- [[raw/branch-notes/feature-rate-limit-idempotency-contract]]
|
||
- [[raw/branch-notes/feature-migration-startup-contract]]
|
||
- [[raw/branch-notes/feature-architecture-enforcement-rules]]
|
||
- [[raw/branch-notes/feature-metrics-alerting-contract]]
|
||
- [[raw/branch-notes/feature-secrets-config-source-contract]]
|
||
- [[raw/branch-notes/feature-management-actuator-security-contract]]
|
||
- [[raw/branch-notes/feature-tenant-context-policy]]
|
||
- [[raw/branch-notes/feature-file-resource-handling-contract]]
|
||
- [[raw/branch-notes/feature-cache-consistency-contract]]
|
||
- [[raw/branch-notes/feature-background-job-async-contract]]
|
||
- [[raw/branch-notes/feature-api-compatibility-deprecation-contract]]
|
||
- [[raw/branch-notes/feature-distributed-tracing-contract]]
|
||
- [[raw/branch-notes/feature-ci-quality-gates-contract]]
|
||
- [[raw/branch-notes/feature-build-release-supply-chain-contract]]
|
||
- [[raw/branch-notes/feature-container-runtime-contract]]
|
||
- [[raw/branch-notes/feature-operational-runbook-contract]]
|
||
- [[raw/branch-notes/feature-data-retention-privacy-contract]]
|
||
- [[raw/branch-notes/feature-developer-experience-contract]]
|
||
- [[raw/branch-notes/feature-domain-feature-onboarding-contract]]
|
||
- [[raw/branch-notes/feature-application-port-usecase-contract]]
|
||
- [[raw/branch-notes/feature-domain-modeling-guardrails]]
|
||
- [[raw/branch-notes/feature-business-rule-validation-contract]]
|
||
- [[raw/branch-notes/feature-domain-event-outbox-contract]]
|
||
- [[raw/branch-notes/feature-sample-removal-adoption-contract]]
|
||
- [[raw/branch-notes/feature-skeleton-package-blueprint-contract]]
|
||
- [[raw/branch-notes/feature-contract-registry-governance]]
|
||
- [[raw/branch-notes/feature-test-taxonomy-fixture-contract]]
|
||
- [[raw/branch-notes/feature-implementation-readiness-scorecard]]
|
||
- [[raw/branch-notes/feature-webhook-outbound-contract]] (signature/replay/retry/observability 계약)
|
||
- [[raw/branch-notes/feature-streaming-response-contract]] (SSE / WebSocket / long-polling / chunked 지원 여부 1차 결정)
|
||
- [[raw/branch-notes/feature-resource-identifier-contract]] (D1~D19 결정 박힘 — ULID 26-char Crockford base32 + PostgreSQL `uuid` native + sample-portfolio `WorkLogId = "01ARZ3NDEKTSV4RRFFQ69G5FAV"` fixture, project §34 Stack Commitment 정합)
|
||
|
||
## 25. Default Decisions
|
||
|
||
> **Legacy reference (v1).** 아래 default와 owner map은 세부 rationale·branch-local owner 설명을 보존한다. project-wide 결정의 현재 owner와 상속 기준은 `## 6.1 Project Decision Registry / 안정 결정 레지스트리`다. branch-owned D-row는 project registry로 복제하지 않는다.
|
||
|
||
이 섹션은 branch 착수자가 자기 해석으로 갈라지지 않도록 하는 기본 결정값입니다. branch 작업 중 더 나은 기준이 발견되면 이 값을 바꾸되, 변경 사유와 대체 테스트 계약을 함께 남깁니다.
|
||
|
||
### Blocking Defaults
|
||
|
||
아래 15개 항목은 모든 branch의 선행 default입니다. 이 표와 충돌하는 branch note는 해당 branch가 아니라 이 프로젝트 노트를 먼저 수정해야 합니다.
|
||
|
||
| 항목 | 기본 결정 | SSOT branch | 실패 조건 |
|
||
| --- | --- | --- | --- |
|
||
| package layout | Gradle multi-module을 기본으로 두고 `domain-core` / `application-core` / `adapter-*` / `shared-contract` / `app-bootstrap` / `sample-portfolio` 책임을 분리 | `feature-skeleton-package-blueprint-contract` | module boundary와 package responsibility가 혼재되어 새 기능 위치를 판정할 수 없음 |
|
||
| transaction boundary | Spring `@Transactional`을 application 구현체에 직접 두지 않고 `TransactionPort` 또는 `TransactionalUseCaseRunner`로 추상화 | `feature-application-port-usecase-contract` | application layer가 Spring transaction annotation을 직접 import |
|
||
| mapper tool | 기본은 수기 mapper + record canonical constructor. MapStruct는 optional profile이며 generated code exemption 필요 | `feature-boundary-validation-mapping-contract` | mapper 도구가 branch마다 다르거나 generated code 예외가 architecture rule에 없음 |
|
||
| error envelope schema | envelope schema와 `error.category` enum은 foundation branch가 단일 owner | `feature-operational-error-observability-foundation` | business/schema/validation branch가 envelope field를 독자 정의 |
|
||
| OpenAPI drift | drift 집행 권한은 verification suite가 단일 owner, API/schema branch는 producer | `feature-contract-verification-test-suite` | OpenAPI snapshot과 실제 envelope가 불일치해도 build 통과 |
|
||
| migration runner | Flyway를 app startup에서 실행하되 readiness는 migration 완료 후에만 healthy. 운영에서 별도 job 전환 가능 | `feature-migration-startup-contract` | migration 실패 또는 진행 중 readiness가 healthy |
|
||
| scheduler/outbox lock | single-instance 기본. multi-instance 활성화 시 DB advisory lock을 기본값으로 사용 | `feature-background-job-async-contract` | scheduled job/outbox publisher가 multi-instance에서 중복 실행 가능 |
|
||
| broker | Kafka 강제 안 함. core는 broker-agnostic outbox contract만 제공하고 Kafka는 optional adapter | `feature-domain-event-outbox-contract` | domain event가 Kafka transport type을 직접 가짐 |
|
||
| circuit breaker/retry | Resilience4j 기본, Spring Retry는 simple blocking retry에만 예외 허용 | `feature-outbound-http-client-baseline` | retry/circuit breaker metric 이름과 정책이 adapter마다 다름 |
|
||
| container base image | Temurin JRE slim 기본, distroless는 runtime debug/runbook 보강 후 허용 | `feature-container-runtime-contract` | base image가 branch마다 다르거나 non-root/JVM memory 기준이 없음 |
|
||
| API versioning | URI prefix `/v1` 기본, `X-Api-Version`은 compatibility 실험용 보조 header | `feature-api-contract-baseline` | 같은 endpoint가 path/header/media type versioning을 섞어 사용 |
|
||
| idempotency key scope | `(authenticatedPrincipal, idempotencyKey, useCaseName)` 기본, tenant 활성화 시 tenant를 앞에 추가 | `feature-rate-limit-idempotency-contract` | user 간 key collision 또는 use case 간 replay 오염 가능 |
|
||
| rate-limit key | authenticated는 principal 기준, unauthenticated는 IP + normalized route 기준. tenant 활성화 시 tenant를 prefix로 추가 | `feature-rate-limit-idempotency-contract` | tenant/user/API key/IP 기준이 branch마다 다름 |
|
||
| bootstrap command | `./gradlew bootstrap` 기본. 없는 경우 `./gradlew test` + `docker compose up` wrapper로 제공 | `feature-developer-experience-contract` | 신규 팀이 첫 실행 명령을 문서에서 판정할 수 없음 |
|
||
| Testcontainers policy | persistence/outbound integration test부터 강제, unit/architecture/contract test는 Testcontainers 금지 | `feature-test-taxonomy-fixture-contract` | contract test가 컨테이너 의존으로 느려지거나 CI 실패 원인을 흐림 |
|
||
|
||
### SSOT Owner Map
|
||
|
||
동일 계약을 여러 branch가 다루더라도 owner는 하나입니다. owner 외 branch는 producer 또는 consumer로만 기록합니다.
|
||
|
||
> 새 결정 추가 전 본 표 grep 의무 — 동일 영역의 owner 가 이미 있으면 충돌 검토.
|
||
|
||
| contract area | single SSOT owner | consumers/producers | rule |
|
||
| --- | --- | --- | --- |
|
||
| OpenAPI / schema drift | `feature-contract-verification-test-suite` | api baseline, compatibility, schema serialization | verification이 release-blocking 판정권을 가짐 |
|
||
| idempotency key | `feature-rate-limit-idempotency-contract` | api baseline, transaction, outbox, tenant | key shape와 replay semantics는 한 곳에서만 변경 |
|
||
| DLQ / retry policy | `feature-background-job-async-contract` | outbox, outbound HTTP | dead-letter abstraction은 background branch가 소유 |
|
||
| error envelope schema | `feature-operational-error-observability-foundation` | business validation, schema serialization | envelope field와 category enum은 foundation에서만 final |
|
||
| requestId/traceId/correlationId meaning | `feature-operational-error-observability-foundation` | distributed tracing, log management | ID 의미와 required 여부는 foundation에서 final |
|
||
| sample-portfolio fixture | `feature-sample-domain-contract-fixture` | verification, DX, scorecard, onboarding | sample scenario와 minimum model은 sample fixture branch만 변경 |
|
||
| actuator/health endpoint shape | `feature-runtime-health-lifecycle-contract` | management actuator security | runtime-health가 shape owner, security는 exposure policy owner |
|
||
| MDC/log key standard | `feature-operational-error-observability-foundation` | log management, metrics alerting | key 이름은 foundation registry와 일치해야 함 |
|
||
| **HTTP status ↔ envelope `error.code` 매핑** | [[raw/branch-notes/feature-operational-error-observability-foundation]] (registry `error-codes.yaml` 의 `http_status` column) | api-contract-baseline D11 (mapping consistency contract test producer) | individual mapping 변경은 registry-governance 절차 + foundation branch SSOT |
|
||
| **API versioning** (`/v1` URI prefix) | [[raw/branch-notes/feature-api-contract-baseline]] D2/D6 | api-compatibility-deprecation (Sunset header 발행 시점) | path version 외 supplemental header (`X-Api-Version`) 만 허용 |
|
||
| **HTTP header registry** (`headers.yaml` 15 rows) | `feature-api-contract-baseline` (cross-owner: idempotency, tracing, tenant, compat, security 모두 cross-cite) | tracing/tenant/security/compat 모든 branch | 새 header 추가는 본 registry yaml + api-baseline branch 경유 |
|
||
| **HTTP method 지원/실패 분류** (D12 405/Allow, D13 HEAD/OPTIONS) | [[raw/branch-notes/feature-api-contract-baseline]] D12/D13 | (no counterpart — leaf) | 405 응답 + `Allow` MUST, HEAD MUST 자동 mirror |
|
||
| **PATCH content type + mapper** | [[raw/branch-notes/feature-boundary-validation-mapping-contract]] B2 (ArchUnit `no_merge_patch_json_media_type_string` enforced) | api-contract-baseline D14 (정정 — content type 정책만 consume) | RFC 7396 (merge-patch+json) / RFC 6902 (json-patch+json) 모두 *미채택* — `application/json` only · absent/null/value 3-상태 wrapper |
|
||
| **Conditional request** (ETag / If-Match / If-None-Match / 304 / 412) | [[raw/branch-notes/feature-api-contract-baseline]] D15 | sample-portfolio fixture (WorkLogVersion 이 ETag derivation source) | DB optimistic lock 과 HTTP 412 가 동일 conflict 의 두 표현 |
|
||
| **Response cache policy + Vary header** | [[raw/branch-notes/feature-api-contract-baseline]] D16 (HTTP header 정책) | `feature-cache-consistency-contract` (cache layer 구현 SSOT) | default `Cache-Control: no-store`, Vary 의무 |
|
||
| **Long-running operation (LRO)** | [[raw/branch-notes/feature-api-contract-baseline]] D17 (polling-only) | webhook callback 패턴은 별도 `feature-webhook-outbound-contract` | 202 + `Location: /v1/operations/{id}` + polling endpoint |
|
||
| **Pagination index base + size cap** | [[raw/branch-notes/feature-api-contract-baseline]] D18 | (no counterpart — leaf) | `page` 0-indexed, `size` default 20 / max 100 |
|
||
| **Resource URL naming convention** | [[raw/branch-notes/feature-api-contract-baseline]] D19 | ArchUnit/architecture branch (controller mapping 검증) | plural + lowercase + AIP-122 regex |
|
||
| **Sort parameter syntax** | [[raw/branch-notes/feature-api-contract-baseline]] D20 | schema-serialization (field name case 정합) | Spring `Pageable` native `?sort=field,direction` |
|
||
| **Filter parameter syntax** | [[raw/branch-notes/feature-api-contract-baseline]] D21 | (no counterpart — leaf, 복잡 filter 는 future) | flat key=value (equality only) |
|
||
| **Cursor pagination shape** | [[raw/branch-notes/feature-api-contract-baseline]] D22 | `feature-security-operational-baseline` (HMAC key rotation cross-link) | opaque base64 + HMAC + 24h TTL |
|
||
| **Bulk operation URL pattern** | [[raw/branch-notes/feature-api-contract-baseline]] D23 | [[raw/branch-notes/feature-boundary-validation-mapping-contract]] B14 (BulkEnvelope.partial — async only), foundation (BATCH_PARTIAL_FAILURE — async only), [[raw/branch-notes/feature-api-contract-baseline]] D17 LRO 결합 (async batch 의 polling endpoint) | AIP-136 colon-verb (`:batchCreate`) + AIP233-C7 sync MUST atomic + partial failure 는 async LRO 만 |
|
||
| **Response Date header** | [[raw/branch-notes/feature-api-contract-baseline]] D24 | (no counterpart — leaf) | Spring/Tomcat default 자동 발행, 비활성화 금지 |
|
||
| **CORS allowlist / preflight policy** | [[raw/branch-notes/feature-security-operational-baseline]] D9 | [[raw/branch-notes/feature-api-contract-baseline]] D13 (OPTIONS preflight envelope 우회 정책 consume) | wildcard + credentials 금지 (FETCH-CORS-C3 normative) |
|
||
| **WWW-Authenticate / Server / X-Powered-By header suppression** | `feature-security-operational-baseline` | api-contract-baseline | API branch 는 forbid 만 cross-cite |
|
||
| **JSON field naming case** (camelCase vs snake_case) | `feature-schema-serialization-contract` | api-contract-baseline (envelope `meta.*` 가 camelCase 라는 cross-cite) | Jackson default + project-internal 결정 |
|
||
| **Date/Time/Decimal serialization** | `feature-schema-serialization-contract` | api-contract-baseline | ISO-8601 UTC + BigDecimal HALF_UP 등 |
|
||
| **Webhook outbound contract** (2026-05-31 신설) | `feature-webhook-outbound-contract` (scaffolding 단계) | api-contract-baseline (inbound API surface 와 분리) | signature/replay/retry/observability — 결정 박힌 후 본 표 update |
|
||
| **Streaming response (SSE/WebSocket/long-poll/chunked)** (2026-05-31 신설) | `feature-streaming-response-contract` (scaffolding 단계) | api-contract-baseline (out of scope 분리) | 1차 결정: 지원 여부 자체 |
|
||
| **Resource ID format** (ULID 26-char Crockford base32) | [[raw/branch-notes/feature-resource-identifier-contract]] D1~D19 | api-contract-baseline (URL path variable), boundary (ArchUnit rules), idempotency (Idempotency-Key 별개 명시), log-management (PII 분류), security (SecureRandom 의무) | ULID time-ordered + project §34 PostgreSQL `uuid` native + sample-portfolio `WorkLogId = "01ARZ3NDEKTSV4RRFFQ69G5FAV"` |
|
||
| **General-purpose distributed lock provider** (`distributedLockProvider` bean 메커니즘 / tx commit 정합 / lease 계약) (2026-06-12 신설) | [[raw/branch-notes/feature-distributed-lock-contract]] D1~D8 | background-job-async (scheduler/outbox 적용처 — consume), cache-consistency (Redis 분기 의존성 공유), env-driven-runtime-configuration (flag + presence 강제 owner) | bean 이름·메커니즘·해제 vs commit 순서는 본 branch 단일 owner. cache stampede lock(`CACHE_STAMPEDE_LOCK_TIMEOUT`)은 cache branch 소유로 불변 |
|
||
| **Dependency vulnerability policy** (SCA 스캐너 / CVSS 차단 임계값 / KEV override / suppression governance / 보안 update 자동화 / license scan) (2026-06-15 신설) | [[raw/branch-notes/feature-dependency-vulnerability-management-contract]] D1~D10 | ci-quality-gates (vuln scan **gate wiring** — consume), container-runtime (image scan wiring — 동일 severity 정책 consume), build-release-supply-chain (release-block **posture** + dependency-locking 선행조건 producer) | scanner·severity·suppression·update·license 정책은 본 branch 단일 owner. ci-gates D5 의 OWNER_AMBIGUITY(scanner 미결) + supply-chain D2(severity)/D3(update) 의 UNSUPPORTED 스텁이 본 branch 로 위임 정합 |
|
||
|
||
### Cross-Branch Decision Conflict Check Procedure
|
||
새 결정 추가 전 다음 절차 의무 (cross-branch SSOT 충돌 차단):
|
||
|
||
1. **본 §25 SSOT Owner Map 의 `contract area` 컬럼 grep** — 동일 영역의 owner 가 이미 있는지 확인.
|
||
- 동일 owner 가 있으면: 본 branch 가 *new owner* 가 아닌 *consumer/producer* 로만 결정 가능.
|
||
- 동일 owner 가 없으면: 본 branch 가 new owner 가 될 수 있음 — 그러나 *주제어 다른* 결정이 sibling branch 에 있을 수 있음 → 2번 진행.
|
||
2. **sibling branch grep** — `grep -rn "<주요 키워드>" raw/branch-notes/feature-*.md` 로 sibling 의 §결정 사항 / §Decision Evidence Map / §Decisionized Work Items 에 동일 키워드 검색.
|
||
- 예: PATCH 결정 추가 전 `grep -rn "PATCH\|merge-patch" raw/branch-notes/feature-*.md` 로 boundary branch B2 사전 발견 가능했음.
|
||
3. **충돌 발견 시 적용 기준**:
|
||
- **검증 깊이 우선**: ArchUnit / static rule / contract test 가 있는 결정이 SSOT.
|
||
- **결정 도메인 우선**: 결정이 *어느 영역의 자연스러운 책임*인지 — PATCH mapper 는 boundary 영역.
|
||
- **시간 순서**: 같은 깊이 + 같은 도메인이면 *먼저 박힌* 결정이 SSOT, 늦게 박은 것이 정정.
|
||
4. **본 §25 표에 신규 row 추가** — 결정 박은 후 본 표에 owner + consumers/producers + rule 명시.
|
||
|
||
이 절차는 추후 `/lint` 명령 또는 `wiki-adversarial-reviewer` 가 자동 검사하도록 확장 가능 (현재는 수동 절차).
|
||
|
||
### Multi-Instance Guardrail
|
||
|
||
이 skeleton의 core contract는 기본적으로 single-instance에서 완결됩니다. HPA, multi-replica scheduler, distributed rate limit, outbox publisher leader election, migration concurrent startup, distributed cache lock은 `multi-instance contract package`가 활성화될 때만 지원 범위에 들어옵니다.
|
||
|
||
<!-- section-id: project-decisions -->
|
||
## 6.1 안정 결정 레지스트리
|
||
|
||
> Project contract v2의 project-wide decision SSOT. §25의 15개 blocking default와 §34 Stack Commitment를 stable ID로 pin한다.
|
||
|
||
| Decision ID | Revision | Domain | Decision Summary | Status | Owner | Evidence |
|
||
|---|---:|---|---|---|---|---|
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001` | 1 | `module-layout` | Gradle multi-module에서 domain-core·application-core·adapter-*·shared-contract·app-bootstrap·sample-portfolio 책임을 분리한다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §25 Blocking Defaults `package layout` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-TRANSACTION-001` | 1 | `transaction` | application은 Spring transaction annotation 대신 TransactionPort 또는 TransactionalUseCaseRunner를 사용한다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §25 `transaction boundary` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MAPPING-001` | 1 | `mapping` | 수기 mapper와 record canonical constructor가 default이며 MapStruct는 optional profile이다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §25 `mapper tool` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-ERROR-ENVELOPE-001` | 1 | `error-envelope` | foundation이 envelope schema와 error.category enum의 단일 owner다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §25 `error envelope schema` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-OPENAPI-001` | 1 | `openapi` | verification suite가 OpenAPI drift의 release-blocking 판정권을 소유한다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §25 `OpenAPI drift` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MIGRATION-001` | 1 | `migration` | Flyway는 startup에서 실행하고 migration 완료 후에만 readiness를 healthy로 전환한다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §25 `migration runner` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-SCHEDULER-LOCK-001` | 1 | `scheduler-lock` | single-instance가 default이며 multi-instance scheduler/outbox는 DB advisory lock을 사용한다 | `conditional-default` | [[raw/project-notes/ca-skeleton-operational-contract]] | §25 `scheduler/outbox lock` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-EVENT-BROKER-001` | 1 | `event-broker` | core는 broker-agnostic outbox를 제공하고 Kafka는 optional adapter로 둔다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §25 `broker` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-RESILIENCE-001` | 1 | `resilience` | Resilience4j가 default이며 Spring Retry는 simple blocking retry에만 허용한다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §25 `circuit breaker/retry` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-CONTAINER-001` | 1 | `container` | Temurin JRE slim이 default이며 distroless는 debug/runbook 보강 후 허용한다 | `conditional-default` | [[raw/project-notes/ca-skeleton-operational-contract]] | §25 `container base image` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-API-VERSIONING-001` | 1 | `api-versioning` | URI prefix /v1이 default이며 X-Api-Version은 compatibility 실험용 보조 header다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §25 `API versioning` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-IDEMPOTENCY-001` | 1 | `idempotency` | idempotency scope는 principal·key·useCase이며 tenant 활성화 시 tenant를 prefix한다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §25 `idempotency key scope` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-RATE-LIMIT-001` | 1 | `rate-limit` | authenticated는 principal, unauthenticated는 IP와 normalized route를 rate-limit key로 사용한다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §25 `rate-limit key` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-BOOTSTRAP-001` | 1 | `bootstrap` | 신규 환경의 default 진입 명령은 ./gradlew bootstrap이다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §25 `bootstrap command` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-TESTCONTAINERS-001` | 1 | `testcontainers` | Testcontainers는 persistence/outbound integration test에 사용하고 unit·architecture·contract test에서는 금지한다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §25 `Testcontainers policy` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-LANGUAGE-001` | 1 | `stack-language` | application language는 Java 21 LTS다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §34 Stack Matrix `Language` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-FRAMEWORK-001` | 1 | `stack-framework` | framework는 Spring Boot 3.5.14다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §34 Stack Matrix `Framework` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-ORM-001` | 1 | `stack-orm` | ORM은 Spring Boot transitive Hibernate ORM 6.5.x다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §34 Stack Matrix `ORM` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-JSON-001` | 1 | `stack-json` | JSON stack은 Spring Boot transitive Jackson 2.18.x다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §34 Stack Matrix `JSON` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-DATABASE-001` | 1 | `stack-database` | database는 PostgreSQL 16 단일 stack이다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §34 Stack Matrix `DB` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-MIGRATION-001` | 1 | `stack-migration` | schema migration tool은 Spring Boot transitive Flyway다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §34 Stack Matrix `Migration` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-BUILD-001` | 1 | `stack-build` | build tool은 Gradle Groovy DSL이다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §34 Stack Matrix `Build tool` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-TEST-001` | 1 | `stack-test` | test framework는 JUnit 5다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §34 Stack Matrix `Test framework` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-ARCHTEST-001` | 1 | `stack-archtest` | architecture test는 archunit-junit5 1.3.0을 사용한다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §34 Stack Matrix `Architecture test` |
|
||
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-RANDOM-001` | 1 | `stack-random` | ULID·idempotency key·token 생성의 random source는 SecureRandom이다 | `active` | [[raw/project-notes/ca-skeleton-operational-contract]] | §34 Stack Matrix `Random source` |
|
||
|
||
| area | single-instance default | multi-instance activation requirement |
|
||
| --- | --- | --- |
|
||
| scheduler | single worker only | DB advisory lock 또는 ShedLock contract test |
|
||
| outbox publisher | one publisher in app process | publisher ownership lock + duplicate publish idempotency |
|
||
| rate limiter | in-memory or app-local policy allowed only for local/dev | Redis/distributed counter + tenant/principal key contract |
|
||
| migration runner | one app startup runner | platform-level one-shot job or migration lock verification |
|
||
| cache stampede | local test policy only | distributed lock or stale-while-revalidate policy |
|
||
| idempotency key concurrency | DB unique constraint required | serializable insert-or-read contract test |
|
||
|
||
multi-instance를 지원한다고 말하려면 위 행 중 적용 영역의 contract test가 있어야 합니다. 없으면 문서와 README에 `single-instance skeleton`이라고 명시합니다.
|
||
|
||
### Minimum Missing-Area Defaults
|
||
|
||
아래 영역은 full implementation이 없어도 skeleton default는 있어야 합니다.
|
||
|
||
| area | default | owner branch |
|
||
| --- | --- | --- |
|
||
| deployment manifest sync | app shutdown timeout, `terminationGracePeriodSeconds`, `preStop`, readiness/liveness/startup probe 값을 한 표에서 관리 | `feature-container-runtime-contract` |
|
||
| DSR | delete/export request는 core domain out of scope이나 PII inventory, redaction point, audit log retention은 privacy branch가 관리 | `feature-data-retention-privacy-contract` |
|
||
| feature flag | runtime toggle은 optional. 기본은 env-startup flag이며 canary/runtime flag 도입 시 registry row 필요 | `feature-env-driven-runtime-configuration` |
|
||
| signed artifact | SBOM + image digest를 기본으로 하고, release branch에서 Cosign/SLSA provenance를 delivery target으로 둠 | `feature-build-release-supply-chain-contract` |
|
||
| dependency upgrade | Renovate 또는 Dependabot 중 하나를 선택하고 security PR은 CI quality gate와 연결 | `feature-build-release-supply-chain-contract` |
|
||
| JWT key rotation | JWKS refresh failure, stale key, unknown `kid`, rotation overlap window를 security failure catalog에 포함 | `feature-security-operational-baseline` |
|
||
| JVM ergonomics | `-XX:MaxRAMPercentage=75`, UTC timezone, OOMKilled vs JVM OOM 분류를 container/runtime branch가 소유 | `feature-container-runtime-contract` |
|
||
| CORS | allowlist + preflight cache seconds는 security branch owner, gateway override 시 mapping 필요 | `feature-security-operational-baseline` |
|
||
|
||
| 항목 | 기본 결정 | 예외 허용 조건 | 테스트 실패 조건 |
|
||
| --- | --- | --- | --- |
|
||
| response envelope field | `success`, `data`, `error`, `meta` | 외부 gateway 표준이 이미 존재할 때만 adapter에서 변환 | 실패 응답에 `error.code`, `error.category`, `meta.requestId` 누락 |
|
||
| error code naming | category 기반 `UPPER_SNAKE_CASE` | provider-specific code는 `dependency.code`에만 보관 | raw exception class name을 code로 사용 |
|
||
| repository capability annotation | `@UseCaseRepositoryAccess` | AOP 대신 ArchUnit/compile-time checker를 쓸 경우 이름만 변경 가능 | 선언 없는 write/bulk/sensitive repository 접근 |
|
||
| env prefix | application-owned key는 `APP_` prefix 사용 | Spring/infra 표준 env는 원래 이름 유지 | 동일 의미 env가 profile마다 다른 이름으로 존재 |
|
||
| log schema | OpenTelemetry semantic convention을 우선 참고하고 app-specific field는 `app.*`, error field는 `error.*`로 둠 | 수집기가 ECS를 강제하면 adapter mapping 문서 필요 | trace/log/error field naming이 branch마다 다름 |
|
||
| tracing implementation | Micrometer Tracing + OpenTelemetry exporter 기준 | exporter 미사용 local profile 가능 | traceId가 inbound/outbound/async/log에서 연결되지 않음 |
|
||
| optional adapter packaging | optional module로 분리하고 disabled env가 기본 | 단순 문서 샘플은 `sample` source set 허용 | disabled adapter bean이 기본 앱 시작에 필요 |
|
||
| sample domain | `sample-portfolio` | 더 작은 fixture가 모든 계약을 검증할 때만 변경 | sample 없이 boundary/repo/transaction/error 계약을 검증 |
|
||
| OpenAPI drift | generated OpenAPI snapshot + contract test | mature openapi-diff 도구 도입 가능 | schema와 실제 envelope/field가 불일치해도 build 통과 |
|
||
| idempotency storage | DB table 기반 key/result/status/ttl 저장 | Redis는 optional adapter에서만 보조 저장소 | retry 시 duplicate write 발생 |
|
||
| migration tool | Flyway 기본 | 조직 표준이 Liquibase일 때만 변경 | migration 실패 후 readiness가 healthy |
|
||
| metric naming | Micrometer naming + low-cardinality tag만 허용 | 수집기 표준 prefix가 있을 때 mapping | userId/orderId 같은 high-cardinality tag 사용 |
|
||
| alert severity | `P1`, `P2`, `P3` | 조직 on-call 표준 명칭 사용 가능 | severity 없는 alert |
|
||
| secret manager | 기본 계약은 env/secret file, prod는 external secret manager 연동 가능하도록 추상화 | local은 `.env` 허용 | prod에서 secret/config dump 노출 |
|
||
| actuator management port | prod/staging은 분리 권장, local/dev는 app port 허용 | platform ingress가 별도 보호를 제공할 때만 단일 port | prod에서 env/configprops 노출 |
|
||
| multi-tenancy | skeleton core는 out of scope, tenant header는 기본 거부 | tenant branch에서 명시 활성화 | tenant context 없이 tenant-scoped repository 접근 |
|
||
| file upload/download | sample v1에는 미포함, core contract만 제공 | file branch에서 sample fixture 추가 가능 | path traversal/content type/size limit 미검증 |
|
||
| cache consistency | core contract에 원칙을 두고 Redis optional adapter에서 구현 | in-memory sample cache는 테스트 전용 | cache miss를 장애로 분류하거나 invalidation 실패를 무시 |
|
||
| domain onboarding template | `domain-core` / `application-core` / `adapter-*` / `shared-contract` 기준으로 read/write module slice를 추가 | read-only feature는 write/idempotency/outbox 구성을 생략 가능 | controller/use case/domain/repository 중 하나만 단독 추가되어 계약 검증 불가 |
|
||
| command/query split | command use case와 query use case 분리 | 단순 admin endpoint도 명시적으로 하나를 선택 | write use case가 query naming으로 transaction/capability를 우회 |
|
||
| port naming | inbound는 `*UseCase`, outbound는 `*Port` | 조직 표준 이름이 있으면 branch에서 대체 가능 | application이 infrastructure adapter 구현체를 직접 의존 |
|
||
| domain event | domain event와 integration event 분리 | 외부 발행이 없는 내부 event는 integration mapping 생략 가능 | domain event가 Kafka/HTTP/Slack 같은 transport detail을 가짐 |
|
||
| sample adoption | `sample-portfolio`은 제거 가능한 fixture이며 새 도메인은 구조만 참고 | 교육용 프로젝트에서는 sample 유지 가능 | production package가 sample package를 import |
|
||
| package blueprint | `domain-core` / `application-core` / `adapter-*` / `shared-contract` / `app-bootstrap` / `sample-portfolio` 멀티모듈 기본 구조 사용 | demo/readme용 single-module 축소형은 같은 responsibility mapping 보존 시 허용 | domain/business code가 shared-contract 또는 adapter module에 들어감 |
|
||
| registry governance | error/env/header/log/metric/capability는 registry로 관리 | 외부 platform 표준이 있으면 mapping table 필수 | 문자열/enum이 문서나 구현에 ad hoc으로 흩어짐 |
|
||
| test taxonomy | unit/contract/architecture/slice/integration/smoke를 분리 | 작은 프로젝트는 디렉터리만 합칠 수 있음 | contract test와 integration test가 섞여 실패 원인을 구분 못함 |
|
||
| readiness score | canonical 승급 전 scorecard 전 항목 통과 | raw 초안 단계는 미통과 허용 | 미통과 항목이 있는데 100점 문서로 선언 |
|
||
|
||
## 26. Universal Acceptance Gate
|
||
|
||
각 branch는 완료 전에 아래 질문에 모두 답할 수 있어야 합니다. 하나라도 답하지 못하면 canonical 문서로 승급하지 않습니다.
|
||
|
||
```text
|
||
1. 이 기준은 어떤 실패를 막는가?
|
||
2. 구현자가 선택해야 하는 기본값은 무엇인가?
|
||
3. 허용되는 예외는 무엇이며 조건은 무엇인가?
|
||
4. 절대 금지되는 것은 무엇인가?
|
||
5. 어떤 env/log/response/test field가 필수인가?
|
||
6. 어떤 테스트가 깨져야 이 계약 위반을 알 수 있는가?
|
||
7. sample-portfolio으로 검증 가능한가?
|
||
8. sample-portfolio 제거 후에도 skeleton core에 남는가?
|
||
9. 실제 도메인 feature가 이 기준을 그대로 따라갈 수 있는가?
|
||
10. 이 내용을 wiki/projects canonical 문서의 어느 섹션으로 승급할 것인가?
|
||
```
|
||
|
||
100점 기준은 문장 완성도가 아니라 contract 강제력입니다.
|
||
|
||
```text
|
||
문서만 읽고도 구현 방향이 하나로 수렴하고,
|
||
테스트만 봐도 계약 위반을 감지할 수 있으며,
|
||
sample-portfolio을 제거한 뒤에도 실제 도메인 feature가 같은 구조로 들어갈 수 있어야 한다.
|
||
```
|
||
|
||
## 27. 100점 Readiness Scorecard
|
||
|
||
아래 항목 중 하나라도 `No`이면 이 skeleton은 100점이 아닙니다.
|
||
|
||
| 영역 | 질문 | 통과 기준 |
|
||
| --- | --- | --- |
|
||
| 구조 | 새 도메인 feature의 위치가 명확한가? | module blueprint와 onboarding slice가 일치 |
|
||
| 응답 | 모든 성공/실패 응답이 envelope를 따르는가? | OpenAPI snapshot과 contract test로 강제 |
|
||
| 오류 | error category/code/status/retryable/log level이 registry에 있는가? | ad hoc error string 금지 |
|
||
| 경계 | request/application/domain/response/filter mapper가 모두 있는가? | 경계 우회 architecture test |
|
||
| 예외 | raw exception이 presentation까지 새지 않는가? | leakage contract test |
|
||
| 로그 | 필수 log field와 금지 field가 테스트되는가? | log capture test |
|
||
| trace | inbound/outbound/async/message trace가 연결되는가? | propagation contract test |
|
||
| env | profile별 env matrix와 fail-fast가 있는가? | startup smoke test |
|
||
| repo | use case capability와 repository capability가 매칭되는가? | architecture/contract test |
|
||
| adapter | 모든 dependency failure가 같은 언어로 분류되는가? | adapter failure mapping test |
|
||
| domain | domain이 framework-neutral한가? | forbidden import test |
|
||
| sample | sample-portfolio 제거 후 core가 살아 있는가? | sample removal smoke test |
|
||
| CI | contract violation이 release-blocking인가? | CI quality gate |
|
||
| 운영 | alert/runbook/metric/log/trace가 연결되는가? | operational runbook link |
|
||
| 보안 | token/PII/secret/body가 노출되지 않는가? | privacy/log leakage test |
|
||
|
||
## 28. Review Remediation Ledger
|
||
|
||
이 섹션은 2026-05-22 senior review의 지적을 100% 추적하기 위한 ledger입니다. `Closed by default`는 이 raw project note와 branch note에 기본값/owner/failure condition이 반영되었다는 뜻이고, 구현 완료를 뜻하지 않습니다.
|
||
|
||
### Critical Defaults
|
||
|
||
| review item | closed by default | owner branch | required branch evidence |
|
||
| --- | --- | --- | --- |
|
||
| package layout | Gradle multi-module Clean Architecture (`domain-core`, `application-core`, `adapter-*`, `shared-contract`, `app-bootstrap`, `sample-portfolio`) | `feature-skeleton-package-blueprint-contract` | module dependency rule + package blueprint + architecture rule |
|
||
| transaction boundary | application responsibility via `TransactionPort`/`TransactionalUseCaseRunner`, no direct Spring transaction import | `feature-application-port-usecase-contract` | forbidden import test + write use case contract |
|
||
| mapper tool | manual mapper + record canonical constructor; MapStruct optional with generated exemption | `feature-boundary-validation-mapping-contract` | mapper boundary test |
|
||
| error envelope schema SSOT | foundation branch owns envelope/category/ID meanings | `feature-operational-error-observability-foundation` | envelope contract test |
|
||
| OpenAPI drift SSOT | verification suite owns drift gate | `feature-contract-verification-test-suite` | generated snapshot + drift check |
|
||
| migration runner | Flyway app startup default, readiness healthy only after migration success | `feature-migration-startup-contract` | migration failure startup/readiness test |
|
||
| scheduler/outbox lock | single-instance default, DB advisory lock or ShedLock required for multi-instance | `feature-background-job-async-contract` | overlap/duplicate publish test |
|
||
| broker | broker-agnostic outbox core, Kafka optional adapter | `feature-domain-event-outbox-contract` | transport-free domain event test |
|
||
| circuit breaker/retry | Resilience4j default, Spring Retry limited exception | `feature-outbound-http-client-baseline` | retry/circuit metrics test |
|
||
| container base image | Temurin JRE slim default; distroless requires runbook/debug proof | `feature-container-runtime-contract` | non-root + JVM memory smoke |
|
||
| versioning | `/v1` URI prefix default; `X-Api-Version` supplemental only | `feature-api-contract-baseline` | OpenAPI version path test |
|
||
| idempotency key scope | `(principal, key, useCaseName)`, tenant prefix if enabled | `feature-rate-limit-idempotency-contract` | duplicate replay/tenant collision test |
|
||
| rate-limit key | authenticated principal; unauthenticated IP + normalized route; tenant prefix if enabled | `feature-rate-limit-idempotency-contract` | 429 envelope + key scope test |
|
||
| bootstrap tool | `./gradlew bootstrap` default | `feature-developer-experience-contract` | bootstrap smoke |
|
||
| Testcontainers policy | integration tests only; unit/contract/architecture no container | `feature-test-taxonomy-fixture-contract` | test taxonomy ownership table |
|
||
|
||
### SSOT Closures
|
||
|
||
| duplicated area | single owner | consumer rule |
|
||
| --- | --- | --- |
|
||
| OpenAPI/schema drift | `feature-contract-verification-test-suite` | API/schema branches produce artifacts only |
|
||
| idempotency key | `feature-rate-limit-idempotency-contract` | transaction/outbox/API/tenant consume key shape |
|
||
| DLQ/retry policy | `feature-background-job-async-contract` | outbox/outbound map their failures into the common DLQ vocabulary |
|
||
| error envelope schema | `feature-operational-error-observability-foundation` | business/schema branches cannot add envelope fields |
|
||
| trace/request/correlation ID semantics | `feature-operational-error-observability-foundation` | tracing/log branches consume names and meanings |
|
||
| sample-portfolio fixture | `feature-sample-domain-contract-fixture` | verification/DX/scorecard/onboarding consume scenarios |
|
||
| actuator/health endpoint shape | `feature-runtime-health-lifecycle-contract` | management security controls exposure only |
|
||
| MDC/log key standard | `feature-operational-error-observability-foundation` | log/metric branches use registry names |
|
||
|
||
### Multi-Instance Closures
|
||
|
||
| risk | default closure | required if multi-instance is claimed |
|
||
| --- | --- | --- |
|
||
| distributed scheduler lock | single worker only | ShedLock or DB advisory lock test |
|
||
| outbox publisher leader election | one publisher in app process | publisher ownership lock + idempotent publish |
|
||
| distributed rate limit | local/dev only | Redis/distributed counter contract |
|
||
| migration concurrent startup | one app startup runner | platform job or migration lock proof |
|
||
| cache distributed lock/stampede | local test policy only | distributed lock or stale-while-revalidate proof |
|
||
| idempotency concurrent arrival | DB unique insert-or-read | concurrent replay test |
|
||
|
||
### Missing Area Closures
|
||
|
||
| missing area | default closure | owner branch |
|
||
| --- | --- | --- |
|
||
| deployment manifest sync | app timeout, `terminationGracePeriodSeconds`, `preStop`, startup/readiness/liveness probes must share one table | `feature-container-runtime-contract` |
|
||
| API gateway/WAF/Ingress | gateway may reject TLS/request-size/WAF before app; app must document envelope bypass and log correlation | `feature-security-operational-baseline` |
|
||
| DSR delete/export | privacy branch owns DSR intake, identity verification, export/delete workflow, audit evidence | `feature-data-retention-privacy-contract` |
|
||
| disaster recovery/restore drill | backup without restore drill is non-compliant; quarterly local/staging restore smoke default | `feature-persistence-failure-baseline` |
|
||
| feature flag system | env-startup flags default; runtime/canary flags need registry row and owner | `feature-env-driven-runtime-configuration` |
|
||
| signed artifact/SLSA/provenance | SBOM + image digest baseline; Cosign signature and provenance are release targets | `feature-build-release-supply-chain-contract` |
|
||
| dependency upgrade policy | Renovate default, Dependabot allowed if org standard | `feature-build-release-supply-chain-contract` |
|
||
| JWT key rotation/JWKS refresh | unknown `kid`, stale JWKS, refresh failure, overlap window are explicit security failures | `feature-security-operational-baseline` |
|
||
| JVM ergonomics | `-XX:MaxRAMPercentage=75`, UTC, OOMKilled vs JVM OOM classification | `feature-container-runtime-contract` |
|
||
| DB read replica/lag | primary reads default; replica use requires max lag threshold and stale-read contract | `feature-persistence-failure-baseline` |
|
||
| CORS preflight/origin allowlist | explicit allowlist, credentials policy, max-age default, gateway override mapping | `feature-security-operational-baseline` |
|
||
| antivirus/file scanning | upload scanning is off by default; external gateway/worker/app-owner decision must be documented | `feature-file-resource-handling-contract` |
|
||
|
||
### Conflict Closures
|
||
|
||
| conflict | closure |
|
||
| --- | --- |
|
||
| domain logger ban vs invariant diagnostics | domain still has no logger; application translates invariant violation and logs client-safe reason code outside domain |
|
||
| `@Transactional` vs application independence | direct Spring transaction import forbidden; transaction port abstraction required |
|
||
| tracing disabled vs required `traceId` | generated opaque trace id remains in envelope; exporter/sampling may be disabled |
|
||
| migration readiness race | startup/readiness remains unhealthy until migration success and startup validation complete |
|
||
|
||
### Self-Contradiction Closures
|
||
|
||
| contradiction | closure |
|
||
| --- | --- |
|
||
| Work Item Contract exists but TODOs stay vague | branch notes must add `Decisionized Work Items` before canonical promotion; TODO list remains raw backlog only |
|
||
| scorecard 100점 but calculator out of scope | scorecard branch owns manual formula and evidence table; automation is optional, formula is not |
|
||
| runbook link required but unverifiable | runbook branch defines link format and CI/link-check smoke; broken placeholder links fail promotion |
|
||
|
||
### Phase A / B / C1 Closures (2026-05-22)
|
||
|
||
4차 audit 이후 다음 phase가 진행되었으며, 산출물은 본 문서와 `ca-tmpl/docs/registries/` 하위 yaml로 분리됩니다.
|
||
|
||
| phase | scope | 산출물 | status |
|
||
| --- | --- | --- | --- |
|
||
| Phase A | numeric conflict 15건, SSOT violation 7건, TODO drain 28+ 파일, 표 양식 자기모순(Work Item Contract 7-required → 4 mandatory + 3 conditional relax), 자기 중복 4건, intent clarification 5건 | 43 branch note 수정 | closed |
|
||
| Phase B | 7개 registry yaml 본문 작성 (총 196 rows, source-grounded) | `ca-tmpl/docs/registries/{error-codes,env-keys,secrets-classification,headers,mdc-keys,metrics,capabilities}.yaml` | closed |
|
||
| Phase C1 | 본 canonical contract 문서에 yaml SSOT reference 반영 + Phase A/B closures 기록 | 본 문서 §21 + §28 갱신, frontmatter `last_reviewed: 2026-05-22` | closed |
|
||
| Phase D1 | test contract 정밀화 (VAGUE 38건 → IMPLEMENTABLE, PARTIAL 88건의 3개 공통 패턴(capability marker / disabled detection / claim parsing) 결정 박기) | 43 branch note 정밀화 | closed |
|
||
| Phase D2 | runbook stub 5종 작성 (release-blocking 5 category 첫 운영 시나리오) | `ca-tmpl/docs/runbooks/*.md` | closed |
|
||
| Phase C2 | ca-tmpl 실 skeleton 코드 (별도 git repo) | build.gradle, application-*.yml, ArchUnit rules, TransactionPort, @UseCaseRepositoryAccess, capability enum, sample-portfolio entity/use case/fixture, Flyway script, OpenAPI snapshot, CI workflow, Cosign/SLSA, docker-compose.yml, .env.example (env-keys.yaml에서 generated) | pending (external) |
|
||
|
||
#### Phase A 세부 closures
|
||
|
||
**Numeric conflicts (4차 audit L1 / 15건)**: executor await 25s→19s (background-job-async); `database default`→`READ_COMMITTED` (application-port-usecase, transaction-concurrency SSOT 위임); `AUTHORIZATION`→`AUTHZ` (business-rule-validation enum 정합); MDC 4 vs 6 rationale (background-job span_id 자동·user_principal opt-in); "9 base + 2 = 11" 통일 (contract-verification); tenant_id cardinality vs ULID 분리 (metric tag 미사용, mapping id/cohort bucket); error_code cardinality registry 동기화; audit log retention 단일 owner = data-retention; outbox claim isolation = `READ_COMMITTED` + SKIP LOCKED 명시; log 10% vs trace 1% sampling 의도 분리; idempotency 24h vs JWT rotation 24h invariant; NESTED/NEVER forbidden 일관; alert dedup 5분 vs P1 2분 noise 억제 의도; file size 3계층 defense-in-depth (Spring 10MB / global 12MB / gateway 20MB); outbound HTTP shutdown retry suppression.
|
||
|
||
**SSOT violations (4차 audit L1 / 7건)**: audit retention 단일 owner = `feature-data-retention-privacy-contract` (log-management는 형식만 owns); outbox claim transaction isolation 명시 = `feature-domain-event-outbox-contract`; TaskDecorator SSOT = `feature-background-job-async-contract` (tenant/security 모두 consumer); security ↔ secrets 양방향 cross-link; runtime-health ↔ integration-adapter 양방향 cross-link; identifier 표기 layer mapping (MDC snake_case / envelope camelCase / HTTP header kebab-case) = `feature-distributed-tracing-contract`; flaky quarantine SSOT = `feature-ci-quality-gates-contract` (test-taxonomy consumer).
|
||
|
||
**TODO drain (28+ 파일)**: stale `planned` TODO를 표 row link 또는 제거. `needs-confirmation` 2건 의도적 retain (verification PII forbidden 구현 메커니즘 / scorecard real-domain dry-run checklist SSOT 분담).
|
||
|
||
**Self-duplicates 해소 (4건)**: transaction-concurrency isolation 2회→1회, management-actuator-security prod allowlist 2회→final list 1회, developer-experience DX Defaults 표 deprecated → Decisionized SSOT, ci-quality-gates Gate Matrix → Gate Ownership Matrix SSOT.
|
||
|
||
**표 양식 자기모순**: `feature-architecture-enforcement-rules`의 Work Item Contract 메타 표를 "7 required" → "4 mandatory (Decision/Allowed/Forbidden/Required contract test) + 3 conditional (Required registry update / Failure condition / Canonical extraction target)"로 relax. 14+ 파일의 5-column 표가 더 이상 자기모순 아님.
|
||
|
||
**Intent clarifications (5건)**: log 10% vs trace 1% sampling 의도 분리 (운영 진단 vs cost 제어), idempotency TTL ≤ JWT rotation overlap window invariant, negative cache 60s vs eventual consistency window 5s 독립축, alert dedup 5분 + P1 2분 noise 억제, file size 3계층 defense-in-depth.
|
||
|
||
#### Phase B 세부 closures
|
||
|
||
7개 yaml 본문 작성 결과:
|
||
|
||
| yaml | rows | 주요 정합 포인트 |
|
||
| --- | --- | --- |
|
||
| `error-codes.yaml` | 49 | category 분포 TRANSIENT_DEPENDENCY 15 · AUTH 8 · INTERNAL 8 · VALIDATION 6 · CONFLICT 4 · AUTHZ 3 · DATA_INTEGRITY 3 · RATE_LIMIT 1 · PERMANENT_DEPENDENCY 1 · NOT_FOUND 0. runbook coverage 100%. |
|
||
| `env-keys.yaml` | 51 | 15개 영역. `APP_` prefix 강제. `reload_policy: restart-only` default. classification cross-link with secrets-classification.yaml. |
|
||
| `secrets-classification.yaml` | 15 | secret 6 / sensitive-config 4 / public-config reference 5. rotation policy 5종 (restart-only / dual-bind-60s / overlap-24h / salt-rotation-90d / manual). prod sentinel prefix `__LOCAL_DEV_` 검증. |
|
||
| `headers.yaml` | 15 | naming 정합 (kebab/lowercase/W3C). direction inbound 3 / outbound 7 / both 5. mdc_key + envelope_meta_field cross mapping 4쌍. |
|
||
| `mdc-keys.yaml` | 19 | foundation core 6 + log extension 13. propagation matrix (http 5 / async 5 / message 4 / none 14). cardinality_safe_for_metric flag로 metric tag 적격 9 / 부적격 10 분리. |
|
||
| `metrics.yaml` | 25 | Micrometer dot.case + unit suffix. cardinality bounds 강제. P1/P2/P3 정량 threshold. high-cardinality forbidden tag 0건. |
|
||
| `capabilities.yaml` | 7 | enforcement ArchUnit SSOT (AOP forbidden). BULK_WRITE threshold N>100. EXTERNAL_OUTBOUND_ALLOWED의 outbox in-process 제외 명시. |
|
||
|
||
품질 정합:
|
||
- 모든 row에 source branch + line 인용 yaml comment.
|
||
- 추측 금지 원칙 준수 (source에 명시되지 않은 row 0개).
|
||
- Cross-registry 정합 (header ↔ MDC ↔ envelope, env ↔ secrets, capability ↔ repository-access ↔ TransactionPort).
|
||
- Runbook coverage 정책 100% (error-codes.yaml row 검증).
|
||
- 명명 규칙 일관: error UPPER_SNAKE / env `APP_` prefix / MDC snake / header kebab / W3C lowercase / metric dot.case.
|
||
|
||
#### Phase C1 closures (this update)
|
||
|
||
- §21 Contract Registry 본문 6개 inline 표를 yaml SSOT reference + 요약 7개 subsection으로 재구성. inline 표의 stale category 명명(`AUTHENTICATION`/`AUTHORIZATION`/`PERSISTENCE`/`DEPENDENCY`/`MESSAGE`/`CACHE`/`NOTIFICATION`)을 foundation enum(`AUTH`/`AUTHZ`/`DATA_INTEGRITY`/`TRANSIENT_DEPENDENCY`/`PERMANENT_DEPENDENCY`)으로 정합. 더 이상 inline ≠ yaml 충돌 없음.
|
||
- §28에 Phase A/B/C1 closures 추가. Phase D1/D2/C2는 pending으로 명시.
|
||
- Header note(`> 이 문서는...`)에 phase 진척 한 줄 추가.
|
||
- frontmatter `last_reviewed: 2026-05-22`로 갱신.
|
||
|
||
#### Phase D1 closures (2026-05-22)
|
||
|
||
Test contract 정밀화 + cross-cutting 결정 + needs-confirmation 해소.
|
||
|
||
**VAGUE → IMPLEMENTABLE (38건)**:
|
||
|
||
| owner branch | item 수 | 정밀화 패턴 |
|
||
| --- | --- | --- |
|
||
| feature-implementation-readiness-scorecard | 6 | 각 readiness 기준을 yaml registry row count + CI step grep + manual evidence column으로 측정 가능하게 (scorecard는 onboarding dry-run consume only — SSOT는 `feature-domain-feature-onboarding-contract`) |
|
||
| feature-operational-runbook-contract | 4 | alert payload field 명시 + runbook link target file 존재 verify + placeholder regex 검출 |
|
||
| feature-test-taxonomy-fixture-contract | 3 | PR diff regex로 contract/architecture test 동반 변경 강제 + sample fixture prod profile 누출 검출 |
|
||
| feature-contract-verification-test-suite | 2 | ArchUnit으로 contract test의 도메인 import 금지 + 9 base contract test enumeration |
|
||
| feature-developer-experience-contract | 2 | fresh-clone-smoke CI job + verifyReadmeCommands Gradle task |
|
||
| feature-container-runtime-contract | 3 | server.shutdown=graceful property verify + temp cleanup 3 trigger + JVM OOM exit code 검출 |
|
||
| feature-file-resource-handling-contract | 2 | TempFileCleanupContractTest 3 trigger + antivirus position branch note grep |
|
||
| feature-env-driven-runtime-configuration | 1 | @FeatureFlag/APP_FEATURE_* row 존재 verify |
|
||
| feature-secrets-config-source-contract | 1 | @RefreshScope bean 금지 verify |
|
||
| feature-ci-quality-gates-contract | 3 | workflow yaml의 needs/if gate + openapi-diff exit code + sample-removal-smoke job verify |
|
||
| feature-background-job-async-contract | 2 | ApplicationListener<ContextClosedEvent> bean verify + ShedLock LockProvider 등록 verify |
|
||
| feature-cache-consistency-contract | 2 | @Cacheable sync=true ArchUnit + RedissonClient bean verify when multi-instance |
|
||
| feature-domain-modeling-guardrails | 2 | @ValueObject 생성자 protection + @AggregateRoot setter visibility ArchUnit |
|
||
| feature-domain-event-outbox-contract | 1 | OutboxPublisherLeaderElectionContractTest 2-context dedup verify |
|
||
| feature-security-operational-baseline | 1 | SecurityFilterChain.getFilters() snapshot diff |
|
||
| feature-management-actuator-security-contract | 1 | branch ownership boundary ArchUnit |
|
||
|
||
**PARTIAL 공통 패턴 결정 (3종)**:
|
||
|
||
| 패턴 | owner branch | 결정 |
|
||
| --- | --- | --- |
|
||
| capability marker | feature-repository-access-permission-contract | Java annotation `@UseCaseRepositoryAccess(value=Capability[])`, retention RUNTIME, target METHOD. `Capability` enum은 capabilities.yaml SSOT와 1:1. consumer는 annotation consume only. |
|
||
| disabled adapter detection | feature-integration-adapter-templates | 3-layer: (1) startup Spring `@ConditionalOnProperty`, (2) build-time ArchUnit `noClasses().that().resideInAPackage("..application..").should().dependOnClassesThat().resideInAPackage("..adapters.{disabled}..")`, (3) runtime fail-fast `AdapterDisabledException`. adapter 추가 시 env-keys.yaml에 row 필수. |
|
||
| claim parsing (multi-instance) | feature-env-driven-runtime-configuration | env `APP_MULTI_INSTANCE_ENABLED` boolean. true 시 ShedLock + Redisson + outbox SKIP LOCKED + distributed rate limiter + platform migration job 5종 contract test 모두 활성 강제. 6개 branch가 consume. |
|
||
|
||
**needs-confirmation closures (2건)**:
|
||
|
||
| 항목 | 결정 |
|
||
| --- | --- |
|
||
| PII/token/body log forbidden 구현 메커니즘 | structured field whitelist + Logback masking 이중 layer. (1) Logback `%mask` converter (regex `(?i)(token|password|authorization|cookie|secret|key)\s*[=:]\s*[^*\s]+` → `****`), (2) Jackson `@JsonSerialize(MaskingSerializer)` on PII DTO fields, (3) request body capture default `false` + allowlist required. JUnit + Logback ListAppender capture로 verify. owner = `feature-contract-verification-test-suite`. |
|
||
| scorecard real-domain dry-run checklist SSOT | SSOT = `feature-domain-feature-onboarding-contract`의 New Domain Module Slice + Read/Write Difference Table. scorecard는 consume only. |
|
||
|
||
#### Phase D2 closures (2026-05-22)
|
||
|
||
Release-blocking 5 category에 대한 runbook stub 5종 작성.
|
||
|
||
| 파일 | category | error_codes 적용 | severity |
|
||
| --- | --- | --- | --- |
|
||
| `ca-tmpl/docs/runbooks/auth-token-rotation-failure.md` | AUTH | AUTH_TOKEN_EXPIRED, AUTH_KID_UNKNOWN, AUTH_JWKS_UNAVAILABLE, AUTH_TOKEN_INVALID_SIGNATURE | P1 |
|
||
| `ca-tmpl/docs/runbooks/authz-cross-tenant-violation.md` | AUTHZ | AUTHZ_INSUFFICIENT_PERMISSION, AUTHZ_TENANT_MISMATCH | P2/P1 |
|
||
| `ca-tmpl/docs/runbooks/rate-limit-exceeded.md` | RATE_LIMIT | RATE_LIMIT_EXCEEDED, IDEMPOTENT_IN_FLIGHT | P3/P2 |
|
||
| `ca-tmpl/docs/runbooks/internal-error-spike.md` | INTERNAL | INTERNAL_ERROR, INTERNAL_AUTH_MISCONFIGURATION, JVM_OOM | P1 |
|
||
| `ca-tmpl/docs/runbooks/dependency-unavailable.md` | TRANSIENT_DEPENDENCY + PERMANENT_DEPENDENCY | DEPENDENCY_TIMEOUT/CONNECT_FAILED/DNS_FAILED/CIRCUIT_OPEN/5XX_SERVER, CACHE_UNAVAILABLE, DB_UNAVAILABLE | P1/P2 |
|
||
|
||
모든 runbook stub은 다음 7 section 표준 구조: Trigger / First Response (5분 이내) / Diagnosis / Mitigation / Escalation / Recovery·Verification / Related. frontmatter에 `status: stub` 명시 — 도메인 도입 시 실제 운영 사례·임계·dashboard URL로 보강 필요.
|
||
|
||
`error-codes.yaml`의 모든 release-blocking row의 `runbook_link` field가 위 5 파일 중 1개로 resolve됨을 verify (Phase D2 contract test). 미resolve 시 fail.
|
||
|
||
#### Pending (Phase D 이후)
|
||
|
||
| pending item | reason | owner |
|
||
| --- | --- | --- |
|
||
| canonical 승급 (`wiki/projects/` 본격 진입) | Phase D 완료 후 본 문서를 `wiki/projects/ca-skeleton-operational-contract.md`로 이동 + `status: verified`. registries/runbooks는 ca-tmpl repo로 이전됐으므로 wiki/projects/ca-tmpl/ subdirectory 불요, flat 위치로 승급. | Phase D 완료 시점 |
|
||
| ca-tmpl 실 코드 (Phase C2) | 별도 git repo. registry yaml을 consume하는 generated constants build task 포함 | external |
|
||
| 외부 근거 wiki/concepts/ 합성 (Phase E) | §29의 6개 topic을 각각 `wiki/concepts/{topic}.md` canonical 문서로 합성 (concept-template 형식, status `draft`→`reviewed`) | Phase E 별도 |
|
||
|
||
---
|
||
|
||
## 29. 외부 근거 / 대안 조사 인덱스 (2026-05-22)
|
||
|
||
본 contract의 6개 핵심 결정에 대해 외부 source(공식 문서·RFC·대기업 기술블로그·GitHub repo)를 조사하여 `raw/official-docs/`와 `raw/company-tech-blogs/`에 raw **54개 파일**로 저장. 각 raw 파일은 owning branch-note와 양방향 wikilink로 연결됨. 비교 분석은 추후 `wiki/concepts/` 합성 단계(Phase E)에서 6개 concept 문서로 정리.
|
||
|
||
### Topic 1 — Architecture Layout
|
||
|
||
- **ca-tmpl 결정**: Gradle multi-module Clean Architecture / Hexagonal boundary (`domain-core`, `application-core`, `adapter-*`, `shared-contract`, `app-bootstrap`, `sample-portfolio`)
|
||
- **대안 조사**: feature-first package / layer-first / hexagonal pure / Spring Modulith / onion
|
||
- **Owning branch-notes**:
|
||
- [[raw/branch-notes/feature-architecture-enforcement-rules]] — 5종 대안 비교 + 채택 근거
|
||
- [[raw/branch-notes/feature-skeleton-package-blueprint-contract]] — 패키지 청사진 관점
|
||
- [[raw/branch-notes/feature-domain-feature-onboarding-contract]] — onboarding 관점
|
||
- **raw 12개**: branch-note의 "외부 근거" 섹션에 full list
|
||
- **비교 핵심**: ca-tmpl Phase C2는 module boundary로 application/domain과 adapter를 물리 분리한다. buckpal은 feature/package 내부 port-adapter 책임 분리 참고로 유지하고, Spring Modulith는 기본값이 아니라 향후 module verification 보강 대안으로 둔다. layer-first는 초기 학습 비용 최저지만 도메인 증가 시 응집도 폭락.
|
||
|
||
### Topic 2 — Transaction Boundary
|
||
|
||
- **ca-tmpl 결정**: TransactionPort + TransactionalUseCaseRunner abstraction (`@Transactional` 직접 import forbidden)
|
||
- **대안 조사**: TransactionPort (baseline, ca-tmpl) / `@Transactional` direct / TransactionTemplate programmatic / Functional Resource monad / Custom TransactionInterceptor AOP
|
||
- **Owning branch-notes**:
|
||
- [[raw/branch-notes/feature-application-port-usecase-contract]] — TransactionPort SSOT
|
||
- [[raw/branch-notes/feature-transaction-concurrency-contract]] — isolation/propagation 관점
|
||
- **raw 8개**: branch-note 외부 근거 섹션 참조
|
||
- **비교 핵심**: ca-tmpl은 "Spring 의존 숨김" 진영(소수파). 다수파는 `@Transactional` 직접 부착(testability 낮지만 boilerplate 최저, Reflectoring 표준 baseline). Functional monad는 testability 최고지만 팀 학습 비용 큼. UNIL 팀이 2024-05에 ca-tmpl과 동일 진화 경로(`@Transactional` → output port + TransactionTemplate)를 거친 사례 존재.
|
||
|
||
### Topic 3 — Outbox Pattern
|
||
|
||
- **ca-tmpl 결정**: DB outbox table polling + `FOR UPDATE SKIP LOCKED` (PostgreSQL/MySQL 양쪽)
|
||
- **대안 조사**: SKIP LOCKED polling (baseline) / Debezium CDC / Kafka Connect outbox SMT / Dual-write (금지, negative reference) / Event sourcing / Spring `@TransactionalEventListener` (in-process only) / Netflix DBLog (극단 자체 CDC)
|
||
- **Owning branch-notes**:
|
||
- [[raw/branch-notes/feature-domain-event-outbox-contract]] — outbox publisher SSOT
|
||
- [[raw/branch-notes/feature-background-job-async-contract]] — retry/DLQ vocabulary SSOT
|
||
- **raw 10개**: branch-note 외부 근거 섹션 참조
|
||
- **비교 핵심**: polling lag vs CDC 인프라 비용이 결정 축. ca-tmpl 가정 = lag 수 초 허용 + Kafka Connect 운영 인력 부재 + DB가 SSOT. 가정 깨지면 Debezium migration (Wix 사례). event sourcing은 "대안"이라기보다 도메인 모델 자체 교체. dual-write는 negative reference (outbox 도입 근거).
|
||
|
||
### Topic 4 — API Error Envelope
|
||
|
||
- **ca-tmpl 결정**: custom envelope (`{success, data, error.{code, category, message, retryable, details}, meta}`), ProblemDetail(RFC 7807) 명시적 forbidden
|
||
- **대안 조사**: Custom envelope (Stripe/GitHub/Toss 진영) / RFC 7807 ProblemDetail / Google `rpc.Status` (gRPC-derived) / JSON:API errors / GraphQL errors array
|
||
- **Owning branch-notes**:
|
||
- [[raw/branch-notes/feature-operational-error-observability-foundation]] — envelope schema SSOT
|
||
- [[raw/branch-notes/feature-boundary-validation-mapping-contract]] — validation error mapping
|
||
- [[raw/branch-notes/feature-business-rule-validation-contract]] — business invariant → category mapping
|
||
- **raw 8개**: branch-note 외부 근거 섹션 참조
|
||
- **비교 핵심**: ca-tmpl의 `success` flag + `retryable` 1급은 어떤 표준에도 없음. Google `rpc.Status`만 retryable을 detail로 가짐. ProblemDetail은 실패 전용 평면이라 ca-tmpl의 success/error 대칭 요구와 구조적 충돌. → ca-tmpl이 ProblemDetail을 거부한 trade-off: 표준 lock-in 회피 + success/error 대칭 + 운영 메타 1급화.
|
||
|
||
### Topic 5 — Idempotency Key Design
|
||
|
||
- **ca-tmpl 결정**: triple scope `(authenticatedPrincipal, idempotencyKey, useCaseName)` + DB table + 24h TTL + 200ms in-flight wait → 409 `IDEMPOTENT_IN_FLIGHT` + fingerprint mismatch → 422 `IDEMPOTENT_REQUEST_MISMATCH`
|
||
- **대안 조사**: Stripe v1 pair `(account, key)` / Stripe v2 triple `(account, API, key)` / Square endpoint-scoped / PayPal `(req-id, API call type)` 45일 TTL / 토스 4-tuple `(account, key, URL, method)` 15일 TTL / AWS Powertools content-hash / GitHub no-API-level dedup / Brandur Postgres locked_at lock
|
||
- **Owning branch-notes**:
|
||
- [[raw/branch-notes/feature-rate-limit-idempotency-contract]] — key shape/TTL/저장소 SSOT
|
||
- [[raw/branch-notes/feature-api-contract-baseline]] — `Idempotency-Key` header 표준 (consume only)
|
||
- **raw 9개**: branch-note 외부 근거 섹션 참조
|
||
- **비교 핵심**: ca-tmpl triple은 Stripe v1보다 보수적, Stripe v2/Square/Toss와 동급. TTL 24h가 모든 reference 중 가장 짧음(스토리지 비용·키 추측 공격면 최소). 200ms wait는 in-flight retry 친화적(Brandur lock의 변형). fingerprint 422는 IETF draft-07 권고 정합. "Stripe pair보다 무조건 안전"이라는 단정은 금지 — v1 한정 비교일 뿐.
|
||
|
||
### Topic 6 — Multi-tenancy Isolation
|
||
|
||
- **ca-tmpl 결정**: opt-in (`APP_TENANT_ENABLED=true` 시만 활성) + shared DB + tenant_id column + ULID 형식 + JWT claim 우선 + `X-Tenant-Id` header admin only
|
||
- **대안 조사**: shared DB + tenant_id (baseline, AWS Pool model) / subdomain-based resolution / JWT claim only / schema-per-tenant (Hibernate SCHEMA strategy, Stripe Citus) / database-per-tenant (AWS Silo model) / Hybrid (Azure Deployment Stamps, tier-based)
|
||
- **Owning branch-notes**:
|
||
- [[raw/branch-notes/feature-tenant-context-policy]] — tenant resolution + isolation SSOT
|
||
- [[raw/branch-notes/feature-repository-access-permission-contract]] — `CROSS_TENANT_ADMIN` capability
|
||
- **raw 9개**: branch-note 외부 근거 섹션 참조
|
||
- **비교 핵심**: ca-tmpl의 opt-in + shared DB + tenant_id는 B2B 초기 단계 적합 (tenant 수 수십~수백). **migration trigger 3가지**: (a) 규제(금융/의료) isolation 강제 → schema-per-tenant, (b) tenant 수 수백~수천 + 단일 row 수 수억 → schema-per-tenant 또는 hybrid, (c) enterprise tier 등장 시 isolation 가격화 → db-per-tenant.
|
||
|
||
### Group G-A — 관측 (Observability) — 4 branches, 11 raw
|
||
|
||
- **Owning branch-notes**: [[raw/branch-notes/feature-log-management-contract]], [[raw/branch-notes/feature-metrics-alerting-contract]], [[raw/branch-notes/feature-distributed-tracing-contract]], [[raw/branch-notes/feature-operational-runbook-contract]]
|
||
- **대안 조사 (sub-topic별)**:
|
||
- **Log**: ca-tmpl(structured JSON + Logback masking + prod 10% sampling) vs ECS schema / OpenTelemetry log signal / Log4j2 / Loki·Datadog SaaS
|
||
- **Metric**: ca-tmpl(Micrometer dot.case + Prometheus + P1/P2/P3 + cardinality bounds) vs StatsD push / Datadog APM / OTel metrics / CloudWatch / SLO burn-rate
|
||
- **Tracing**: ca-tmpl(W3C traceparent + Micrometer Tracing + prod 1%) vs B3 Zipkin legacy / Datadog APM / AWS X-Ray / Tail-based sampling / Adaptive sampling
|
||
- **Runbook**: ca-tmpl(`runbook://` scheme + repo path + link-check smoke) vs Confluence runbook / PagerDuty Runbook Automation / Auto-remediation
|
||
- **비교 핵심**: 자체 JSON schema + Logback masking은 minimal core + JVM stdout 친화. OTel log signal은 trace correlation 강점이나 2024 ecosystem maturity 낮음. SLO burn-rate alert는 traffic 무관 일관 severity이지만 정식 SLO 수립 후 단계. W3C tracecontext + Micrometer Tracing은 vendor-neutral, B3은 64-bit non-호환으로 forbidden. `runbook://` git markdown은 drift 방지 + PR review로 SaaS runbook 대비 강점.
|
||
|
||
### Group G-B — 보안 baseline — 3 branches, 12 raw
|
||
|
||
- **Owning branch-notes**: [[raw/branch-notes/feature-security-operational-baseline]], [[raw/branch-notes/feature-management-actuator-security-contract]], [[raw/branch-notes/feature-secrets-config-source-contract]]
|
||
- **대안 조사**:
|
||
- **Security baseline**: ca-tmpl(JWT Resource Server + AuthN/AuthZ matrix 12행 + JWKS 10min + clock skew 60s) vs Session+cookie / OAuth2 Authorization Code+PKCE / mTLS / API key+HMAC (AWS SigV4) / OPA policy engine
|
||
- **Actuator**: ca-tmpl(management port 9001 + prod allowlist) vs Single port + path ACL / mTLS / Network ACL only / Service mesh (Istio)
|
||
- **Secrets**: ca-tmpl(prod=secret manager OR mounted env + restart-only rotation + HMAC salt 90d) vs AWS Secrets Manager auto-rotation / HashiCorp Vault dynamic secrets / K8s Secret + external-secrets-operator / Doppler·1Password SDK / Plain env (rejected)
|
||
- **비교 핵심**: JWT Resource Server는 stateless 확장성 우위 vs session, revocation은 JWKS rotation으로 일부 회수. mTLS는 sender-constrained라 강하지만 PKI 운영 비용 큼. OPA는 외부 policy engine으로 정책-코드 분리 강점이나 AUTHZ 2종에는 in-process 충분. Vault dynamic은 short lease 보안 우위지만 ca-tmpl `@RefreshScope` 금지와 정면 충돌. AWS Secrets Manager auto-rotation이 dual-bind 60s 패턴과 정합.
|
||
|
||
### Group G-C — Data layer — 3 branches, 11 raw
|
||
|
||
- **Owning branch-notes**: [[raw/branch-notes/feature-persistence-failure-baseline]], [[raw/branch-notes/feature-cache-consistency-contract]], [[raw/branch-notes/feature-outbound-http-client-baseline]]
|
||
- **대안 조사**:
|
||
- **Persistence**: ca-tmpl(SQLState 9-row matrix + OSIV off + Hikari alert + read replica lag threshold) vs Spring Data JPA default less-granular / R2DBC reactive / JOOQ SQL-first / 직접 JDBC + classifier / CockroachDB·Spanner·Aurora-specific
|
||
- **Cache**: ca-tmpl(cache-aside + Caffeine local + Redisson RLock distributed + after-commit invalidation + 5s window) vs Write-through / Write-behind / Read-through / Hazelcast vs Redis / Stale-while-revalidate
|
||
- **Outbound HTTP**: ca-tmpl(Spring RestClient + Resilience4j + timeout 2s/5s/10s + retry default disabled + CB) vs RestTemplate legacy / WebClient reactive / Feign·OpenFeign / OkHttp+Retrofit / Hystrix (deprecated)
|
||
- **비교 핵심**: SQLState matrix는 Spring DataAccessException hierarchy 위에 SQLState 입힌 형태로 임의 분류 아님. OSIV는 Hibernate 권위자(Vlad Mihalcea)도 anti-pattern 명시. cache-aside는 application owns invalidation으로 실패 가시성 강점. Resilience4j는 Spring 공식 maintenance 정책 정합(RestTemplate maintenance-only, Hystrix deprecated). WebClient는 다른 runtime model이라 MVC baseline에 강제 시 event-loop blocking risk. Stripe은 retry default-on이지만 idempotency-key 보장 전제.
|
||
|
||
### Group G-D — Runtime / Lifecycle — 3 branches, 12 raw
|
||
|
||
- **Owning branch-notes**: [[raw/branch-notes/feature-container-runtime-contract]], [[raw/branch-notes/feature-runtime-health-lifecycle-contract]], [[raw/branch-notes/feature-migration-startup-contract]]
|
||
- **대안 조사**:
|
||
- **Container**: ca-tmpl(Temurin JRE slim + MaxRAMPercentage=75 + UTC/UTF-8 + graceful shutdown 20s+5s+35s) vs Distroless (Google) / Alpine + GraalVM / GraalVM native-image / Spring Boot Native / Multi-stage debug variant
|
||
- **Runtime health**: ca-tmpl(liveness/readiness/startup 분리 + Required Optional Dependency Matrix + UTC + NTP drift >5s) vs Single /health legacy / Custom HealthIndicator / Spring Actuator Groups / Service mesh health (Istio·Consul)
|
||
- **Migration**: ca-tmpl(Flyway + readiness gated + exit codes 78/70/71/72 + prod repair forbidden) vs Liquibase XML/YAML / Hibernate hbm2ddl (anti-pattern) / Init container in K8s / Separate migration job / Atlas·Tern (schema-as-code)
|
||
- **비교 핵심**: Temurin JRE slim은 운영 친숙도/디버깅 우선. Distroless는 보안 surface 축소하지만 in-container 디버깅 손실. GraalVM native-image는 cold start/메모리 우위지만 reflection 비용 + peak throughput 손실 (우아한형제들도 hybrid 채택). K8s 공식 + Spring Actuator Groups가 ca-tmpl 3-endpoint 분리와 정합. Flyway 공식이 prod repair/baseline_on_migrate/out_of_order 위험성을 명시 → ca-tmpl forbidden의 직접 근거. multi-instance에서는 K8s Job 또는 migration lock이 init container보다 race 회피에 우월.
|
||
|
||
### Group G-E — DevOps / CI — 3 branches, 9 raw
|
||
|
||
- **Owning branch-notes**: [[raw/branch-notes/feature-ci-quality-gates-contract]], [[raw/branch-notes/feature-build-release-supply-chain-contract]], [[raw/branch-notes/feature-developer-experience-contract]]
|
||
- **대안 조사**:
|
||
- **CI**: ca-tmpl(Gate ownership matrix 20 rows + flaky quarantine 14d + OpenAPI snapshot diff + Trivy) vs Jenkins / GitLab CI vs GitHub Actions / CircleCI·Buildkite / Drone CI / Tekton (k8s-native)
|
||
- **Supply chain**: ca-tmpl(Cosign keyless + SLSA + Gradle dependency-locking + SemVer+sha + reproducibility) vs GPG signing legacy / Notary v1 / in-toto attestations / JFrog Artifactory provenance / Sigstore for non-container
|
||
- **DX**: ca-tmpl(`./gradlew bootstrap` + Temurin 21 LTS + Testcontainers integration + markdown-link-check) vs `make bootstrap` / `docker compose up` only / devcontainer (VSCode·Codespaces) / Nix flake / mise·asdf
|
||
- **비교 핵심**: GitHub Actions `needs:` + `if: success()`가 ca-tmpl contract gate 모델과 정확히 맞물림. Tekton/Jenkins는 k8s 인프라/plugin 의존도로 skeleton 단계에 과함. Cosign keyless signature 누락만 차단으로는 부족 — identity 매칭 정책(`--certificate-identity`)이 추가 필요(branch note 보강 후보). Flaky quarantine은 Spotify/Google/MS 인정 vs Fowler 반대 — ca-tmpl 14d sunset이 절충안. mise/asdf는 `.tool-versions` 표준, SDKMAN은 `.sdkmanrc` — branch note "또는" 표현은 drift 위험 내포.
|
||
|
||
### Group G-F — API evolution & schema — 2 branches, 8 raw
|
||
|
||
- **Owning branch-notes**: [[raw/branch-notes/feature-api-compatibility-deprecation-contract]], [[raw/branch-notes/feature-schema-serialization-contract]]
|
||
- **대안 조사**:
|
||
- **Compatibility**: ca-tmpl(90d public + 30d internal migration window + breaking change catalog 7행 + Sunset header) vs Stripe date-based versioning (no removal, freeze) / Twitter Tier-based (legacy/current/beta) / Microsoft REST API versioning policy / GitHub preview API headers / Spring HATEOAS (links over versions)
|
||
- **Schema**: ca-tmpl(ISO-8601 offset UTC + BigDecimal scale 2 HALF_UP + unknown field strict inbound·tolerant outbound + null/empty/missing 분리) vs Jackson default lenient / Avro·Protobuf strict typing / JSON Schema validation / Smithy (AWS API modeling) / OpenAPI 3.1 spec
|
||
- **비교 핵심**: Stripe(freeze forever) vs ca-tmpl(90d/30d window) vs GitHub(24mo EOL + 410 Gone): 외부 컨슈머 규모와 운영 비용 trade-off. ca-tmpl internal-first면 90d 합리, EOL 응답 코드(410 Gone)가 catalog에 누락. Google AIP-180은 enum value 제거도 금지 → ca-tmpl `narrow enum = breaking, new version` 결정과 부분 정합. Sunset(RFC 8594) + Deprecation 헤더는 **함께** 보내야 정합. Protobuf `reserved`(field number/name 재사용 차단)가 JSON 환경에서 ca-tmpl이 가장 크게 보강할 부분. Avro full-compatibility는 schema registry 자동 검사 강력하지만 outbox/event 한정 도입 권장.
|
||
|
||
### Group G-G — Skeleton governance — 4 branches, 11 raw
|
||
|
||
- **Owning branch-notes**: [[raw/branch-notes/feature-contract-registry-governance]], [[raw/branch-notes/feature-contract-verification-test-suite]], [[raw/branch-notes/feature-test-taxonomy-fixture-contract]], [[raw/branch-notes/feature-implementation-readiness-scorecard]]
|
||
- **대안 조사**:
|
||
- **Registry governance**: ca-tmpl(markdown SSOT + YAML/generated constants + 7-column schema) vs Code-only enums / Protobuf·Smithy as registry / ArchUnit annotations as registry / Database-stored registry / `@ConfigurationProperties` as registry
|
||
- **Verification**: ca-tmpl(11 release-blocking gates + JSON snapshot + Pact CDC out-of-scope) vs Pact CDC / Spring REST Docs / Spring Cloud Contract / Hoverfly·WireMock service virtualization / PostgreSQL diff
|
||
- **Test taxonomy**: ca-tmpl(6 levels + Testcontainers from integration + src/testFixtures + 5min budget) vs Classic test pyramid / Test trophy (Kent Dodds) / Honeycomb (Spotify) / Fitness functions
|
||
- **Scorecard**: ca-tmpl(binary pass/fail + 15 area + 1:1 branch evidence) vs OpenTelemetry Maturity Model / AWS Well-Architected Framework / CIS Benchmark scoring / SLSA build level scoring / CMMI maturity
|
||
- **비교 핵심**: ca-tmpl branch note 결정 라인이 사실상 mini-ADR로 동작 (Status=`status_label`, Context=목표/WHY, Decision=결정 사항, Consequences=테스트 계약) — 별도 ADR 파일 도입 불요. Pact 공식이 직접 "consumer-known subset만 검증"이라 명시 → ca-tmpl single-team 환경에서 snapshot 우위. Testcontainers 공식이 "real services, no H2" 입장 — ca-tmpl integration부터 강제 정합. binary pass/fail은 adoption gate에 적합, WAR/CIS 점진적 점수는 운영 중 지속 개선에 적합.
|
||
|
||
### Group G-H — Sample / adoption — 2 branches, 8 raw
|
||
|
||
- **Owning branch-notes**: [[raw/branch-notes/feature-sample-domain-contract-fixture]], [[raw/branch-notes/feature-sample-removal-adoption-contract]]
|
||
- **대안 조사**:
|
||
- **Sample fixture**: ca-tmpl(sample-portfolio 12 scenario matrix + 6-field minimum model + state machine + optimistic lock + idempotency key) vs Spring Petclinic / RealWorld (gothinkster) / Microservices sample (Spring guides) / Shopping cart (Stripe testmode) / No fixture
|
||
- **Removal/adoption**: ca-tmpl(2-step removal + dual-mode CI matrix + 7-step adoption checklist) vs Yeoman·archetype auto-remove / Cookiecutter / degit (Svelte) / Spring Initializr / GitHub Template Repository / Manual fork
|
||
- **비교 핵심**: Petclinic은 "demo지 best-practice 아님" 본인 선언, RealWorld는 spec 풍부하지만 minimum 아니고 contract scenario 부재. ca-tmpl 결정이 skeleton contract 검증 도구라는 목적에 가장 적합. Initializr/Cookiecutter는 generator 시점 sample-off라 ca-tmpl dual-mode CI matrix와 충돌. **GitHub Template Repository**가 CI/Actions까지 함께 복제되어 friction 최저 — reference 1순위. Backstage는 조직 규모 임계점 이후 IDP 후보.
|
||
|
||
### Group G-I — Config / adapter — 2 branches, 7 raw
|
||
|
||
- **Owning branch-notes**: [[raw/branch-notes/feature-env-driven-runtime-configuration]], [[raw/branch-notes/feature-integration-adapter-templates]]
|
||
- **대안 조사**:
|
||
- **Env config**: ca-tmpl(APP_ prefix + Duration `30s` 1택 + boolean true/false + no-runtime-reload + .env.example drift verify + APP_MULTI_INSTANCE_ENABLED claim parsing) vs Spring Cloud Config Server / k8s ConfigMap + Spring Cloud Kubernetes auto-reload / HashiCorp Consul KV / AWS Parameter Store·AppConfig / LaunchDarkly·Unleash
|
||
- **Adapter templates**: ca-tmpl(optional module + `@ConditionalOnProperty` + ArchUnit 3-layer detection + `AdapterDisabledException`) vs Spring Boot AutoConfiguration without ConditionalOnProperty / Plugin architecture (OSGi) / Spring `@Profile` based / SPI ServiceLoader / Feature flag library (FF4J·Togglz)
|
||
- **비교 핵심**: 12-factor §III. Config가 ca-tmpl `APP_` env-only + no-reload 결정의 이론 출처. Spring Cloud Config Server는 인프라 SPOF + bootstrap 의존, k8s reload는 partial-state 디버깅 어려움. LaunchDarkly/Unleash는 product-grade A/B/canary 요구 발생 시 진입점. ca-tmpl `@ConditionalOnProperty`는 Layer 1만 Spring 공식 cover, Layer 2(ArchUnit)/Layer 3(`AdapterDisabledException`)는 branch 자체 contract — ArchUnit source 별도 필요한 미흡 영역. SPI는 on/off 표현 불가 + DI 미통합 + default constructor 강제. Togglz/FF4J는 runtime branching 도구라 시맨틱 다름.
|
||
|
||
### Group G-J — Privacy / file / domain modeling — 3 branches, 10 raw
|
||
|
||
- **Owning branch-notes**: [[raw/branch-notes/feature-data-retention-privacy-contract]], [[raw/branch-notes/feature-file-resource-handling-contract]], [[raw/branch-notes/feature-domain-modeling-guardrails]]
|
||
- **대안 조사**:
|
||
- **Privacy**: ca-tmpl(30/180/365d retention + HMAC-SHA-256 salt rotation 90d + DSR SLA 30d/14d + is_sample column) vs GDPR-compliant privacy-by-design libraries / AWS Macie PII detection / OneTrust·TrustArc SaaS / Cryptographic erasure (delete key vs delete data) / Tokenization vs pseudonymization
|
||
- **File**: ca-tmpl(10MB/12MB/20MB 3-layer + content-type allowlist 6종 + temp orphan 1h cleanup + antivirus gateway default) vs Direct S3 presigned URL / tus protocol (resumable) / multipart/form-data only / ClamAV in-app vs gateway / AWS GuardDuty Malware·GCP SCC
|
||
- **Domain modeling**: ca-tmpl(VO private constructor + aggregate root mutator protection + domain logger ban + safe reason enum + invariant in constructor + ORM 외부 매핑) vs Functional domain (Scala·F#) / Anemic vs Rich model / Pure DDD aggregates / Event sourcing / CQRS
|
||
- **비교 핵심**: GDPR Art.25 (Privacy by design) + NIST SP 800-88 (Cryptographic Erase)가 ca-tmpl retention/backup 결정의 표준 근거. HMAC + 90d salt rotation은 ENISA가 인정하나 brute-force 가능 input space(예: 한국 휴대폰 11자리)에서는 tokenization 우위. backup의 GDPR Art.17 erasure는 cryptographic erase가 NIST 정식 인정 → per-principal envelope key 구조 필요(ca-tmpl 미결정). ICAP/RFC 3507이 antivirus gateway 표준이지만 HTTPS E2E TLS 환경에서 적용 어려움. tus 채택 시 ca-tmpl "1h orphan cleanup"이 session 잘못 삭제 가능. Vaughn Vernon "Effective Aggregate Design" + Fowler "Anemic Domain Model"이 ca-tmpl 결정의 reference standard. ca-tmpl의 "ORM 외부 매핑"은 Vernon Option A, 우아한형제들 초기 글은 Option B(JPA direct annotation + protected ctor)지만 ca-tmpl forbidden import 규칙 위배라 거부. Greg Young 글에서 ca-tmpl은 CQRS read 분리/event sourcing 모두 미채택, 단순 "domain event = transport-free fact" 정의만 차용.
|
||
|
||
---
|
||
|
||
### 다음 단계 (Phase E)
|
||
|
||
**모든 43 branch의 외부 근거 조사 완료** (총 16 topic, 153 raw 파일). 다음은 wiki/concepts/ 합성 단계:
|
||
|
||
위 16개 topic을 각각 `wiki/concepts/{topic}.md` canonical 문서로 합성 예정:
|
||
- (T1-T6 기존 6개) `clean-architecture-package-layout` / `transaction-boundary-abstraction` / `transactional-outbox-pattern` / `api-error-envelope-design` / `idempotency-key-design` / `multi-tenancy-isolation-patterns`
|
||
- (G-A) `observability-log-metric-trace-runbook`
|
||
- (G-B) `security-baseline-jwt-actuator-secrets`
|
||
- (G-C) `data-layer-persistence-cache-outbound`
|
||
- (G-D) `runtime-container-health-migration`
|
||
- (G-E) `devops-ci-supply-chain-dx`
|
||
- (G-F) `api-evolution-and-schema`
|
||
- (G-G) `skeleton-governance-registry-verification-test-scorecard`
|
||
- (G-H) `sample-fixture-and-adoption`
|
||
- (G-I) `config-and-adapter-templates`
|
||
- (G-J) `privacy-file-domain-modeling`
|
||
|
||
각 concept 문서는 `templates/concept-template.md` 형식 (Summary / Standard / 한계 / Project Application / Interview Questions / Do Not Overclaim / Sources). raw 153개를 Sources로 인용. status `draft`로 시작.
|
||
|
||
### 검증 권장 (needs-confirmation)
|
||
|
||
각 topic 에이전트가 부분 추출만 가능했던 source — 후속 보강 필요:
|
||
- `layer-first-baeldung-clean-architecture-spring-boot.md` (본문 직접 인용 미완)
|
||
- `hexagonal-cockburn-wikipedia-summary.md` (원문 SSL 만료, Wikipedia 대체)
|
||
- `outbox-woowahan-techblog-pattern.md` (인용 wording 보강)
|
||
- `outbox-netflix-domain-events-cdc.md` (DBLog 정확한 인용)
|
||
- `multitenancy-stripe-citus-schema-per-tenant.md` (Citus 한계치 수치)
|
||
|
||
### 후속 보강 결과 (2026-05-22 처리 완료)
|
||
|
||
8건의 후속 보강 후보 모두 처리 완료. 외부 source 추가 + branch-note 결정사항 추가 + concept/project 보강. 신규 raw 8 파일은 status `needs-confirmation` 또는 `raw`(high confidence)로 분류.
|
||
|
||
| 항목 | 처리 결과 | 신규 raw 파일 |
|
||
|------|----------|--------------|
|
||
| **G-E** Cosign identity 매칭 정책 | **결정 추가**: `cosign verify --certificate-identity=<expected> --certificate-oidc-issuer=<expected>` 필수. signature 존재만 검증하면 fail. (status: high) | [[raw/official-docs/cosign-keyless-identity-verification-policy]] |
|
||
| **G-E** SLSA v1.0 spec 필드명 | **결정 추가**: provenance 생성 시 SLSA 공식 필드명(`buildDefinition.{buildType, externalParameters, internalParameters, resolvedDependencies}` + `runDetails.{builder.id, metadata.invocationId, ...}`) 사용. 약식 명명 forbidden. (status: high) | [[raw/official-docs/slsa-v1-provenance-schema]] |
|
||
| **G-F** Sunset+Deprecation paired | **결정 추가**: API deprecation 응답은 `Sunset` + `Deprecation` 헤더 **함께** 전송. 단독 Sunset 금지. `Link: <url>; rel="sunset"` 권장. (status: high) | [[raw/official-docs/sunset-deprecation-headers-paired-usage]] |
|
||
| **G-F** Protobuf `reserved` JSON 흉내 | **결정 보류**: OpenAPI `x-removed-fields` extension OR markdown 자체 catalog. 코드 단계 도구 결정. (status: needs-confirmation) | [[raw/official-docs/protobuf-reserved-vs-json-openapi-extension]] |
|
||
| **G-G** ArchUnit annotation-as-registry | **결정 유지**: markdown SSOT 유지, ArchUnit annotation은 verifier 한정 (registry 아님). 근거: framework-neutral, git diff review, 외부 도구 호환. (status: needs-confirmation, 공식 권고 부재) | [[raw/official-docs/archunit-annotation-as-registry-evaluation]] |
|
||
| **G-I** ArchUnit Layer 2 정적 검사 범위 | **결정 명확화**: Layer 2는 "annotation 존재 + naming pattern" fitness function까지만 정적 보장. runtime active 검사는 Layer 3 (`AdapterDisabledException`)에 위임. (status: needs-confirmation) | [[raw/official-docs/archunit-conditional-on-property-3-layer-pattern]] |
|
||
| **G-J** per-principal envelope key | **결정 추가**: backup PII 포함 시 per-principal envelope key (또는 tenant-level CMK) 구조 적용. HMAC + salt rotation은 forward security only 명시. 구체 패턴은 Phase C2 보류. (status: needs-confirmation) | [[raw/official-docs/gdpr-cryptographic-erasure-envelope-key-pattern]] |
|
||
| **G-B** 한국 보안 기술블로그 | **부분 완료**: Actuator 영역 2건 (우아한형제들 + 토스페이먼츠) 확보. JWT/secret 직접 사례는 fetch 가능 source 부재 → follow-up 후보로 유지. (status: raw) | [[raw/company-tech-blogs/security-woowahan-actuator-safe-usage]], [[raw/company-tech-blogs/security-toss-actuator-healthcheck]] |
|
||
|
||
총 신규 raw 파일: 9개 (G-B만 2개). 누적 외부 근거 raw: 162개 (Topic 1-6: 54 + G-A~J: 99 + 후속 보강: 9).
|
||
|
||
### 잔여 follow-up
|
||
|
||
- **G-B**: 한국 기업 JWT/secret 직접 사례 (토스/카카오/네이버 등) — 검색 가능한 글 등장 시 추가.
|
||
- **G-F**: Protobuf `reserved` 흉내 도구 선택 (`x-removed-fields` extension vs markdown catalog) — Phase C2 코드 단계 결정.
|
||
- **G-I**: ArchUnit Layer 2 fitness function 도입 여부 — Phase C2 코드 단계 결정.
|
||
- **G-J**: envelope key 구체 패턴 (per-principal CMK / per-principal DEK+master CMK / tenant-level CMK) — Phase C2 KMS 선택 단계 결정.
|
||
|
||
---
|
||
|
||
<!-- section-id: architecture-components -->
|
||
## 30. 시스템 아키텍처
|
||
|
||
> 본 절은 `templates/project-template.md` §3 표준에 맞춰 작성. ca-skeleton 은 **운영 계약 문서** 가 본체이며 아키텍처는 모듈 의존성 + 외부 의존성 2관점으로 표현.
|
||
>
|
||
> 작성 도구: **draw.io** (`templates/diagram-standards.md` v2 minimalist 표준). Mermaid 는 시퀀스용 (§30.1~§30.3).
|
||
|
||
### 30-1. 모듈 의존성 (Gradle 멀티모듈 + Clean Architecture)
|
||
|
||
![[raw/diagrams/ca-skeleton/architecture-modules-2026-05-26.drawio]]
|
||
|
||
**다이어그램이 답하는 질문**: 5개 Gradle 모듈은 어느 방향으로만 서로 의존할 수 있고, 그 중심은 무엇인가?
|
||
|
||
**핵심 메시지**: `domain` (파란 박스) 이 CA 의 심장이며, 모든 의존 화살표가 결국 domain 으로 수렴한다. cmd 는 composition root 로서 모든 모듈을 조립하지만, 자기 자신은 어디에도 의존받지 않는다.
|
||
|
||
**허용 방향** (다이어그램 화살표 8개):
|
||
|
||
- `cmd → presentation / service / infra / domain` — composition root
|
||
- `presentation → service` (UseCase 호출) + `presentation → domain` (도메인 모델/예외 직접 사용)
|
||
- `service → domain` (UseCase 가 도메인 모델 조작)
|
||
- `infra → domain` (Repository Port 구현, 도메인 모델 매핑)
|
||
|
||
**HARD-STOP 금지 사항** (callout 참조):
|
||
- `domain` → 어떤 다른 모듈 또는 Spring/JPA/HTTP/cloud SDK (순수 Java 만)
|
||
- `service` → `infra` 또는 `presentation` (포트로만 통신)
|
||
- `presentation` → `infra` (Repository / JPA Entity 직접 사용 금지)
|
||
- `infra` → `presentation` 또는 controller DTO (요청 객체 누출 금지)
|
||
|
||
**검증 수단**:
|
||
- `./gradlew verifyCleanArchitectureDependencies` — Gradle project-dependency check
|
||
- `./gradlew :cmd:test` — ArchUnit `CleanArchitectureTest` 실행
|
||
|
||
### 30-2. 외부 의존성 & 신뢰 경계 (런타임 토폴로지)
|
||
|
||
![[raw/diagrams/ca-skeleton/architecture-runtime-topology-2026-05-26.drawio]]
|
||
|
||
**다이어그램이 답하는 질문**: 앱이 기동하기 위해 반드시 있어야 하는 것은 무엇이고, `APP_ADAPTER_*_ENABLED=false` 로 끌 수 있는 것은 무엇인가?
|
||
|
||
**핵심 메시지**: Application 은 **단 하나의 mandatory 외부 의존성 = PostgreSQL** 만 가진다. Redis / Kafka / Email / Slack / Google 은 모두 optional — adapter 를 끄거나 외부 장애 시에도 앱 자체는 살아 있어야 한다.
|
||
|
||
**의존성 분류** (다이어그램 색·선 ↔ 정책):
|
||
|
||
| 종류 | 시각화 | 예시 | 정책 |
|
||
|---|---|---|---|
|
||
| **Mandatory** | 파란 굵은 실선 | Client→app(HTTP), app→PostgreSQL(JDBC) | 없으면 기동 실패. `cmd` health check 에서 fail-fast |
|
||
| **Optional internal** | 주황 점선 | Redis cache, Kafka outbox publisher | `APP_ADAPTER_REDIS_ENABLED=false` 로 끌 수 있음. 끌 경우 fallback path 활성 |
|
||
| **External Internet** | 회색 점선 | Email API, Slack API, Google OIDC | 외부 장애에도 앱 자체는 살아 있어야 함 (degrade 또는 retry-able) |
|
||
|
||
**운영 정책 (§11 Adapter Failure Contract)**:
|
||
|
||
- Mandatory adapter (PostgreSQL) 장애 → app 자체가 `/readyz` 실패, traffic 차단
|
||
- Optional internal adapter (Redis/Kafka) 장애 → 해당 기능만 degrade, app 자체는 healthy
|
||
- External (Email/Slack/Google) 장애 → 호출 단위로 retry / circuit-breaker, app 자체는 healthy
|
||
|
||
**금지**: optional adapter 가 mandatory 처럼 동작하도록 hard-coded (e.g., service 가 `RedisCachePort` 를 null 검사 없이 의존) → §11 위반.
|
||
|
||
<!-- section-id: sequence -->
|
||
### 30.1 핵심 시퀀스 (Mermaid)
|
||
|
||
> §3 ~ §7 (응답 envelope, validation, exception, error category) 의 데이터 흐름을 시퀀스로 표현. happy path + error path.
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
autonumber
|
||
actor Client
|
||
participant FE as Presentation (Controller)
|
||
participant App as Application (UseCase)
|
||
participant Dom as Domain
|
||
participant Infra as Infrastructure (Adapter)
|
||
participant DB as DB
|
||
|
||
Client->>FE: HTTP request
|
||
FE->>FE: Request DTO validation (§4 syntax layer)
|
||
FE->>App: command/query (record)
|
||
App->>Dom: domain invariant check (§4 invariant layer)
|
||
App->>Infra: outbound port call (via TransactionPort)
|
||
Infra->>DB: persistence
|
||
alt success
|
||
DB-->>Infra: result
|
||
Infra-->>App: domain object
|
||
App-->>FE: response value
|
||
FE-->>Client: 200 OK {success: true, data: ..., meta: {request_id, trace_id}}
|
||
else domain invariant 위반
|
||
Dom-->>App: DomainInvariantException
|
||
App-->>FE: bubble up
|
||
FE-->>Client: 422 Unprocessable Entity {success: false, error: {category: VALIDATION, code: ...}}
|
||
else infra/DB 장애
|
||
Infra-->>App: PersistenceException (translated by §6 mapper)
|
||
App-->>FE: bubble up
|
||
FE-->>Client: 503 Service Unavailable {success: false, error: {category: TRANSIENT_DEPENDENCY, code: ...}}
|
||
end
|
||
```
|
||
|
||
### 30.2 Transactional Outbox publish (§domain-event-outbox-contract)
|
||
|
||
> SKIP LOCKED polling 패턴. DB 트랜잭션 + outbox 적재 + 비동기 broker 발행이 분리되어 원자성 확보.
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
autonumber
|
||
actor Client
|
||
participant App as service (UseCase)
|
||
participant Infra as infra (Adapter)
|
||
participant DB as PostgreSQL
|
||
participant Poller as OutboxPoller<br/>(scheduled, multi-instance)
|
||
participant Kafka as Kafka broker
|
||
|
||
Client->>App: business command
|
||
App->>Infra: save Aggregate + Outbox event<br/>(single TX)
|
||
Infra->>DB: BEGIN; INSERT aggregate; INSERT outbox; COMMIT
|
||
DB-->>Infra: OK
|
||
Infra-->>App: success
|
||
App-->>Client: 200 OK
|
||
|
||
Note over Poller: 1초 주기 + SKIP LOCKED
|
||
Poller->>DB: SELECT FROM outbox WHERE status='PENDING'<br/>FOR UPDATE SKIP LOCKED
|
||
DB-->>Poller: events to publish
|
||
loop 각 event
|
||
Poller->>Kafka: publish(event)
|
||
alt 성공
|
||
Kafka-->>Poller: ack
|
||
Poller->>DB: UPDATE outbox SET status='SENT'
|
||
else 실패
|
||
Kafka-->>Poller: error
|
||
Poller->>DB: UPDATE outbox SET attempt_count+=1
|
||
Note over Poller,DB: attempt_count >= max → status='DEAD'
|
||
end
|
||
end
|
||
```
|
||
|
||
### 30.3 Tenant Context Propagation (§tenant-context-policy)
|
||
|
||
> 멀티 테넌트 opt-in. JWT claim → ThreadLocal → 비동기 전파 → finally clear.
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
autonumber
|
||
actor Client
|
||
participant Filter as TenantContextFilter<br/>(presentation)
|
||
participant TL as ThreadLocal<br/>(TenantContext)
|
||
participant App as service (UseCase)
|
||
participant TD as TaskDecorator
|
||
participant Async as Async Executor<br/>(ThreadPoolTaskExecutor)
|
||
participant DB as DB Repo
|
||
|
||
Client->>Filter: HTTP request<br/>+ Authorization: Bearer JWT
|
||
Filter->>Filter: JWT validate + extract tenant_id claim
|
||
alt JWT 유효 + tenant_id 존재
|
||
Filter->>TL: set(tenant_id)
|
||
Filter->>App: forward
|
||
App->>DB: query with WHERE tenant_id=current()
|
||
DB-->>App: tenant-scoped data
|
||
App-->>Filter: result
|
||
|
||
Note over App,Async: 비동기 작업 시
|
||
App->>TD: submit Runnable
|
||
TD->>TD: capture caller tenant_id
|
||
TD->>Async: wrap Runnable with try-finally
|
||
Async->>TL: set(tenant_id) on worker thread
|
||
Async->>App: business work
|
||
Async->>TL: clear() ← MANDATORY (finally)
|
||
Async-->>App: done
|
||
|
||
Filter->>TL: clear() ← finally (worker thread reuse 보호)
|
||
else JWT 무효
|
||
Filter-->>Client: 401 Unauthorized
|
||
else multi-tenant disabled + X-Tenant-Id header 유입
|
||
Filter-->>Client: 400 TENANT_NOT_SUPPORTED
|
||
end
|
||
```
|
||
|
||
**핵심 함정** (§tenant-context-policy 의 결정 사항):
|
||
- 비동기 작업 후 `ThreadLocal.clear()` 누락 시 스레드 풀 재사용으로 인한 **테넌트 정보 누수 (Tenant Leakage)** — finally 강제
|
||
|
||
(이 외 패턴 — JWKS refresh, idempotency replay, graceful shutdown — 은 각 feature-* sub-branch 의 시퀀스에서.)
|
||
|
||
## 31. 묶음
|
||
|
||
<!-- GENERATED: sources:start -->
|
||
- [[raw/company-tech-blogs/adapter-togglz-ff4j-feature-toggle-library]]
|
||
- [[raw/company-tech-blogs/api-versioning-github-rest-date-header]]
|
||
- [[raw/company-tech-blogs/api-versioning-stripe-date-based]]
|
||
- [[raw/company-tech-blogs/arhohuttunen-hexagonal-architecture-spring-boot]]
|
||
- [[raw/company-tech-blogs/aws-iam-arn-format]]
|
||
- [[raw/company-tech-blogs/axonframework-transactionmanager-spring-adapter]]
|
||
- [[raw/company-tech-blogs/brandur-stripe-idempotency-keys]]
|
||
- [[raw/company-tech-blogs/buckpal-archunit-lombok-allowlist-direct-transactional]]
|
||
- [[raw/company-tech-blogs/cache-woowahan-after-commit-invalidation]]
|
||
- [[raw/company-tech-blogs/ci-flaky-test-quarantine-spotify-google]]
|
||
- [[raw/company-tech-blogs/config-launchdarkly-feature-flag-best-practice]]
|
||
- [[raw/company-tech-blogs/container-woowahan-spring-native-tradeoffs]]
|
||
- [[raw/company-tech-blogs/cqrs-lite-clean-architecture-read-path-bypass-wakita]]
|
||
- [[raw/company-tech-blogs/curity-oauth2-scope-vs-permission-naming]]
|
||
- [[raw/company-tech-blogs/custom-transaction-interceptor-catnipcoder]]
|
||
- [[raw/company-tech-blogs/domain-event-sourcing-vs-cqrs-greg-young]]
|
||
- [[raw/company-tech-blogs/domain-woowahan-ddd-aggregate-techblog]]
|
||
- [[raw/company-tech-blogs/explicit-architecture-ddd-hexagonal-cqrs-hgraca]]
|
||
- [[raw/company-tech-blogs/feature-first-sahibinden-package-by-layer-vs-feature]]
|
||
- [[raw/company-tech-blogs/file-clamav-icap-gateway-scan]]
|
||
- [[raw/company-tech-blogs/github-api-error-format]]
|
||
- [[raw/company-tech-blogs/github-graphql-global-node-id]]
|
||
- [[raw/company-tech-blogs/hexagonal-reflectoring-transactional-placement]]
|
||
- [[raw/company-tech-blogs/hexagonal-woowahan-techblog-2023]]
|
||
- [[raw/company-tech-blogs/idempotency-brandur-stripe-postgres]]
|
||
- [[raw/company-tech-blogs/idempotency-redis-vs-db-storage]]
|
||
- [[raw/company-tech-blogs/idempotency-toss-payments-techblog]]
|
||
- [[raw/company-tech-blogs/jwks-workos-unknown-kid-refresh-rate-limit-pattern]]
|
||
- [[raw/company-tech-blogs/layer-first-kamilmazurek-github-template]]
|
||
- [[raw/company-tech-blogs/lock-subskribe-advisory-lock-distributed-consensus]]
|
||
- [[raw/company-tech-blogs/metric-toss-payments-alert-severity-techblog]]
|
||
- [[raw/company-tech-blogs/micrometer-context-propagation-line-be-hase]]
|
||
- [[raw/company-tech-blogs/modulith-arawn-github-modular-monoliths-spring]]
|
||
- [[raw/company-tech-blogs/modulith-kakaobank-techblog-2025]]
|
||
- [[raw/company-tech-blogs/multitenancy-atlassian-tenant-context]]
|
||
- [[raw/company-tech-blogs/multitenancy-auth0-tenant-resolution]]
|
||
- [[raw/company-tech-blogs/multitenancy-hybrid-pooled-siloed-mix]]
|
||
- [[raw/company-tech-blogs/multitenancy-stripe-citus-schema-per-tenant]]
|
||
- [[raw/company-tech-blogs/multitenancy-subdomain-resolution-patterns]]
|
||
- [[raw/company-tech-blogs/netflix-tudum-cqrs-separate-read-store-evolution]]
|
||
- [[raw/company-tech-blogs/onion-allegro-tech-blog-2023]]
|
||
- [[raw/company-tech-blogs/outbound-stripe-rate-limit-retry-engineering]]
|
||
- [[raw/company-tech-blogs/outbox-confluent-kafka-connect-smt]]
|
||
- [[raw/company-tech-blogs/outbox-netflix-domain-events-cdc]]
|
||
- [[raw/company-tech-blogs/outbox-wix-engineering-debezium]]
|
||
- [[raw/company-tech-blogs/outbox-woowahan-techblog-pattern]]
|
||
- [[raw/company-tech-blogs/percona-uuid-storage-mysql]]
|
||
- [[raw/company-tech-blogs/planetscale-nanoid-api]]
|
||
- [[raw/company-tech-blogs/privacy-pseudonymization-hmac-vs-tokenization-iapp]]
|
||
- [[raw/company-tech-blogs/read-only-tx-hibernate-optimization-vladmihalcea]]
|
||
- [[raw/company-tech-blogs/realtime-service-experience-woowahan-websocket]]
|
||
- [[raw/company-tech-blogs/retry-aws-exponential-backoff-and-jitter]]
|
||
- [[raw/company-tech-blogs/runbook-atlassian-gitops-runbook-as-code]]
|
||
- [[raw/company-tech-blogs/runbook-woowahan-incident-techblog]]
|
||
- [[raw/company-tech-blogs/runtime-health-datadog-engineering-graceful-shutdown]]
|
||
- [[raw/company-tech-blogs/scaffolding-backstage-golden-path-spotify]]
|
||
- [[raw/company-tech-blogs/scoped-value-structured-concurrency-softwaremill]]
|
||
- [[raw/company-tech-blogs/secrets-1password-developer-secret-references]]
|
||
- [[raw/company-tech-blogs/security-toss-actuator-healthcheck]]
|
||
- [[raw/company-tech-blogs/security-woowahan-actuator-safe-usage]]
|
||
- [[raw/company-tech-blogs/segment-ksuid]]
|
||
- [[raw/company-tech-blogs/snowflake-twitter-id]]
|
||
- [[raw/company-tech-blogs/spring-modulith-archunit-generated-exemption-and-violations-as-data]]
|
||
- [[raw/company-tech-blogs/sse-realtime-notification-woowahan]]
|
||
- [[raw/company-tech-blogs/stripe-error-format]]
|
||
- [[raw/company-tech-blogs/test-pyramid-vs-trophy-kent-dodds]]
|
||
- [[raw/company-tech-blogs/threadlocal-capture-restore-att-israel]]
|
||
- [[raw/company-tech-blogs/toss-payments-error-format]]
|
||
- [[raw/company-tech-blogs/tracing-datadog-apm-vs-opentelemetry]]
|
||
- [[raw/company-tech-blogs/transaction-port-clean-ddd-spring-medium]]
|
||
- [[raw/company-tech-blogs/transaction-port-vassilis-soum-github-readme]]
|
||
- [[raw/company-tech-blogs/woowahan-hexagonal-multimodule]]
|
||
- [[raw/official-docs/actuator-endpoint-exposure-spring-official]]
|
||
- [[raw/official-docs/actuator-istio-sidecar-management-alt]]
|
||
- [[raw/official-docs/actuator-management-port-spring-official]]
|
||
- [[raw/official-docs/adapter-java-spi-serviceloader]]
|
||
- [[raw/official-docs/adapter-spring-boot-autoconfig-custom-starter]]
|
||
- [[raw/official-docs/api-versioning-google-aip-180]]
|
||
- [[raw/official-docs/arch-acl-microsoft-pattern]]
|
||
- [[raw/official-docs/arch-clean-architecture-uncle-bob]]
|
||
- [[raw/official-docs/arch-hexagonal-cockburn]]
|
||
- [[raw/official-docs/archunit-annotation-as-registry-evaluation]]
|
||
- [[raw/official-docs/archunit-conditional-on-property-3-layer-pattern]]
|
||
- [[raw/official-docs/archunit-user-guide]]
|
||
- [[raw/official-docs/at-transactional-spring-official]]
|
||
- [[raw/official-docs/aws-builders-retry-jitter]]
|
||
- [[raw/official-docs/aws-iam-google-iam-permission-naming-convention]]
|
||
- [[raw/official-docs/baggage-otel-baggage-api-spec]]
|
||
- [[raw/official-docs/baggage-w3c-baggage-spec]]
|
||
- [[raw/official-docs/cache-aside-vs-write-through-aws]]
|
||
- [[raw/official-docs/cache-caffeine-asyncloadingcache-readme]]
|
||
- [[raw/official-docs/cache-redisson-rlock-vs-setnx]]
|
||
- [[raw/official-docs/calver-spec-calver-official]]
|
||
- [[raw/official-docs/checkstyle-google-style-reference]]
|
||
- [[raw/official-docs/ci-github-actions-vs-gitlab-comparison]]
|
||
- [[raw/official-docs/ci-openapi-snapshot-diff-tooling]]
|
||
- [[raw/official-docs/cloudevents-spec-required-attributes]]
|
||
- [[raw/official-docs/compat-rfc-8594-sunset-header]]
|
||
- [[raw/official-docs/config-12-factor-app-config]]
|
||
- [[raw/official-docs/config-aws-appconfig-feature-flag-deployment]]
|
||
- [[raw/official-docs/config-spring-boot-externalized-configuration]]
|
||
- [[raw/official-docs/config-spring-cloud-config-server-official]]
|
||
- [[raw/official-docs/config-spring-cloud-kubernetes-configmap-reload]]
|
||
- [[raw/official-docs/container-alpine-java-musl-tradeoffs]]
|
||
- [[raw/official-docs/container-distroless-google-github]]
|
||
- [[raw/official-docs/container-graalvm-native-image-spring-boot]]
|
||
- [[raw/official-docs/cosign-keyless-identity-verification-policy]]
|
||
- [[raw/official-docs/cqrs-fowler-bliki]]
|
||
- [[raw/official-docs/cqrs-pattern-azure-architecture-center]]
|
||
- [[raw/official-docs/crockford-base32-spec]]
|
||
- [[raw/official-docs/cuid2-spec]]
|
||
- [[raw/official-docs/dependabot-supported-ecosystems-official]]
|
||
- [[raw/official-docs/domain-event-fowler-eaa]]
|
||
- [[raw/official-docs/domain-fowler-anemic-vs-rich-model]]
|
||
- [[raw/official-docs/domain-vaughn-vernon-aggregate-root]]
|
||
- [[raw/official-docs/dual-write-antipattern-microservices-io]]
|
||
- [[raw/official-docs/dx-devcontainer-spring-boot]]
|
||
- [[raw/official-docs/dx-mise-asdf-tool-versioning]]
|
||
- [[raw/official-docs/dx-testcontainers-java-best-practices]]
|
||
- [[raw/official-docs/ecs-awslogs-stdout-cloudwatch-aws-official]]
|
||
- [[raw/official-docs/errorprone-gradle-plugin-readme]]
|
||
- [[raw/official-docs/event-sourcing-vs-outbox-microservices-io]]
|
||
- [[raw/official-docs/feature-first-uncle-bob-screaming-architecture-2011]]
|
||
- [[raw/official-docs/fetch-spec-cors]]
|
||
- [[raw/official-docs/file-s3-presigned-url-upload]]
|
||
- [[raw/official-docs/file-tus-resumable-upload-protocol]]
|
||
- [[raw/official-docs/find-sec-bugs-official]]
|
||
- [[raw/official-docs/functional-tx-arrow-kt-resource-docs]]
|
||
- [[raw/official-docs/gdpr-cryptographic-erasure-envelope-key-pattern]]
|
||
- [[raw/official-docs/github-webhook-signature]]
|
||
- [[raw/official-docs/google-aip-122-resource-names]]
|
||
- [[raw/official-docs/google-aip-127-http-transcoding]]
|
||
- [[raw/official-docs/google-aip-132-list-method]]
|
||
- [[raw/official-docs/google-aip-136-custom-methods]]
|
||
- [[raw/official-docs/google-aip-148-standard-fields]]
|
||
- [[raw/official-docs/google-aip-151-long-running-operations]]
|
||
- [[raw/official-docs/google-aip-158-pagination]]
|
||
- [[raw/official-docs/google-aip-160-filtering]]
|
||
- [[raw/official-docs/google-aip-185-resource-versioning]]
|
||
- [[raw/official-docs/google-aip-233-batch-create]]
|
||
- [[raw/official-docs/google-antigravity-hooks]]
|
||
- [[raw/official-docs/google-api-error-format]]
|
||
- [[raw/official-docs/google-java-format-readme]]
|
||
- [[raw/official-docs/governance-archunit-official]]
|
||
- [[raw/official-docs/gradle-java-library-api-vs-implementation]]
|
||
- [[raw/official-docs/graphql-errors-spec]]
|
||
- [[raw/official-docs/hexagonal-cockburn-wikipedia-summary]]
|
||
- [[raw/official-docs/hexagonal-thombergs-buckpal-github]]
|
||
- [[raw/official-docs/idempotency-aws-lambda-powertools]]
|
||
- [[raw/official-docs/idempotency-ietf-draft]]
|
||
- [[raw/official-docs/idempotency-no-api-level-github-rest]]
|
||
- [[raw/official-docs/idempotency-paypal-docs]]
|
||
- [[raw/official-docs/idempotency-square-api]]
|
||
- [[raw/official-docs/idempotency-stripe-api-ref]]
|
||
- [[raw/official-docs/jdk21-threadpoolexecutor-javadoc]]
|
||
- [[raw/official-docs/json-api-errors-spec]]
|
||
- [[raw/official-docs/jsonapi-pagination-format]]
|
||
- [[raw/official-docs/junit5-conditional-env-variable-user-guide]]
|
||
- [[raw/official-docs/jwks-keycloak-key-rotation-active-passive]]
|
||
- [[raw/official-docs/jwks-nimbus-jose-jwksourcebuilder-spring-integration]]
|
||
- [[raw/official-docs/k8s-application-security-checklist-readonly-fs]]
|
||
- [[raw/official-docs/k8s-configure-probes-task-page]]
|
||
- [[raw/official-docs/k8s-logging-architecture-kubernetes-official]]
|
||
- [[raw/official-docs/k8s-pod-lifecycle-probes-concept]]
|
||
- [[raw/official-docs/k8s-pod-security-standards-restricted]]
|
||
- [[raw/official-docs/keycloak-authorization-services-realm-client-roles]]
|
||
- [[raw/official-docs/kubernetes-exit-code-observability-termination]]
|
||
- [[raw/official-docs/kubernetes-pod-lifecycle-termination]]
|
||
- [[raw/official-docs/layer-first-baeldung-clean-architecture-spring-boot]]
|
||
- [[raw/official-docs/lock-postgres-advisory-locks]]
|
||
- [[raw/official-docs/lock-shedlock-issue-899-non-scheduler-use]]
|
||
- [[raw/official-docs/lock-shedlock-readme]]
|
||
- [[raw/official-docs/lock-spring-integration-lock-registry]]
|
||
- [[raw/official-docs/log-ecs-schema-elastic-official]]
|
||
- [[raw/official-docs/log-logback-mask-pattern-converter-official]]
|
||
- [[raw/official-docs/log-otel-log-data-model-spec]]
|
||
- [[raw/official-docs/lombok-builder-data-features-official]]
|
||
- [[raw/official-docs/mapstruct-generated-annotation-official]]
|
||
- [[raw/official-docs/metric-google-sre-slo-burn-rate]]
|
||
- [[raw/official-docs/metric-google-sre-workbook-on-call]]
|
||
- [[raw/official-docs/metric-micrometer-high-cardinality-tags-detector]]
|
||
- [[raw/official-docs/metric-micrometer-histogram-percentile-concepts]]
|
||
- [[raw/official-docs/metric-micrometer-naming-convention-official]]
|
||
- [[raw/official-docs/metric-otel-metrics-data-model-spec]]
|
||
- [[raw/official-docs/metric-prometheus-histograms-vs-summaries-practices]]
|
||
- [[raw/official-docs/metric-prometheus-label-cardinality-best-practices]]
|
||
- [[raw/official-docs/micrometer-context-propagation-official]]
|
||
- [[raw/official-docs/micrometer-context-propagation-purpose-thread-local-accessor]]
|
||
- [[raw/official-docs/microservices-io-transactional-outbox]]
|
||
- [[raw/official-docs/migration-atlas-schema-as-code]]
|
||
- [[raw/official-docs/migration-flyway-official-concepts-and-repair]]
|
||
- [[raw/official-docs/migration-k8s-init-container-job-pattern]]
|
||
- [[raw/official-docs/migration-liquibase-official-changelog-xml-yaml]]
|
||
- [[raw/official-docs/modulith-spring-official-doc]]
|
||
- [[raw/official-docs/multitenancy-aws-saas-tenant-isolation-whitepaper]]
|
||
- [[raw/official-docs/multitenancy-azure-architecture-patterns]]
|
||
- [[raw/official-docs/multitenancy-hibernate-user-guide]]
|
||
- [[raw/official-docs/multitenancy-microservices-io-pattern]]
|
||
- [[raw/official-docs/mysql-innodb-transaction-isolation-official]]
|
||
- [[raw/official-docs/nanoid-spec]]
|
||
- [[raw/official-docs/onion-palermo-original-2008]]
|
||
- [[raw/official-docs/openjdk-jdk-8196595-container-support]]
|
||
- [[raw/official-docs/opentelemetry-http-semconv-migration-guide]]
|
||
- [[raw/official-docs/opentelemetry-versioning-stability-spec]]
|
||
- [[raw/official-docs/otel-exceptions-semantic-conventions]]
|
||
- [[raw/official-docs/outbound-openfeign-declarative-client]]
|
||
- [[raw/official-docs/outbound-resilience4j-vs-spring-retry]]
|
||
- [[raw/official-docs/outbound-spring-restclient-baseline]]
|
||
- [[raw/official-docs/outbound-webclient-vs-restclient-spring]]
|
||
- [[raw/official-docs/outbox-debezium-official-docs]]
|
||
- [[raw/official-docs/outbox-skip-locked-microservices-io]]
|
||
- [[raw/official-docs/owasp-authz-permission-model-abac-rbac]]
|
||
- [[raw/official-docs/owasp-file-upload-cheat-sheet]]
|
||
- [[raw/official-docs/owasp-hsts-cheat-sheet]]
|
||
- [[raw/official-docs/owasp-logging-cheat-sheet]]
|
||
- [[raw/official-docs/owasp-path-traversal]]
|
||
- [[raw/official-docs/owasp-ssrf-prevention]]
|
||
- [[raw/official-docs/patch-json-merge-rfc7396]]
|
||
- [[raw/official-docs/persistence-hikaricp-pool-sizing-wiki]]
|
||
- [[raw/official-docs/persistence-osiv-antipattern-hibernate-vladmihalcea]]
|
||
- [[raw/official-docs/persistence-r2dbc-reactive-spring]]
|
||
- [[raw/official-docs/persistence-spring-dataaccessexception-hierarchy]]
|
||
- [[raw/official-docs/postgres-transaction-isolation-official]]
|
||
- [[raw/official-docs/privacy-cryptographic-erasure-nist-sp800-88]]
|
||
- [[raw/official-docs/privacy-gdpr-article-25-design]]
|
||
- [[raw/official-docs/problem-detail-rfc-7807]]
|
||
- [[raw/official-docs/protobuf-reserved-vs-json-openapi-extension]]
|
||
- [[raw/official-docs/redhat-openjdk-container-awareness-java17]]
|
||
- [[raw/official-docs/registry-adr-official]]
|
||
- [[raw/official-docs/reproducible-builds-org-jvm-guide]]
|
||
- [[raw/official-docs/retry-aws-well-architected-rel05-bp03]]
|
||
- [[raw/official-docs/retry-spring-retry-readme-backoff-defaults]]
|
||
- [[raw/official-docs/rfc3986-uri-generic-syntax]]
|
||
- [[raw/official-docs/rfc6455-websocket]]
|
||
- [[raw/official-docs/rfc9111-http-caching]]
|
||
- [[raw/official-docs/rfc9112-http-1-1-chunked-transfer]]
|
||
- [[raw/official-docs/rfc9421-http-message-signatures]]
|
||
- [[raw/official-docs/rfc9457-problem-details-http-apis]]
|
||
- [[raw/official-docs/rfc9562-uuid]]
|
||
- [[raw/official-docs/runbook-pagerduty-incident-response-doc]]
|
||
- [[raw/official-docs/runtime-health-istio-mesh-health-check]]
|
||
- [[raw/official-docs/runtime-health-k8s-probes-official]]
|
||
- [[raw/official-docs/runtime-health-spring-actuator-groups]]
|
||
- [[raw/official-docs/runtime-spring-boot-virtual-threads]]
|
||
- [[raw/official-docs/sample-microservices-spring-cloud-github]]
|
||
- [[raw/official-docs/sample-realworld-gothinkster-github]]
|
||
- [[raw/official-docs/sample-spring-petclinic-github]]
|
||
- [[raw/official-docs/scaffolding-cookiecutter-official]]
|
||
- [[raw/official-docs/scaffolding-degit-svelte-github]]
|
||
- [[raw/official-docs/scaffolding-github-template-repository]]
|
||
- [[raw/official-docs/scaffolding-spring-initializr]]
|
||
- [[raw/official-docs/schema-avro-evolution-rules]]
|
||
- [[raw/official-docs/schema-bigdecimal-money-serialization-java]]
|
||
- [[raw/official-docs/schema-jackson-polymorphic-deserialization]]
|
||
- [[raw/official-docs/schema-jackson-unknown-field-handling]]
|
||
- [[raw/official-docs/schema-protobuf-vs-json-evolution]]
|
||
- [[raw/official-docs/scoped-value-jep-446-506-openjdk]]
|
||
- [[raw/official-docs/scorecard-aws-well-architected]]
|
||
- [[raw/official-docs/scorecard-cis-benchmarks-slsa]]
|
||
- [[raw/official-docs/scorecard-opentelemetry-maturity]]
|
||
- [[raw/official-docs/secrets-aws-secrets-manager-rotation]]
|
||
- [[raw/official-docs/secrets-k8s-secret-external-secrets-operator]]
|
||
- [[raw/official-docs/secrets-vault-dynamic-secrets-hashicorp]]
|
||
- [[raw/official-docs/security-authorization-cheatsheet-owasp]]
|
||
- [[raw/official-docs/security-aws-sigv4-hmac-signing]]
|
||
- [[raw/official-docs/security-jwt-rfc-7519-validation]]
|
||
- [[raw/official-docs/security-mtls-rfc-8705]]
|
||
- [[raw/official-docs/security-oauth2-pkce-rfc-8252]]
|
||
- [[raw/official-docs/security-opa-policy-engine-official]]
|
||
- [[raw/official-docs/security-spring-jwt-timestamp-validator-clock-skew]]
|
||
- [[raw/official-docs/semver-2-0-0-spec-semver-official]]
|
||
- [[raw/official-docs/skip-locked-mysql-docs]]
|
||
- [[raw/official-docs/skip-locked-postgres-docs]]
|
||
- [[raw/official-docs/slsa-v1-provenance-schema]]
|
||
- [[raw/official-docs/sonarqube-server-versus-cloud]]
|
||
- [[raw/official-docs/spotbugs-gradle-plugin-docs]]
|
||
- [[raw/official-docs/spotless-gradle-plugin-readme]]
|
||
- [[raw/official-docs/spring-boot-exit-code-generator-startup-failure]]
|
||
- [[raw/official-docs/spring-boot-graceful-shutdown-reference]]
|
||
- [[raw/official-docs/spring-boot-structuring-your-code]]
|
||
- [[raw/official-docs/spring-boot-task-execution-scheduling-reference]]
|
||
- [[raw/official-docs/spring-boot-test-slices-webmvctest-datajpatest-official]]
|
||
- [[raw/official-docs/spring-data-jpa-auditing-official]]
|
||
- [[raw/official-docs/spring-data-jpa-projections-spring-official]]
|
||
- [[raw/official-docs/spring-data-jpa-transactionality-spring-official]]
|
||
- [[raw/official-docs/spring-data-pageable-defaults]]
|
||
- [[raw/official-docs/spring-executor-configuration-support-javadoc]]
|
||
- [[raw/official-docs/spring-framework-observability-context-propagating-task-decorator]]
|
||
- [[raw/official-docs/spring-framework-test-enabledif-jupiter-annotation]]
|
||
- [[raw/official-docs/spring-framework-threadpooltaskexecutor-javadoc]]
|
||
- [[raw/official-docs/spring-mvc-async-streaming]]
|
||
- [[raw/official-docs/spring-mvc-rest-exception-handling]]
|
||
- [[raw/official-docs/spring-problem-detail]]
|
||
- [[raw/official-docs/spring-security-authorization-architecture]]
|
||
- [[raw/official-docs/spring-security-concurrency-delegating-security-context-executor]]
|
||
- [[raw/official-docs/spring-transaction-synchronization-manager-javadoc]]
|
||
- [[raw/official-docs/spring-transactional-event-listener]]
|
||
- [[raw/official-docs/spring-tx-propagation-required-new-nested-official]]
|
||
- [[raw/official-docs/stripe-resource-id-convention]]
|
||
- [[raw/official-docs/stripe-webhook-signature]]
|
||
- [[raw/official-docs/sunset-deprecation-headers-paired-usage]]
|
||
- [[raw/official-docs/supply-chain-cosign-keyless-sigstore]]
|
||
- [[raw/official-docs/supply-chain-gradle-vs-maven-dependency-locking]]
|
||
- [[raw/official-docs/supply-chain-slsa-provenance-framework]]
|
||
- [[raw/official-docs/svix-webhook-best-practices]]
|
||
- [[raw/official-docs/sysexits-bsd-exit-code-convention]]
|
||
- [[raw/official-docs/test-taxonomy-practical-pyramid-fowler]]
|
||
- [[raw/official-docs/test-taxonomy-testcontainers-official]]
|
||
- [[raw/official-docs/threadlocal-virtual-threads-java21-oracle]]
|
||
- [[raw/official-docs/trace-context-w3c-recommendation]]
|
||
- [[raw/official-docs/tracing-b3-propagation-zipkin-spec]]
|
||
- [[raw/official-docs/tracing-micrometer-observation-introduction]]
|
||
- [[raw/official-docs/tracing-otel-sampling-tail-vs-head-spec]]
|
||
- [[raw/official-docs/tracing-otel-trace-api-spec]]
|
||
- [[raw/official-docs/tracing-spring-boot-3-actuator-tracing-reference]]
|
||
- [[raw/official-docs/tracing-w3c-trace-context-spec]]
|
||
- [[raw/official-docs/transaction-template-spring-official]]
|
||
- [[raw/official-docs/transactional-outbox-aws-prescriptive-guidance]]
|
||
- [[raw/official-docs/trivy-severity-exit-code-gating]]
|
||
- [[raw/official-docs/ulid-spec]]
|
||
- [[raw/official-docs/validation-jakarta-bean-validation-3.0-spec]]
|
||
- [[raw/official-docs/verification-approvaltests-snapshot-official]]
|
||
- [[raw/official-docs/verification-pact-cdc-official]]
|
||
- [[raw/official-docs/verification-spring-cloud-contract-official]]
|
||
- [[raw/official-docs/verification-spring-restdocs-official]]
|
||
- [[raw/official-docs/whatwg-html-server-sent-events]]
|
||
<!-- GENERATED: sources:end -->
|
||
|
||
<!-- GENERATED: interviews:start -->
|
||
- [[raw/interviews/archunit-manual-importer-vs-analyzeclasses]]
|
||
- [[raw/interviews/archunit-static-analysis-limits]]
|
||
- [[raw/interviews/async-executor-saturation-context-propagation-2026-06-13]]
|
||
- [[raw/interviews/ci-release-gate-fan-in-blocking-2026-06-20]]
|
||
- [[raw/interviews/clean-architecture-boundary-enforcement]]
|
||
- [[raw/interviews/clean-architecture-domain-onboarding-guardrails]]
|
||
- [[raw/interviews/clean-architecture-identifier-generation]]
|
||
- [[raw/interviews/clean-architecture-method-authorization-without-spring-coupling-2026-06-08]]
|
||
- [[raw/interviews/clean-architecture-module-blueprint]]
|
||
- [[raw/interviews/crown-one-query-vs-cqrs-lite-read-model]]
|
||
- [[raw/interviews/deterministic-logback-asyncappender-drop-metric-test-2026-06-14]]
|
||
- [[raw/interviews/digest-first-supply-chain-release-gates]]
|
||
- [[raw/interviews/domain-modeling-guardrails-archunit-2026-06-05]]
|
||
- [[raw/interviews/formatter-vs-style-linter-responsibility-split-2026-06-20]]
|
||
- [[raw/interviews/idempotency-rate-limit-design-tradeoffs-2026-06-09]]
|
||
- [[raw/interviews/jwt-resource-server-fine-grained-error-classification-2026-06-08]]
|
||
- [[raw/interviews/manifest-driven-multi-platform-agent-harness]]
|
||
- [[raw/interviews/native-query-addscalar-runtime-validation]]
|
||
- [[raw/interviews/operational-error-envelope-and-observability-foundation]]
|
||
- [[raw/interviews/optional-adapter-3-layer-disabled-detection-2026-06-09]]
|
||
- [[raw/interviews/post-implementation-knowledge-capture]]
|
||
- [[raw/interviews/sample-domain-contract-fixture-clean-architecture]]
|
||
- [[raw/interviews/shared-contract-and-sample-isolation]]
|
||
- [[raw/interviews/single-command-local-bootstrap]]
|
||
- [[raw/interviews/spring-jpa-flyway-initialization-lifecycle-circular-dependency]]
|
||
- [[raw/interviews/startup-fail-fast-config-validation-2026-06-06]]
|
||
- [[raw/interviews/transaction-port-vs-spring-transactional]]
|
||
- [[raw/interviews/transactional-outbox-skip-locked-implementation-2026-06-11]]
|
||
- [[raw/interviews/trivy-suppression-dual-control-governance-2026-06-20]]
|
||
<!-- GENERATED: interviews:end -->
|
||
|
||
<!-- GENERATED: blog-topics:start -->
|
||
- [[raw/blog-topics/api-deprecation-sunset-header-migration-window-2026-07-02]]
|
||
- [[raw/blog-topics/archunit-generic-return-type-purity-query-port-2026-06-05]]
|
||
- [[raw/blog-topics/archunit-jackson-default-typing-cve-2019-14379-block-2026-05-29]]
|
||
- [[raw/blog-topics/archunit-testcompileonly-fixture-annotation-pattern-2026-06-02]]
|
||
- [[raw/blog-topics/archunit-violations-as-data-pattern-2026-05-28]]
|
||
- [[raw/blog-topics/binary-readiness-scorecard-clean-architecture-skeleton-2026-07-02]]
|
||
- [[raw/blog-topics/boundary-validation-mapper-responsibility-map-2026-07-02]]
|
||
- [[raw/blog-topics/cache-backend-router-fail-open-decorator-2026-07-02]]
|
||
- [[raw/blog-topics/cache-consistency-after-commit-stampede-contract-2026-07-02]]
|
||
- [[raw/blog-topics/ci-gate-wiring-vs-policy-ownership-2026-06-20]]
|
||
- [[raw/blog-topics/clean-architecture-boundary-enforcement-2026-05-28]]
|
||
- [[raw/blog-topics/clean-architecture-module-blueprint-2026-05-28]]
|
||
- [[raw/blog-topics/clean-architecture-reference-project-adoption-2026-06-17]]
|
||
- [[raw/blog-topics/contract-registry-schema-owner-vs-row-owner-gate-2026-06-20]]
|
||
- [[raw/blog-topics/contract-verification-suite-release-gates-2026-07-02]]
|
||
- [[raw/blog-topics/digest-first-java-release-pipeline-2026-06-21]]
|
||
- [[raw/blog-topics/distributed-lock-transaction-commit-boundary-2026-07-02]]
|
||
- [[raw/blog-topics/domain-modeling-guardrails-as-archunit-fitness-functions-2026-06-05]]
|
||
- [[raw/blog-topics/env-example-drift-gate-gradle-2026-06-06]]
|
||
- [[raw/blog-topics/executable-clean-architecture-onboarding-2026-06-25]]
|
||
- [[raw/blog-topics/five-stage-local-bootstrap-contract-2026-06-24]]
|
||
- [[raw/blog-topics/framework-free-method-authorization-clean-architecture-2026-06-08]]
|
||
- [[raw/blog-topics/gitea-act-dependency-security-gate-portability-2026-07-02]]
|
||
- [[raw/blog-topics/gradle9-java21-static-analysis-baseline-2026-06-20]]
|
||
- [[raw/blog-topics/hikaricp-inter-knob-constraints-startup-guard-2026-06-09]]
|
||
- [[raw/blog-topics/idempotency-executor-application-layer-clean-architecture-2026-06-09]]
|
||
- [[raw/blog-topics/identifier-governance-rule-scoping-by-id-kind-2026-06-01]]
|
||
- [[raw/blog-topics/java21-context-propagation-strategy-virtual-threads-2026-07-02]]
|
||
- [[raw/blog-topics/jdk-httpclient-dns-connectexception-classification-2026-07-02]]
|
||
- [[raw/blog-topics/jvm-oom-vs-container-oomkill-exit-137-2026-07-02]]
|
||
- [[raw/blog-topics/logback-layer1-secret-masking-json-vs-pattern-2026-06-14]]
|
||
- [[raw/blog-topics/manifest-driven-agent-harness-policy-engine]]
|
||
- [[raw/blog-topics/micrometer-meterfilter-resilience4j-functioncounter-2026-07-02]]
|
||
- [[raw/blog-topics/nplus1-lab-checkoutable-api-replay-2026-07-15]]
|
||
- [[raw/blog-topics/operational-error-envelope-meta-category-migration-2026-06-01]]
|
||
- [[raw/blog-topics/persistence-audit-metadata-clean-architecture-2026-07-02]]
|
||
- [[raw/blog-topics/post-implementation-knowledge-capture-workflow-2026-05-28]]
|
||
- [[raw/blog-topics/repository-capability-archunit-fitness-function-2026-07-02]]
|
||
- [[raw/blog-topics/runbook-coverage-junit-contract-test-2026-07-02]]
|
||
- [[raw/blog-topics/sample-domain-contract-fixture-clean-architecture-2026-06-10]]
|
||
- [[raw/blog-topics/sample-fixture-dual-mode-build-matrix-2026-06-25]]
|
||
- [[raw/blog-topics/secret-source-port-restart-only-rotation-2026-07-02]]
|
||
- [[raw/blog-topics/skip-locked-outbox-per-aggregate-fifo-gate-2026-06-11]]
|
||
- [[raw/blog-topics/spring-actuator-health-probe-group-split-2026-07-02]]
|
||
- [[raw/blog-topics/spring-async-taskdecorator-bounded-executor-saturation-shutdown-2026-06-13]]
|
||
- [[raw/blog-topics/spring-boot-3-configprops-record-multi-constructor-binding-2026-06-12]]
|
||
- [[raw/blog-topics/spring-boot-serialization-contract-pins-2026-07-02]]
|
||
- [[raw/blog-topics/spring-boot-startup-exit-code-propagation-2026-06-10]]
|
||
- [[raw/blog-topics/spring-conditional-on-property-optional-adapter-template-2026-06-09]]
|
||
- [[raw/blog-topics/spring-responseentityexceptionhandler-transport-failure-envelope-2026-07-02]]
|
||
- [[raw/blog-topics/spring-security-filter-layer-error-envelope-2026-06-08]]
|
||
- [[raw/blog-topics/streaming-response-not-supported-archunit-ban-2026-07-02]]
|
||
- [[raw/blog-topics/test-taxonomy-archunit-enforcement-2026-06-19]]
|
||
- [[raw/blog-topics/transaction-isolation-vendor-default-pin-2026-07-02]]
|
||
- [[raw/blog-topics/transaction-port-abstraction-over-spring-transactional-2026-05-28]]
|
||
- [[raw/blog-topics/trivy-suppression-governance-static-gate-2026-06-20]]
|
||
- [[raw/blog-topics/ulid-crockford-base32-excluded-letters-2026-06-01]]
|
||
- [[raw/blog-topics/w3c-traceparent-fork-activated-seam-2026-07-02]]
|
||
- [[raw/blog-topics/webhook-full-jitter-dlq-observability-2026-07-02]]
|
||
- [[raw/blog-topics/webhook-signature-replay-contract-2026-07-02]]
|
||
- [[raw/blog-topics/webhook-ssrf-egress-proxy-redirect-block-2026-07-02]]
|
||
<!-- GENERATED: blog-topics:end -->
|
||
|
||
<!-- GENERATED: errors:start -->
|
||
- [[raw/errors/apply-patch-auto-approval-rejected-2026-05-28]]
|
||
- [[raw/errors/archunit-b7-configprops-nested-record-accessor-outbound-2026-06-13]]
|
||
- [[raw/errors/archunit-b7-configuration-bean-factory-return-type-2026-06-09]]
|
||
- [[raw/errors/archunit-empty-should-anchor-2026-05-27]]
|
||
- [[raw/errors/archunit-importpackages-empty-vacuous-stale-build-2026-06-20]]
|
||
- [[raw/errors/archunit-no-uuid-random-trace-id-false-positive-2026-06-01]]
|
||
- [[raw/errors/archunit-test-scope-sample-ticket-inclusion-2026-05-28]]
|
||
- [[raw/errors/bootstrap-postgres-port-collision-2026-06-24]]
|
||
- [[raw/errors/ca-gitignored-seed-divergence-at-rebase]]
|
||
- [[raw/errors/ca-public-path-snapshot-scope-violation]]
|
||
- [[raw/errors/ca-tmpl-preexisting-check-baseline-failures-2026-07-20]]
|
||
- [[raw/errors/ci-fan-in-skipped-not-failed-and-gitignored-config-2026-06-20]]
|
||
- [[raw/errors/contract-registry-reference-row-universal-column-false-fail-2026-06-20]]
|
||
- [[raw/errors/developer-experience-contract-agents-bridge-2026-07-15]]
|
||
- [[raw/errors/flyway-launcher-divergent-migration-set-shared-dev-db-2026-06-12]]
|
||
- [[raw/errors/gitea-act-action-tag-and-dependency-graph-2026-06-20]]
|
||
- [[raw/errors/gitea-act-missing-jq-job-bootstrap-2026-06-23]]
|
||
- [[raw/errors/global-sed-env-rename-pitfalls-2026-06-06]]
|
||
- [[raw/errors/gradle-strict-lock-stale-entry-non-resolvable-config-2026-07-08]]
|
||
- [[raw/errors/gradle-wrapper-lock-read-only-sandbox-2026-06-10]]
|
||
- [[raw/errors/gradle-wrapper-readonly-cache-2026-05-28]]
|
||
- [[raw/errors/gradle-wrapper-sandbox-lock-2026-06-25]]
|
||
- [[raw/errors/gradle-wrapper-sandbox-lock-readiness-scorecard-2026-06-26]]
|
||
- [[raw/errors/hibernate-dto-projection-explain-width-not-narrower-2026-07-13]]
|
||
- [[raw/errors/hibernate-getcollectionfetchcount-batch-semantics-2026-07-13]]
|
||
- [[raw/errors/hibernate7-hhh90003004-collection-fetch-paging-2026-07-13]]
|
||
- [[raw/errors/idempotency-column-definition-base-check-failure-2026-07-15]]
|
||
- [[raw/errors/idempotency-expired-row-reclaim-409-loop-2026-06-09]]
|
||
- [[raw/errors/internal-auth-misconfiguration-retryable-invariant-conflict-2026-06-08]]
|
||
- [[raw/errors/jdk-httpclient-dns-unresolvedaddress-connectexception-2026-06-11]]
|
||
- [[raw/errors/jpa-repository-scan-miss-multimodule-2026-06-10]]
|
||
- [[raw/errors/mapping-exception-location-archunit-catch-2026-05-29]]
|
||
- [[raw/errors/method-security-cglib-vs-jdk-proxy-usecase-injection-2026-06-08]]
|
||
- [[raw/errors/method-security-class-pointcut-final-usecase-bean-2026-06-12]]
|
||
- [[raw/errors/micrometer-meterfilter-replacetagvalues-functioncounter-2026-06-11]]
|
||
- [[raw/errors/mockmvc-406-produces-accept-double-fault-2026-06-02]]
|
||
- [[raw/errors/responseentityexceptionhandler-ambiguous-exception-handler-2026-06-02]]
|
||
- [[raw/errors/sample-portfolio-flyway-out-of-order-2026-06-23]]
|
||
- [[raw/errors/sample-portfolio-oauth2-resource-server-dependency-2026-05-27]]
|
||
- [[raw/errors/sample-portfolio-tomcat-port-in-use-check-2026-07-03]]
|
||
- [[raw/errors/sample-ticket-oauth2-resource-server-dependency-2026-05-27]]
|
||
- [[raw/errors/sandbox-build-verification-boundaries-2026-06-21]]
|
||
- [[raw/errors/scheduled-reaper-wrong-config-prefix-2026-06-09]]
|
||
- [[raw/errors/slim-jre-random-generator-missing-2026-06-24]]
|
||
- [[raw/errors/spanerrorrecorder-constructor-breaks-webmvctest-slice-2026-06-14]]
|
||
- [[raw/errors/spotbugs-commons-lang3-bom-downgrade-noclassdef-2026-06-20]]
|
||
- [[raw/errors/spring-boot-four-jackson-three-migration-2026-06-30]]
|
||
- [[raw/errors/spring-configuration-bean-factory-method-not-processed-2026-06-11]]
|
||
- [[raw/errors/spring-integration-defaultlockrepository-aftersingletons-null-template-2026-06-13]]
|
||
- [[raw/errors/spring-jpa-flyway-circular-dependency-2026-06-23]]
|
||
- [[raw/errors/spring-jpa-postgres-lob-oid-cast-2026-06-23]]
|
||
- [[raw/errors/startup-log-suppression-spotless-format-2026-07-03]]
|
||
- [[raw/errors/testcontainers-two-context-shared-datasource-close-2026-06-11]]
|
||
- [[raw/errors/ulid-fixture-crockford-u-self-inconsistency-2026-06-01]]
|
||
- [[raw/errors/webmvctest-component-filter-constructor-dep-breaks-slice-2026-06-14]]
|
||
- [[raw/errors/webmvctest-nested-springbootconfiguration-context-pollution-2026-06-01]]
|
||
- [[raw/errors/webmvctest-slice-configprops-enum-placeholder-no-default-2026-06-20]]
|
||
<!-- GENERATED: errors:end -->
|
||
|
||
> ca-skeleton (= ca-tmpl) 프로젝트에 묶이는 모든 raw 자료. ca-tmpl repo (`/home/donghyeon/workspace/ca-tmpl/`) 의 코드와 함께 본 LLM Wiki 의 자료들이 cluster 구성.
|
||
|
||
### 31.1 브랜치 (feature-* / develop-* / fix-* / chore-* / experiment-*)
|
||
|
||
<!-- GENERATED: branches:start -->
|
||
- [[raw/branch-notes/feature-api-compatibility-deprecation-contract]]
|
||
- [[raw/branch-notes/feature-api-contract-baseline]]
|
||
- [[raw/branch-notes/feature-application-port-usecase-contract]]
|
||
- [[raw/branch-notes/feature-application-query-bypass-contract]]
|
||
- [[raw/branch-notes/feature-architecture-enforcement-rules]]
|
||
- [[raw/branch-notes/feature-authentication-authorization-contract]]
|
||
- [[raw/branch-notes/feature-background-job-async-contract]]
|
||
- [[raw/branch-notes/feature-boundary-validation-mapping-contract]]
|
||
- [[raw/branch-notes/feature-build-release-supply-chain-contract]]
|
||
- [[raw/branch-notes/feature-business-rule-validation-contract]]
|
||
- [[raw/branch-notes/feature-cache-consistency-contract]]
|
||
- [[raw/branch-notes/feature-cachestore-multi-backend-router]]
|
||
- [[raw/branch-notes/feature-ci-quality-gates-contract]]
|
||
- [[raw/branch-notes/feature-container-runtime-contract]]
|
||
- [[raw/branch-notes/feature-contract-registry-governance]]
|
||
- [[raw/branch-notes/feature-contract-verification-test-suite]]
|
||
- [[raw/branch-notes/feature-data-retention-privacy-contract]]
|
||
- [[raw/branch-notes/feature-database-connection-pool-contract]]
|
||
- [[raw/branch-notes/feature-dependency-vulnerability-management-contract]]
|
||
- [[raw/branch-notes/feature-developer-experience-contract]]
|
||
- [[raw/branch-notes/feature-distributed-lock-contract]]
|
||
- [[raw/branch-notes/feature-distributed-tracing-contract]]
|
||
- [[raw/branch-notes/feature-domain-event-outbox-contract]]
|
||
- [[raw/branch-notes/feature-domain-feature-onboarding-contract]]
|
||
- [[raw/branch-notes/feature-domain-modeling-guardrails]]
|
||
- [[raw/branch-notes/feature-env-driven-runtime-configuration]]
|
||
- [[raw/branch-notes/feature-file-resource-handling-contract]]
|
||
- [[raw/branch-notes/feature-implementation-readiness-scorecard]]
|
||
- [[raw/branch-notes/feature-integration-adapter-templates]]
|
||
- [[raw/branch-notes/feature-log-management-contract]]
|
||
- [[raw/branch-notes/feature-management-actuator-security-contract]]
|
||
- [[raw/branch-notes/feature-messaging-multibroker-router]]
|
||
- [[raw/branch-notes/feature-metrics-alerting-contract]]
|
||
- [[raw/branch-notes/feature-migration-startup-contract]]
|
||
- [[raw/branch-notes/feature-notification-provider-spi]]
|
||
- [[raw/branch-notes/feature-operational-error-observability-foundation]]
|
||
- [[raw/branch-notes/feature-operational-runbook-contract]]
|
||
- [[raw/branch-notes/feature-outbound-http-client-baseline]]
|
||
- [[raw/branch-notes/feature-persistence-auditing-contract]]
|
||
- [[raw/branch-notes/feature-persistence-failure-baseline]]
|
||
- [[raw/branch-notes/feature-rate-limit-idempotency-contract]]
|
||
- [[raw/branch-notes/feature-repository-access-permission-contract]]
|
||
- [[raw/branch-notes/feature-resource-identifier-contract]]
|
||
- [[raw/branch-notes/feature-runtime-context-propagation-contract]]
|
||
- [[raw/branch-notes/feature-runtime-health-lifecycle-contract]]
|
||
- [[raw/branch-notes/feature-sample-domain-contract-fixture]]
|
||
- [[raw/branch-notes/feature-sample-portfolio-public-access]]
|
||
- [[raw/branch-notes/feature-sample-removal-adoption-contract]]
|
||
- [[raw/branch-notes/feature-schema-serialization-contract]]
|
||
- [[raw/branch-notes/feature-secrets-config-source-contract]]
|
||
- [[raw/branch-notes/feature-security-operational-baseline]]
|
||
- [[raw/branch-notes/feature-skeleton-package-blueprint-contract]]
|
||
- [[raw/branch-notes/feature-startup-failure-log-suppression]]
|
||
- [[raw/branch-notes/feature-static-analysis-quality-contract]]
|
||
- [[raw/branch-notes/feature-streaming-response-contract]]
|
||
- [[raw/branch-notes/feature-tenant-context-policy]]
|
||
- [[raw/branch-notes/feature-test-taxonomy-fixture-contract]]
|
||
- [[raw/branch-notes/feature-transaction-concurrency-contract]]
|
||
- [[raw/branch-notes/feature-webhook-outbound-contract]]
|
||
<!-- GENERATED: branches:end -->
|
||
|
||
> generated reverse view는 child branch의 v2 contract migration 후 채운다. 아래 수기 목록은 그 전까지 legacy navigation으로 보존한다.
|
||
|
||
> ca-skeleton 은 root branch 가 단일이 아니라 다수의 `feature-*` 가 직접 project 에 매달림. 모두 Tier-1 hub.
|
||
|
||
핵심 `feature-*` branch-notes (`raw/branch-notes/`):
|
||
|
||
- [[raw/branch-notes/feature-architecture-enforcement-rules]] — ArchUnit + Gradle dependency
|
||
- [[raw/branch-notes/feature-skeleton-package-blueprint-contract]] — Gradle multi-module Clean Architecture / Hexagonal module blueprint
|
||
- [[raw/branch-notes/feature-domain-modeling-guardrails]] — VO/Entity/Aggregate 규칙
|
||
- [[raw/branch-notes/feature-application-port-usecase-contract]] — TransactionPort / Use Case
|
||
- [[raw/branch-notes/feature-boundary-validation-mapping-contract]] — Validation 4-layer
|
||
- [[raw/branch-notes/feature-api-contract-baseline]] — `/v1`, Idempotency-Key, Pagination
|
||
- [[raw/branch-notes/feature-api-compatibility-deprecation-contract]] — Sunset + Deprecation 90/30 일
|
||
- [[raw/branch-notes/feature-contract-registry-governance]] — error/env/log/metric registry SSOT
|
||
- [[raw/branch-notes/feature-sample-removal-adoption-contract]] — sample-portfolio 제거 2단계
|
||
- [[raw/branch-notes/feature-business-rule-validation-contract]] — 도메인 vs 인프라 검증 책임
|
||
- [[raw/branch-notes/feature-domain-event-outbox-contract]] — SKIP LOCKED outbox
|
||
- [[raw/branch-notes/feature-transaction-concurrency-contract]] — READ_COMMITTED + retry
|
||
- [[raw/branch-notes/feature-cache-consistency-contract]] — after-commit invalidation + stampede
|
||
- [[raw/branch-notes/feature-persistence-failure-baseline]] — OSIV off + SQLState 매핑
|
||
- [[raw/branch-notes/feature-rate-limit-idempotency-contract]] — 3-tuple idempotency + 200ms wait
|
||
- [[raw/branch-notes/feature-file-resource-handling-contract]] — 3계층 size limit
|
||
- [[raw/branch-notes/feature-schema-serialization-contract]] — ISO-8601 + BigDecimal scale
|
||
- [[raw/branch-notes/feature-data-retention-privacy-contract]] — HMAC salt + GDPR Art.17
|
||
- [[raw/branch-notes/feature-integration-adapter-templates]] — Kafka/Redis/Slack/Google Email
|
||
- [[raw/branch-notes/feature-outbound-http-client-baseline]] — RestClient + Resilience4j
|
||
- [[raw/branch-notes/feature-background-job-async-contract]] — TaskDecorator + ShedLock
|
||
- [[raw/branch-notes/feature-distributed-tracing-contract]] — Micrometer Tracing + W3C
|
||
- [[raw/branch-notes/feature-log-management-contract]] — structured JSON + masking
|
||
- [[raw/branch-notes/feature-management-actuator-security-contract]] — port 9001 + allowlist
|
||
- [[raw/branch-notes/feature-metrics-alerting-contract]] — Micrometer + cardinality limit
|
||
- [[raw/branch-notes/feature-migration-startup-contract]] — Flyway + multi-instance lock
|
||
- [[raw/branch-notes/feature-operational-error-observability-foundation]] — custom envelope + 10 categories
|
||
- [[raw/branch-notes/feature-secrets-config-source-contract]] — `__LOCAL_DEV_` sentinel
|
||
- [[raw/branch-notes/feature-env-driven-runtime-configuration]] — APP_*, Duration `30s`
|
||
- [[raw/branch-notes/feature-container-runtime-contract]] — MaxRAMPercentage=75
|
||
- [[raw/branch-notes/feature-runtime-health-lifecycle-contract]] — 3-probe + NTP drift
|
||
- [[raw/branch-notes/feature-security-operational-baseline]] — JWT + JWKS refresh
|
||
- [[raw/branch-notes/feature-repository-access-permission-contract]] — @UseCaseRepositoryAccess
|
||
- [[raw/branch-notes/feature-tenant-context-policy]] — multi-tenancy opt-in
|
||
- [[raw/branch-notes/feature-operational-runbook-contract]] — runbook:// scheme
|
||
- [[raw/branch-notes/feature-contract-verification-test-suite]] — 11 release-blocking gates
|
||
- [[raw/branch-notes/feature-test-taxonomy-fixture-contract]] — 6 test levels
|
||
- [[raw/branch-notes/feature-sample-domain-contract-fixture]] — sample-portfolio 12 scenarios
|
||
- [[raw/branch-notes/feature-developer-experience-contract]] — `./gradlew bootstrap`
|
||
- [[raw/branch-notes/feature-ci-quality-gates-contract]] — 20 CI gates
|
||
- [[raw/branch-notes/feature-build-release-supply-chain-contract]] — SBOM + Cosign + SLSA
|
||
- [[raw/branch-notes/feature-domain-feature-onboarding-contract]] — multi-module domain onboarding slice
|
||
- [[raw/branch-notes/feature-implementation-readiness-scorecard]] — 15-area binary gate
|
||
- [[raw/branch-notes/feature-distributed-lock-contract]] — `distributedLockProvider` bean 계약 (JdbcLockRegistry default + tx commit 정합)
|
||
|
||
(총 44개 — `raw/branch-notes/feature-*.md` glob 으로 확인 가능)
|
||
|
||
### 31.2 근거 자료
|
||
|
||
- 개별 official-docs / company-tech-blogs 는 각 `feature-*` branch-note 의 Sources 표에서 cited.
|
||
|
||
### 31.3 오류 기록
|
||
|
||
- [[raw/errors/archunit-empty-should-anchor-2026-05-27]] — skeleton anchor package와 ArchUnit empty should rule 정합성 문제.
|
||
- [[raw/errors/sample-portfolio-oauth2-resource-server-dependency-2026-05-27]] — sample-portfolio 격리 후 OAuth2 resource-server dependency 누락 문제.
|
||
- [[raw/errors/gradle-wrapper-readonly-cache-2026-05-28]] — agent sandbox에서 Gradle wrapper cache lock 파일 생성 실패.
|
||
|
||
### 31.4 면접 준비
|
||
|
||
- [[raw/interviews/clean-architecture-module-blueprint]] — multi-module Clean Architecture skeleton 선택 이유.
|
||
- [[raw/interviews/shared-contract-and-sample-isolation]] — shared-contract와 sample-portfolio 격리 근거.
|
||
- [[raw/interviews/clean-architecture-boundary-enforcement]] — Gradle/ArchUnit 기반 경계 검증 경험.
|
||
|
||
### 31.5 블로그·채용공고 연계 글감
|
||
|
||
- [[raw/blog-topics/clean-architecture-module-blueprint-2026-05-28]] — package/module skeleton blueprint와 sample-portfolio 격리에서 나온 글감.
|
||
- [[raw/blog-topics/clean-architecture-boundary-enforcement-2026-05-28]] — Gradle/ArchUnit 경계 검증에서 나온 글감.
|
||
- [[raw/blog-topics/post-implementation-knowledge-capture-workflow-2026-05-28]] — 구현 후 Wiki capture workflow에서 나온 글감.
|
||
|
||
### 31.6 파생 wiki 문서
|
||
|
||
- canonical 검증 사실:
|
||
- [[ca-tmpl]] — 16 의사결정 project doc hub (named hub, sibling `wiki/projects/ca-tmpl/` 폴더의 MOC)
|
||
- 16 개별 project docs: `wiki/projects/ca-tmpl/{topic}.md`
|
||
- 관련 일반 개념:
|
||
- 16 wiki/concepts/{topic}.md (Core 6 + Cross-cutting 10) — [[llm-wiki]] 참조
|
||
- 포트폴리오: (Phase D 후속)
|
||
- 블로그 글: (Phase D 후속)
|
||
|
||
## 32. Phase 5 Additional Evidence Raws (2026-05-27)
|
||
|
||
> Phase 5B 외부 근거 추가 보강. 25개 신규 raw 파일 (`raw/official-docs/` 하위) 을 owning decision/branch-note 별로 매핑. 각 raw 는 frontmatter `related_projects: [ca-skeleton]` 보유. 본 섹션은 §29 (Phase 1~4 162개 누적) 이후 추가된 evidence index.
|
||
>
|
||
> **출처 신뢰도 (CLAUDE.md §5 정합)**: 본 섹션의 모든 raw 는 `source_type: official-doc` (RFC, IANA registry, vendor 공식 reference, OWASP cheat sheet, K8s 공식 문서 등). company-tech-blog 는 포함되지 않음.
|
||
>
|
||
> **사용 경계**: 본 섹션은 raw evidence 의 cluster-level index 역할. 각 raw 의 Claim ID / Usage Boundary 는 raw 파일 자체의 `## Claims Extracted` 섹션에서 확인. 본 project-note 는 raw 를 owning decision/branch 에 매핑할 뿐이며, raw 의 verbatim claim 을 그대로 best practice 로 단정하지 않음.
|
||
|
||
### 32.1 Architecture / Boundary (3 raw)
|
||
|
||
| raw | 채택 위치 (decision / branch) | 사용 근거 |
|
||
| --- | --- | --- |
|
||
| [[raw/official-docs/arch-clean-architecture-uncle-bob]] | `feature-repository-access-permission-contract`, `feature-architecture-enforcement-rules`, `feature-skeleton-package-blueprint-contract` | Clean Architecture 의 Dependency Rule (외층 → 내층 only) 이 ca-skeleton 의 module dependency rule (§20) 의 1차 reference standard |
|
||
| [[raw/official-docs/arch-hexagonal-cockburn]] | `feature-application-port-usecase-contract`, `feature-repository-access-permission-contract`, `feature-architecture-enforcement-rules` | Cockburn 의 Ports & Adapters 가 inbound port (`*UseCase`) / outbound port (`*Port`) 분리 (§25 port naming default decision) 의 reference standard |
|
||
| [[raw/official-docs/cqrs-fowler-bliki]] | [[raw/branch-notes/feature-repository-access-permission-contract]] (D10 capability matrix), `feature-domain-modeling-guardrails` | Fowler 의 CQRS 분류가 command/query use case 분리 (§19 Use Case / Port Contract) 와 `READ_REPOSITORY` / `WRITE_REPOSITORY` capability 분리 (§10) 의 reference. 단, ca-skeleton 은 event sourcing 미채택. |
|
||
|
||
### 32.2 Repository / Persistence / Transaction (3 raw)
|
||
|
||
| raw | 채택 위치 | 사용 근거 |
|
||
| --- | --- | --- |
|
||
| [[raw/official-docs/microservices-io-transactional-outbox]] | [[raw/branch-notes/feature-repository-access-permission-contract]] (D7 outbox capability), `feature-domain-event-outbox-contract` | microservices.io 의 Transactional Outbox pattern 정의가 ca-skeleton 의 outbox SKIP LOCKED polling 결정 (§14, §29 Topic 3) 의 reference (단, microservices.io 는 패턴 카탈로그이며 polling vs CDC 트레이드오프는 별도 source). |
|
||
| [[raw/official-docs/archunit-user-guide]] | [[raw/branch-notes/feature-repository-access-permission-contract]] (D8 enforcement), `feature-architecture-enforcement-rules` | ArchUnit 공식 user guide 가 `@UseCaseRepositoryAccess` annotation-based rule 의 enforcement 메커니즘 (§21 Capability Registry) 근거. annotation processor alternative, runtime AOP forbidden 정합. |
|
||
| [[raw/official-docs/spring-tx-management-reference]] | [[raw/branch-notes/feature-repository-access-permission-contract]] (D4 transaction boundary), `feature-transaction-concurrency-contract`, `feature-application-port-usecase-contract` | Spring 공식 Transaction Management reference 가 `@Transactional` propagation/isolation 의 표준 정의. ca-skeleton 은 `@Transactional` 직접 import 금지 + `TransactionPort` 추상화 (§25 transaction boundary default) 채택 — Spring 표준을 reference 로 두되 application layer 격리. |
|
||
|
||
### 32.3 Outbound HTTP / Resilience (3 raw)
|
||
|
||
| raw | 채택 위치 | 사용 근거 |
|
||
| --- | --- | --- |
|
||
| [[raw/official-docs/resilience4j-micrometer-module]] | [[raw/branch-notes/feature-outbound-http-client-baseline]] (D4 metric), `feature-metrics-alerting-contract` | Resilience4j 공식 Micrometer 통합 모듈이 retry/circuit-breaker metric 이름·tag (§29 Group G-A metric) 의 표준 reference. ca-skeleton metric registry (§21 Metrics Registry) 의 retry/CB metric 정의 근거. |
|
||
| [[raw/official-docs/spring-restclient-builder-reference]] | [[raw/branch-notes/feature-outbound-http-client-baseline]] (D5/D7 mechanism) | Spring 6.1+ RestClient 공식 builder API reference. ca-skeleton 의 RestClient 기본값 (§11 Outbound HTTP, §29 Group G-C) 의 직접 source. RestTemplate maintenance-only 정책과 정합. |
|
||
| [[raw/official-docs/spring-smartlifecycle-reference]] | [[raw/branch-notes/feature-outbound-http-client-baseline]] (D8 graceful shutdown), `feature-runtime-health-lifecycle-contract` | Spring `SmartLifecycle` 인터페이스 reference. ca-skeleton 의 graceful shutdown 20s+5s+35s (§29 Group G-D Container) 와 outbound HTTP shutdown retry suppression (§28 Numeric conflicts) 의 phase 분리 메커니즘 근거. |
|
||
|
||
### 32.4 API Contract / Schema / Versioning (4 raw)
|
||
|
||
| raw | 채택 위치 | 사용 근거 |
|
||
| --- | --- | --- |
|
||
| [[raw/official-docs/rfc9110-http-semantics]] | [[raw/branch-notes/feature-outbound-http-client-baseline]] (D6 status code), [[raw/branch-notes/feature-api-contract-baseline]] (D8/D9 method/status) | RFC 9110 (HTTP Semantics, 2022) 이 status code 의미·method 정의·conditional request 의 정식 reference. ca-skeleton 의 error envelope HTTP status 매핑 (§3, §6) 과 outbound HTTP 분류 (§11) 의 standard. |
|
||
| [[raw/official-docs/openapi-spec-3-1-0]] | [[raw/branch-notes/feature-api-contract-baseline]] (D10), `feature-contract-verification-test-suite`, `feature-api-compatibility-deprecation-contract` | OpenAPI 3.1.0 공식 spec (JSON Schema 2020-12 정합). ca-skeleton 의 OpenAPI snapshot drift test (§25 OpenAPI drift default, §29 Group G-G) 의 standard reference. |
|
||
| [[raw/official-docs/google-aip-185-resource-versioning]] | [[raw/branch-notes/feature-api-contract-baseline]] (D2/D6 versioning) | Google AIP-185 (Resource Versioning) 가 URI path version (`/v1`) vs header version trade-off 의 reference. ca-skeleton 의 `/v1` URI prefix default (§25 API versioning) 결정 근거 — Google AIP 는 외부 공식 reference 이지만 Google API 정책이라 ca-skeleton 이 100% 따라가지는 않음. |
|
||
| [[raw/official-docs/jsonapi-pagination-format]] | [[raw/branch-notes/feature-api-contract-baseline]] (D7 pagination) | JSON:API 공식 pagination format (`page[number]`, `page[size]`, `links.{first,last,next,prev}`). ca-skeleton 의 envelope `meta.page` (§21 Response Envelope) 의 reference 대안 1종 — ca-skeleton 은 자체 envelope 채택, JSON:API 는 비교 대안 (§29 Topic 4 API Error Envelope) 으로 보존. |
|
||
|
||
### 32.5 Schema / Serialization (2 raw)
|
||
|
||
| raw | 채택 위치 | 사용 근거 |
|
||
| --- | --- | --- |
|
||
| [[raw/official-docs/rfc3339-datetime-utc]] | [[raw/branch-notes/feature-runtime-health-lifecycle-contract]] (D12 timezone), `feature-schema-serialization-contract` | RFC 3339 (Date and Time on the Internet) 이 ISO-8601 의 IETF profile. ca-skeleton 의 ISO-8601 offset UTC default (§16, §29 Group G-F Schema) 의 직접 reference. |
|
||
| [[raw/official-docs/iana-media-types-registry]] | [[raw/branch-notes/feature-file-resource-handling-contract]] (D7 content-type allowlist), `feature-schema-serialization-contract` | IANA Media Types Registry 가 `Content-Type` allowlist (§18 File / Resource Handling, §29 Group G-J File) 의 SSOT. ca-skeleton 의 6종 content-type allowlist 의 reference. |
|
||
|
||
### 32.6 File / Resource Handling (5 raw)
|
||
|
||
| raw | 채택 위치 | 사용 근거 |
|
||
| --- | --- | --- |
|
||
| [[raw/official-docs/spring-boot-multipart-reference]] | [[raw/branch-notes/feature-file-resource-handling-contract]] (D3/D4 mechanism) | Spring Boot Multipart 공식 reference (`spring.servlet.multipart.max-file-size` 등). ca-skeleton 의 3-layer size limit (Spring 10MB / global 12MB / gateway 20MB, §29 Numeric conflicts) 중 Spring layer 의 직접 source. |
|
||
| [[raw/official-docs/nginx-client-max-body-size]] | [[raw/branch-notes/feature-file-resource-handling-contract]] (D4 gateway layer) | nginx `client_max_body_size` 공식 reference. ca-skeleton 3-layer size limit 의 gateway layer (20MB) 의 source. |
|
||
| [[raw/official-docs/owasp-file-upload-cheat-sheet]] | [[raw/branch-notes/feature-file-resource-handling-contract]] (D5 security), `feature-security-operational-baseline` | OWASP File Upload Cheat Sheet 가 file upload 보안 baseline (content-type validation, size limit, path validation, antivirus scanning) 의 SSOT. ca-skeleton 의 antivirus gateway default (§29 Missing Area Closures) 와 content-type allowlist 의 보안 reference. |
|
||
| [[raw/official-docs/owasp-path-traversal]] | `feature-file-resource-handling-contract` | OWASP Path Traversal cheat sheet 가 download/serve 경로 traversal 방지 (§18 File / Resource Handling - "path traversal 방지") 의 source. |
|
||
| [[raw/official-docs/jdk-files-createtempfile]] | [[raw/branch-notes/feature-file-resource-handling-contract]] (D6 temp file) | JDK `Files.createTempFile` Javadoc reference. ca-skeleton 의 temp file 1h orphan cleanup (§29 Group G-J File) 과 secure temp file creation 의 표준 API source. |
|
||
| [[raw/official-docs/spring-streaming-response-body]] | [[raw/branch-notes/feature-file-resource-handling-contract]] (D8 download streaming) | Spring `StreamingResponseBody` 공식 reference. ca-skeleton 의 download streaming failure 분류 (§18 File / Resource Handling - "download streaming failure") 의 mechanism source. |
|
||
|
||
### 32.7 Runtime / Health / Lifecycle (2 raw)
|
||
|
||
| raw | 채택 위치 | 사용 근거 |
|
||
| --- | --- | --- |
|
||
| [[raw/official-docs/k8s-configure-probes-task-page]] | [[raw/branch-notes/feature-runtime-health-lifecycle-contract]] (D5 probe config / D11 startup probe) | K8s 공식 "Configure Liveness, Readiness and Startup Probes" task page. ca-skeleton 의 3-probe 분리 (§29 Group G-D Runtime health) 와 readiness/liveness/startup separation 의 SSOT. |
|
||
| [[raw/official-docs/k8s-pod-lifecycle-probes-concept]] | [[raw/branch-notes/feature-runtime-health-lifecycle-contract]] (D7 probe semantics) | K8s 공식 Pod Lifecycle concept page (probe lifecycle, restart policy 등). ca-skeleton 의 readiness gated migration (§28 Critical Defaults - migration runner) 와 graceful shutdown ↔ probe interaction 의 conceptual reference. |
|
||
|
||
### 32.8 Operational Runbook / Alerting (3 raw)
|
||
|
||
| raw | 채택 위치 | 사용 근거 |
|
||
| --- | --- | --- |
|
||
| [[raw/official-docs/lychee-link-checker]] | [[raw/branch-notes/feature-operational-runbook-contract]] (D4 link-check tool) | lychee (Rust 기반 markdown link checker) 공식 doc. ca-skeleton 의 markdown-link-check 또는 lychee 를 통한 runbook link drift 방지 (§29 Self-Contradiction Closures - "runbook link required but unverifiable") 의 tool option. |
|
||
| [[raw/official-docs/prometheus-alertmanager-silences]] | [[raw/branch-notes/feature-operational-runbook-contract]] (D6 alert silencing) | Prometheus Alertmanager silences 공식 doc. ca-skeleton 의 alert dedup 5분 + P1 2분 noise 억제 (§28 Numeric conflicts) 의 silence/inhibition mechanism reference. |
|
||
| [[raw/official-docs/google-sre-workbook-on-call-monitoring]] | [[raw/branch-notes/feature-operational-runbook-contract]] (D2 monitoring philosophy / D10 on-call) | Google SRE Workbook "Monitoring" + "Being On-Call" chapters. ca-skeleton 의 P1/P2/P3 severity (§18 Metrics / Alerting) 와 runbook 7-section 표준 (§28 Phase D2 closures) 의 conceptual reference. company-tech-blog 아님 (Google 공식 book chapter, O'Reilly publication 형식이지만 Google SRE 가 저자). |
|
||
|
||
---
|
||
|
||
## 33. 아키텍처 검토 체크리스트
|
||
|
||
- [x] 한 줄 요약 + 현재 상태 + 나의 역할 채워짐 (본문 도입부)
|
||
- [x] 측정 가능한 성공 기준 — §1 목표 + §28 Phase 매트릭스 ✓
|
||
- [x] 아키텍처 다이어그램 1개 이상 첨부 (§30-1 모듈 의존성, §30-2 런타임 토폴로지) ✓ (Mermaid; drawio 이관은 Phase C2 시 검토)
|
||
- [x] 다이어그램의 모든 컴포넌트가 라벨 + 역할 + 기술 스택 표기 ✓
|
||
- [x] 다이어그램의 모든 화살표가 프로토콜·데이터 종류 라벨링 ✓
|
||
- [x] 외부 시스템이 점선 또는 색으로 시각적 구분 ✓ (`classDef external`)
|
||
- [x] 범례(Legend) 다이어그램에 포함 ✓ (§30-2 끝 범례 블록)
|
||
- [x] 신뢰 경계 / 네트워크 경계 표시 ✓ (subgraph TB_*)
|
||
- [x] 시퀀스 다이어그램 ≥1 (Mermaid) — happy path + error path (§30.1 Request flow, §30.2 Outbox, §30.3 Tenant) — 총 3개 ✓
|
||
- [x] Cluster 섹션의 root/feature branch 목록 채워짐 (§31.1) ✓
|
||
- [x] 마지막 architecture review 날짜 frontmatter `architecture_review:` 에 기록 — 2026-05-26 ✓
|
||
- [x] Phase 5B evidence raws (25 raw, §32) cluster-level index 작성 ✓
|
||
|
||
## 35. Implementation Coverage Checklist
|
||
|
||
본 § 는 ca-skeleton 의 *전체 영역 × 구현 진척* 트래커. 신규 영역 발견 시 본 § 에 row 추가 → branch 신설 → 결정 박음 → 코드 작성 순서. 상태 변경 시 본 § + 해당 branch 의 `status_label` 동시 갱신.
|
||
|
||
### 상태 표기
|
||
|
||
| 아이콘 | 의미 | 등급 (CLAUDE.md §6) |
|
||
|---|---|---|
|
||
| `[ ]` | 미시작 / scaffolding | `planned` |
|
||
| `[~]` | 결정 박힘, 코드 없음 | `documented-only` |
|
||
| `[*]` | 코드 일부 작성 | `actually-implemented` (partial) |
|
||
| `[x]` | 코드 완성 + 로컬 검증 | `locally-verified` |
|
||
| `[X]` | 운영 검증 | `prod-verified` |
|
||
| `(없음)` | branch 미존재 (신설 후보) | — |
|
||
|
||
### A. 외부 통신 / API 계약 영역
|
||
|
||
- `[~]` HTTP 표면 baseline (24 결정 — envelope / status / pagination / URL naming / PATCH / conditional / cache / LRO / bulk) — `feature-api-contract-baseline` (D=24, sl=in-progress)
|
||
- `[~]` Resource ID format (ULID 26-char Crockford base32) — `feature-resource-identifier-contract` (D=19, sl=in-progress, §구현 가이드 §1~§8 코드 skeleton ready)
|
||
- `[ ]` Webhook outbound (signature / replay / retry / observability) — `feature-webhook-outbound-contract` (D=0, scaffolding)
|
||
- `[ ]` Streaming response (SSE / WebSocket / long-poll / chunked — 1차 결정: 지원 여부) — `feature-streaming-response-contract` (D=0, scaffolding)
|
||
- `[~]` API versioning + Sunset / Deprecation (`/v1` URI prefix → 향후 `/v2`) — `feature-api-compatibility-deprecation-contract` (D=8, sl=in-progress)
|
||
- `[~]` Outbound HTTP resilience (Resilience4j circuit breaker / retry / timeout) — `feature-outbound-http-client-baseline` (D=11, sl=in-progress)
|
||
- `[~]` Error envelope + 코드 registry (`error-codes.yaml` SSOT) — `feature-operational-error-observability-foundation` (D=12, sl=in-progress)
|
||
- `[~]` Idempotency-Key + Rate limit (HTTP header / TTL / fingerprint) — `feature-rate-limit-idempotency-contract` (D=10, sl=in-progress)
|
||
- `[~]` Contract verification test suite (OpenAPI drift detection) — `feature-contract-verification-test-suite` (D=9, sl=in-progress)
|
||
- `[~]` Schema / Serialization (Jackson naming / date-time / decimal) — `feature-schema-serialization-contract` (D=7, sl=in-progress)
|
||
- `(없음)` Documentation generation / API docs publishing (OpenAPI → Swagger UI / Redoc / release artifact 묶기) — F 미래 후보 (사용자 항목 #8)
|
||
|
||
### 영속성 영역
|
||
|
||
- `[~]` Persistence failure baseline (optimistic lock / conflict 분류) — `feature-persistence-failure-baseline` (D=8, sl=in-progress)
|
||
- `[x]` Application port + use case contract (transaction 경계 + port 추상화) — `feature-application-port-usecase-contract` (D=14, sl=**actually-implemented**, AI=5, LV=2)
|
||
- `[~]` Repository capability annotation (`@UseCaseRepositoryAccess`) — `feature-repository-access-permission-contract` (D=11, sl=in-progress)
|
||
- `[~]` Transaction / Concurrency contract — `feature-transaction-concurrency-contract` (D=7, sl=in-progress)
|
||
- `[~]` Migration runner readiness gate (Flyway startup) — `feature-migration-startup-contract` (D=8, sl=in-progress)
|
||
- `[~]` Multi-tenancy isolation (tenant context + DB scope) — `feature-tenant-context-policy` (D=10, sl=in-progress)
|
||
- `[~]` Data retention / Privacy / GDPR (DSR / PII / 감사 log) — `feature-data-retention-privacy-contract` (D=12, sl=in-progress)
|
||
- `[~]` File / Resource handling (upload / download / S3) — `feature-file-resource-handling-contract` (D=12, sl=in-progress)
|
||
- `[~]` Domain event + Transactional Outbox — `feature-domain-event-outbox-contract` (D=10, sl=in-progress)
|
||
- `[~]` Cache consistency (Redis adapter + invalidation) — `feature-cache-consistency-contract` (D=9, sl=in-progress)
|
||
- `(없음)` Persistence auditing (CreatedBy / UpdatedBy 도메인 오염 차단) — **신규 branch 권고: `feature-persistence-auditing-contract`**
|
||
- `(없음)` DB connection pool 운영 안정성 (HikariCP pool size / timeout / leak detection / slow query) — **신규 branch 권고 (priority #4): `feature-database-connection-pool-contract`**
|
||
- `(없음)` Backup / restore / DR (PITR / schema rollback policy / restore drill) — F 미래 후보 (사용자 항목 #6)
|
||
|
||
### 배포 영역
|
||
|
||
- `[~]` Background job + Async boundary (scheduler / ShedLock) — `feature-background-job-async-contract` (D=12, sl=in-progress)
|
||
- `[~]` Runtime health / Lifecycle (actuator / probe / readiness gate) — `feature-runtime-health-lifecycle-contract` (D=13, sl=in-progress)
|
||
- `[~]` Management actuator security (port 분리 / 인증) — `feature-management-actuator-security-contract` (D=8, sl=in-progress)
|
||
- `[~]` Metrics / Alerting (Micrometer + P1/P2/P3 severity) — `feature-metrics-alerting-contract` (D=10, sl=in-progress)
|
||
- `[~]` Distributed tracing (W3C trace context + Micrometer Tracing) — `feature-distributed-tracing-contract` (D=12, sl=in-progress)
|
||
- `[~]` Log management (MDC / scrubber / SLF4J 2.x / profile별 console encoder 포맷) — `feature-log-management-contract` (D=10, sl=in-progress)
|
||
- `[~]` Container runtime (Temurin slim / JVM ergonomics / non-root) — `feature-container-runtime-contract` (D=5, sl=in-progress)
|
||
- `[~]` Build / Release / Supply chain (Gradle / SBOM / Cosign) — `feature-build-release-supply-chain-contract` (D=13, sl=in-progress)
|
||
- `[~]` Operational runbook (P1/P2/P3 runbook section 표준) — `feature-operational-runbook-contract` (D=10, sl=in-progress)
|
||
- `[~]` Developer experience (bootstrap command / IDE / docker-compose) — `feature-developer-experience-contract` (D=10, sl=in-progress)
|
||
- `[~]` Secrets / Config source (env / secret manager) — `feature-secrets-config-source-contract` (D=10, sl=in-progress)
|
||
- `[~]` Env-driven runtime configuration (`APP_*` prefix / feature flag) — `feature-env-driven-runtime-configuration` (D=10, sl=in-progress)
|
||
- `[~]` CI quality gates (test/lint/coverage thresholds) — `feature-ci-quality-gates-contract` (D=9, sl=in-progress)
|
||
- `(없음)` Static analysis / code quality baseline (Checkstyle / Spotless / ErrorProne / SpotBugs / PMD / Sonar) — **신규 branch 권고 (priority #2): `feature-static-analysis-quality-contract`** — ci-quality-gates 와 별개 (그 branch 는 *threshold*, 본 branch 는 *tool 선택 + 룰셋*)
|
||
- `[~]` Dependency / vulnerability management (CVE scan(Trivy) / CVSS 차단 임계값 / KEV override / suppression governance / Renovate-Dependabot 보안 update / license scan / transitive audit) — [[raw/branch-notes/feature-dependency-vulnerability-management-contract]] (2026-06-15 scaffold + D1~D10, sl=in-progress, 전부 `planned`) — build-release-supply-chain 과 별개 (그 branch 는 *artifact / SBOM / locking*, 본 branch 는 *vuln 정책 + 운영 중 upgrade*). §25 SSOT Owner Map "Dependency vulnerability policy" row 참조
|
||
- `(없음)` Performance / load baseline (k6 / Gatling / JMeter smoke load test / latency budget / throughput budget / N+1 query 감지) — F 미래 후보 (사용자 항목 #7)
|
||
- `(없음)` Local dev data lifecycle (seed data / test data reset / docker-compose volume reset / local DB migration 재실행) — F 미래 후보 (사용자 항목 #9). DX 와 인접하나 별도 row
|
||
|
||
### 보안·거버넌스 영역
|
||
|
||
- `[*]` Boundary validation + Mapping (B1~B9 — Jackson / PATCH / Bean Validation / Polymorphic / Virtual thread / ACL / Bulk / ArchUnit cross-cite) — `feature-boundary-validation-mapping-contract` (D=15, sl=in-progress, **AI=15, LV=2**)
|
||
- `[~]` Business rule validation (domain invariant) — `feature-business-rule-validation-contract` (D=9, sl=in-progress)
|
||
- `[~]` Security operational baseline (CORS / SecureRandom / header suppression / API key / session) — `feature-security-operational-baseline` (D=11, sl=in-progress)
|
||
- `[~]` Domain modeling guardrails (aggregate boundary / value object) — `feature-domain-modeling-guardrails` (D=8, sl=in-progress)
|
||
- `[*]` Domain feature slice + onboarding template — `feature-domain-feature-onboarding-contract` (D=7, sl=in-progress, AI=2, LV=2)
|
||
- `[x]` Skeleton package blueprint (Gradle multi-module + Clean Architecture) — `feature-skeleton-package-blueprint-contract` (D=10, sl=**locally-verified**, AI=3, LV=8)
|
||
- `[x]` Architecture enforcement rules (ArchUnit suite SSOT) — `feature-architecture-enforcement-rules` (D=12, sl=**review**, AI=11, LV=11)
|
||
- `[~]` Integration adapter templates — `feature-integration-adapter-templates` (D=9, sl=in-progress)
|
||
- `[~]` Sample domain fixture (sample-portfolio) — `feature-sample-domain-contract-fixture` (D=6, sl=in-progress)
|
||
- `[*]` Sample removal / Project adoption — `feature-sample-removal-adoption-contract` (D=6, sl=in-progress, AI=2, LV=2)
|
||
- `[~]` Contract registry governance (yaml SSOT) — `feature-contract-registry-governance` (D=7, sl=in-progress)
|
||
- `[*]` Implementation readiness scorecard — `feature-implementation-readiness-scorecard` (D=6, sl=in-progress, AI=2, LV=2)
|
||
- `[~]` Test taxonomy + fixture (unit/contract/architecture/integration) — `feature-test-taxonomy-fixture-contract` (D=8, sl=in-progress)
|
||
- `[~]` **Tenant context policy + multi-tenancy model** — [[raw/branch-notes/feature-tenant-context-policy]] (in-progress). **활성화 트리거**: [[raw/branch-notes/feature-resource-identifier-contract]] 의 D13 (ID 내 tenant 인코딩 거부 — *형식적 위치만* 결정) + D17 의 5번째 ArchUnit rule (`no_find_by_id_without_tenant`) 이 본 branch 결정 후 활성화 대기 중. **현재 branch out-of-scope** ("실제 SaaS tenant model 구현") 가 *모델 확장이 필요할 때* 갱신 필요 (`TenantId` VO / `tenant` 테이블 / FK / `findByIdAndTenant` repository contract / auth → tenant 해석). 단순 single-tenant skeleton 이면 *지원 안함* 결정으로 close 가능
|
||
- `(없음)` Template instantiation contract (group / artifact / basePackage / root package rename / README 치환 / sample-off 적용 검증) — **신규 branch 권고 (priority #1): `feature-template-instantiation-contract`** — developer-experience + sample-removal-adoption 와 인접하나 *clone 후 검증 절차* 가 독립 row 로 약함
|
||
- `(없음)` AuthN / AuthZ product API baseline (JWT / OAuth2 resource server / RBAC / ABAC / permission matrix / endpoint authorization annotation) — **신규 branch 권고 (priority #5): `feature-authentication-authorization-contract`** — `feature-security-operational-baseline` 와 별개 (그 branch 는 CORS / SecureRandom / header suppression 중심, 본 branch 는 *product API 인증/인가*)
|
||
|
||
### E. 신규 branch 권고 (우선순위 9개)
|
||
|
||
사용자 18항 + 9 보강 분석 결과의 통합 우선순위. 박을 시점은 본 branch 가 *현재 결정에 영향* 을 주거나 *코드 작성 중 막힐* 때.
|
||
|
||
| 우선순위 | branch (예정) | 영역 | 박을 시점 | 비고 |
|
||
|---|---|---|---|---|
|
||
| 1 | `feature-template-instantiation-contract` | D | 사용자 첫 template clone 시점 | group/artifact/basePackage rename + sample-off 자동화 |
|
||
| 2 | `feature-static-analysis-quality-contract` | C | 코드 작성 본격화 직전 | Checkstyle/Spotless/ErrorProne/SpotBugs/PMD/Sonar tool 선택 + 룰셋 |
|
||
| 3 | `feature-dependency-vulnerability-management-contract` | C | CI 셋업 시점 | Dependabot/Renovate + CVE scan + license scan + 운영 upgrade 정책 |
|
||
| 4 | `feature-database-connection-pool-contract` | B | persistence 코드 작성 시점 | HikariCP pool size / timeout / leak detection / slow query |
|
||
| 5 | `feature-authentication-authorization-contract` | D | 도메인이 사용자 인증 요구하는 시점 | JWT/OAuth2 RS + RBAC/ABAC + endpoint auth annotation |
|
||
| 6 | `feature-application-query-bypass-contract` | B/D | query endpoint 첫 작성 시점 | CQRS Q 경로 — use case bypass 허용 여부 (architecture-blocking). **✅ 2026-06-05 scaffold + 구현 완료 (locally-verified)**: branch-note + D1 purity-guardrail ArchUnit rule(`query_ports_do_not_leak_domain_jpa_or_web_types`, generic type argument 검사) + sample-portfolio projection demo + D3/D4/D5 코드화. D2(separate read store) documented-only |
|
||
| 7 | `feature-runtime-context-propagation-contract` | B/D | virtual thread 활성화 + 도메인 context 전파 요구 시점 | Java 21 Scoped Values — boundary B6 의 도메인 확장 |
|
||
| 8 | `feature-persistence-auditing-contract` | B | entity audit 컬럼 (CreatedBy/UpdatedBy) 도입 시점 | 도메인 오염 차단 메커니즘 (`AuditPort` + adapter 가로채기) |
|
||
| 9 | `feature-distributed-lock-contract` | B/C | multi-instance prod 도입 시점 | Redisson / DB advisory lock + 트랜잭션 commit 정합. **✅ 2026-06-12 branch-note 생성 (D1~D8 박힘 — JdbcLockRegistry default + xact advisory 보조 + ShedLock/session-advisory 배제, 코드 전부 `planned`)** — [[raw/branch-notes/feature-distributed-lock-contract]] |
|
||
|
||
### 운영 요구 시 신설)
|
||
|
||
운영 단계에서 *필수가 되지만* skeleton 1차 범위에서는 deferred. 도메인이 요구하거나 prod 운영 시점에 신설 의무.
|
||
|
||
- `(없음)` Backup / restore / DR (PITR / schema rollback / restore drill) — 운영 앱 진입 시 필수 (사용자 항목 #6)
|
||
- `(없음)` Performance / load baseline (k6 / Gatling / JMeter / latency budget / N+1 detection) — prod 트래픽 수반 시 필수 (사용자 항목 #7)
|
||
- `(없음)` Documentation generation / API docs publishing (Swagger UI / Redoc / release artifact 묶기) — API 외부 공개 시 필수 (사용자 항목 #8)
|
||
- `(없음)` Local dev data lifecycle (seed / reset / docker volume / migration 재실행) — DX 강화 시점 (사용자 항목 #9). DX 와 인접
|
||
- `(없음)` Time / Clock 주입 (`Clock` port, `Instant.now()` 차단 ArchUnit rule) — domain 시간 의존 시점
|
||
- `(없음)` Locale / i18n (error message 다국어, `MessageSource` 추상화) — 다국어 서비스 시점
|
||
- `(없음)` Money / Currency / BigDecimal 정밀도 (금융 도메인 패턴) — 금융 도메인 시점
|
||
- `(없음)` Search abstraction (Elasticsearch / PostgreSQL FTS port) — 검색 도입 시점
|
||
- `(없음)` Email / SMS / Notification outbound (adapter 표면) — 알림 도입 시점
|
||
- `(없음)` Saga / Process Manager (multi-step 분산 트랜잭션) — 복합 도메인 시점
|
||
- `(없음)` Soft delete vs hard delete policy (data-retention 의 확장) — soft-delete 도입 시점
|
||
|
||
### 사용 절차
|
||
|
||
1. **상태 확인**: 코딩 시작 전 본 § grep 으로 *해당 영역 branch 상태* 파악.
|
||
2. **결정 부족 시**: 해당 branch 의 §결정 사항 / §Decision Evidence Map drain 우선.
|
||
3. **코드 시작 후 갱신**: `[ ]` → `[~]` → `[*]` → `[x]` → `[X]` 순서로 본 § + branch `status_label` 동시 갱신.
|
||
4. **신규 영역 발견 시**: §31.1 Cluster Branches list + §25 SSOT Owner Map + 본 § 에 row 추가 후 branch 신설 (§34 Stack Commitment 정합 의무).
|
||
5. **gap 식별**: 정기적 (주 1회 권장) 본 § scan 으로 *`[ ]` 가 많은 영역* / *`(없음)` 항목* 검토 → 코딩 우선순위 조정.
|
||
6. **상태 grade 의 evidence 근거**: `[*]`/`[x]`/`[X]` 마킹 시 branch 의 §완료 후 정리 / Closure 섹션에 해당 grade 의 *실제 코드 reference* (PR / commit / test 파일 경로) 명시 의무.
|
||
|
||
### 현재 우선순위 (진행 가능 순서)
|
||
|
||
**현재 분포 요약** (46 ca-skeleton branches + 9 신규 권고 + 11 미래 후보):
|
||
|
||
- `[x]` 3개 (locally-verified 이상): `feature-skeleton-package-blueprint-contract`, `feature-architecture-enforcement-rules`, `feature-application-port-usecase-contract`
|
||
- `[*]` 4개 (partial implementation): `feature-boundary-validation-mapping-contract`, `feature-domain-feature-onboarding-contract`, `feature-sample-removal-adoption-contract`, `feature-implementation-readiness-scorecard`
|
||
- `[~]` 37개 (결정 박힘, 코드 없음): 대부분 — D-row 평균 9~12개
|
||
- `[ ]` 2개 (scaffolding only): `feature-webhook-outbound-contract`, `feature-streaming-response-contract`
|
||
- `(없음)` 8개 (신규 branch 권고, E 영역): template-instantiation / static-analysis / dependency-vulnerability / database-connection-pool / authn-authz / runtime-context / persistence-auditing / distributed-lock — (query-bypass 는 2026-06-05 scaffold+구현 완료로 제외, `[x]` locally-verified 로 승급)
|
||
- `(없음)` 11개 (미래 후보, F 영역): backup-restore / performance-load / docs-publishing / local-dev-data / clock-injection / i18n / money-decimal / search / notification / saga / soft-delete
|
||
|
||
**작업 흐름 권고**:
|
||
|
||
1. **`[~]` → `[*]` drain** — 코드 작성 단계로 진입. 우선순위:
|
||
- **(1순위) `feature-resource-identifier-contract`** — §구현 가이드 §1~§8 코드 skeleton ready, 즉시 코드 작성 가능
|
||
- **(2순위) `feature-api-contract-baseline`** — D=24 결정 모두 박힘. ArchUnit rule 작성 + envelope serializer
|
||
- **(3순위) `feature-operational-error-observability-foundation`** — error registry yaml SSOT (다수 branch 의 dependency)
|
||
- **(4순위) `feature-security-operational-baseline`** — CORS / SecureRandom / API key — security baseline
|
||
2. **`(없음)` E 영역 신규 branch scaffolding** — *코드 작성 *전에* 박아야 할 architecture-blocking 결정*:
|
||
- **template-instantiation** (priority 1) — project clone 시점에 즉시 필요
|
||
- **static-analysis-quality** (priority 2) — CI 셋업 시점
|
||
- **dependency-vulnerability** (priority 3) — CI 셋업 시점
|
||
- **database-connection-pool** (priority 4) — persistence 코드 작성 시점
|
||
- **authn-authz** (priority 5) — 도메인 사용자 인증 요구 시점
|
||
- 나머지 3개 (runtime-context, persistence-auditing, distributed-lock) 는 *코드 작성 중 부딪힐 때* scaffolding (query-bypass 는 2026-06-05 scaffold+구현 완료)
|
||
3. **`[ ]` → `[~]` 결정 drain** — scaffolding 2개 (webhook / streaming) 의 1차 결정 박기. 도메인 요구 등장 전까지 *미지원 default + ArchUnit 차단* 권고.
|
||
4. **`[*]` → `[x]` 승급** — 4개 partial 의 `planned` 잔존 row drain. 특히 boundary branch 의 ArchUnit rule 추가 작성.
|
||
5. **`[x]` → `[X]` 승급** — 3개 locally-verified 의 prod-deploy 후 운영 검증 (실제 서비스 배포 후).
|
||
6. **F 영역 미래 후보** — 운영 / 도메인 요구 등장 시점에 신설. skeleton 1차 범위 *밖*.
|
||
|
||
**Branch 작업 시점 의무**:
|
||
|
||
- 본 § 의 해당 row 상태 갱신
|
||
- 해당 branch 의 `status_label` frontmatter 갱신
|
||
- §완료 후 정리 / Closure 섹션에 evidence reference (PR / commit / test 경로) 추가
|
||
- §31.1 Cluster Branches list 의 description 갱신 (필요시)
|
||
- 신규 branch 신설 시 §31.1 + §25 SSOT Owner Map + 본 § row 동시 추가 (§34 Stack Commitment 정합 의무)
|
||
|
||
### Branch 작성 가이드 — 학습된 실패 모드 (4가지)
|
||
|
||
2026-06-01 [[raw/branch-notes/feature-resource-identifier-contract]] 4개 의문점 (sealed permits 모듈 경계 / D5 본문 vs §1/§2 와이어링 / D13 tenant 모델 부재 / D17 + §6 위임 vs 작성) 의 root cause 분석에서 식별된 *반복 발생 가능* 실패 모드. branch 작성 / 리뷰 시 본 § 항목별 self-check 권고.
|
||
|
||
| Failure mode | 발생 영역 | 위반된 룰 | Self-check 질문 |
|
||
|---|---|---|---|
|
||
| **F1. Cross-branch SSOT 미확인** | branch 가 *다른 branch 결정 영역* (예: 모듈 경계, ArchUnit suite 소유) 을 자기 §구현 가이드에 결정 | CLAUDE.md §11 *"본 branch 결정 범위 밖 cell 작성 금지"* + §15.5 **R3 OUT_OF_BRANCH_SCOPE** | 본 §구현 가이드 의 각 cell 이 sibling branch 의 결정 영역 (특히 `feature-skeleton-package-blueprint-contract` 의 모듈 경계, `feature-boundary-validation-mapping-contract` 의 ArchUnit suite, `feature-tenant-context-policy` 의 tenant 모델) 을 침범하지 않는가? |
|
||
| **F2. 본문 결정 ↔ §구현 가이드 self-inconsistency** | D-row 결정과 §구현 가이드 코드가 *서로 다른 패턴* 채택 (예: D5 본문 = static factory, §1/§2 = port + DI). **D-row 끼리도 self-inconsistency** (예: D2 charset = Crockford base32, I/L/O/U 제외 → 그러나 D19 fixture 값 `01HRGC7K2N4F6P8Q0R2S4T6U8V` 가 `U` 포함 → 자기 regex 통과 불가, 2026-06-01 self-catch) | §15.5 R1~R3 의 *암묵적 가정* — *근거 → 결정* 만 검사, *결정 → 구현* 미검사, *결정 → 결정* 도 미검사. wiki-workflow STOP self-check 12 도 동일 한계 | 각 D-row 결정의 *기술 선택* 이 §구현 가이드 코드 예시와 1:1 매칭되는가? (메커니즘 / 호출자 / 의존 방향 모두) **그리고 D-row 간 cross-reference 가 자기 자신의 charset/regex/format 통과하는가?** (예: charset 결정의 alphabet 이 fixture 값을 actually 통과) |
|
||
| **F3. 실제 코드 cross-check 부재** | spec 이 현재 코드에 *존재하지 않는* 의존성 (예: tenant 컬럼, ArchUnit rule 의 검사 대상 패키지) 을 가정 | 명시적 룰 없음 — *코드 cross-check 게이트 부재* | 본 branch §구현 가이드 의 *전제 사실* (테이블 / 컬럼 / 모듈 / 패키지) 이 `/home/donghyeon/workspace/ca-tmpl` 의 실제 코드에 존재하는가? 없으면 *마이그레이션 대상* 임을 본문에 명시했는가? |
|
||
| **F4. 위임 / 작성 모호** | branch 가 *결정 SSOT* 임을 명시했으나 §구현 가이드에 실제 작성 코드 잔존 (R3 부분 적용) | §15.5 R3 의 *부분 적용* | §구현 가이드 의 코드 skeleton 이 *reference (실제 호스팅 = sibling)* 인지 *실제 작성 (본 branch host)* 인지 본문에 명시했는가? reference 라면 sibling cite 와 *코드 위치 = sibling* 한 줄 추가했는가? |
|
||
|
||
위 4개 self-check 는 `/lint` 가 자동 catch 하지 못하는 정성적 영역 — branch 작성 / Sources 추가 / Decision 추가 / §구현 가이드 작성 시점에 *명시적으로* 검토.
|
||
|
||
장기적으로 `/lint` 검사 항목 (§15.5 *예정* 목록) 에 다음 4가지 추가 권고:
|
||
1. F1 — `..domain..` / `..adapter..` 등 package glob 이 sibling branch SSOT 모듈 경계 위반 여부 정적 grep
|
||
2. F2 — `## 결정 사항` 의 각 D-row 본문이 `## 구현 가이드` 의 §N 코드에서 referenced 됐는지 (`Trace: D<N>` 헤더 grep)
|
||
3. F3 — `## 구현 가이드` 의 코드 예시에 등장하는 클래스명 / 테이블명 / 패키지명이 실제 코드에 grep hit
|
||
4. F4 — `## 구현 가이드` 의 코드 skeleton 첫 줄에 `REFERENCE ONLY` 또는 `actual location: ` 라벨 grep — 미명시 시 본 branch 호스팅으로 간주
|
||
|
||
## 34. Stack Commitment
|
||
|
||
> **Legacy detail/reference.** stack 선택의 stable owner는 `## 6.1 Project Decision Registry / 안정 결정 레지스트리`의 `STACK-*` rows다. 아래 matrix는 버전·trade-off 설명을 보존한다.
|
||
|
||
ca-skeleton 은 *단일 stack 커밋* 을 채택합니다. 다중 DB / 다중 언어 / 다중 빌드 도구 가정은 모든 branch 의 결정 부담을 *theoretical UNSUPPORTED_IMPL_DECISION* 으로 부풀려 minimalist 정신과 충돌합니다. 본 § 가 stack SSOT — 모든 branch 는 본 § 를 *상속* 하며 stack 관련 결정을 자기 branch 에서 재선언하지 않습니다.
|
||
|
||
### Stack Matrix
|
||
|
||
| Layer | 선택 | 버전 | 비고 |
|
||
|---|---|---|---|
|
||
| Language | Java | 21 LTS | `java.util.UUID` v7 native 미지원 — ULID 선택 근거 (resource-identifier branch D1) |
|
||
| Framework | Spring Boot | 3.5.14 | starter web / data-jpa / validation 사용 |
|
||
| ORM | Hibernate ORM | 6.5.x (Spring Boot transitive) | `@JdbcTypeCode(SqlTypes.UUID)` native UUID |
|
||
| JSON | Jackson | 2.18.x (Spring Boot transitive) | custom serializer for value objects |
|
||
| DB | PostgreSQL | 16 | `uuid` native column type (16-byte binary). MySQL / Oracle / SQL Server *out of scope* |
|
||
| Migration | Flyway | (Spring Boot transitive) | startup runner, readiness gate (§25 default) |
|
||
| Build tool | Gradle | Groovy DSL | multi-module + `apply false` 패턴. `io.spring.dependency-management` 1.1.6 |
|
||
| Test framework | JUnit | 5 | Spring Boot starter 기본 |
|
||
| Architecture test | archunit-junit5 | 1.3.0 | D17 ArchUnit rule suite (resource-identifier branch + boundary branch) |
|
||
| Random source | `java.security.SecureRandom` | Java 21 | ULID generator + idempotency key + token generation 의 의무 random source |
|
||
|
||
### Cross-Branch 상속 패턴
|
||
|
||
각 branch 의 §결정 사항 / §Decision Evidence Map / §구현 가이드 가 stack 관련 결정 시 본 § 를 *reference* 만 하고 *재선언하지 않음*. 예시:
|
||
|
||
```text
|
||
✗ 잘못된 패턴 (재선언):
|
||
D10: DB primary key = BINARY(16) (MySQL InnoDB) + uuid native (PostgreSQL)
|
||
→ 다중 DB 가정 = theoretical UNSUPPORTED_IMPL_DECISION 발생
|
||
|
||
✓ 올바른 패턴 (상속):
|
||
D10: DB primary key = PostgreSQL 16 uuid native (project §34 Stack Commitment)
|
||
→ 단일 stack, 결정 명확, 미래 stack 변경 시 §34 한 곳만 갱신
|
||
```
|
||
|
||
### Stack 변경 절차
|
||
|
||
본 § 의 stack 변경은 *모든 branch 에 cascade* 됩니다. 변경 시:
|
||
|
||
1. 본 § Stack Matrix 갱신 (변경 row + 변경 사유 한 줄)
|
||
2. 영향 받는 sibling branch 식별 — `grep -rn "project §34" raw/branch-notes/feature-*.md`
|
||
3. 각 sibling branch 의 §Decision Evidence Map 의 `project-ssot` (§34) reference 영향 평가
|
||
4. 영향 큰 결정 (D1 ULID 같은 foundational) 은 branch 의 §결정 사항 재평가 + UNSUPPORTED_IMPL_DECISION 재평가
|
||
|
||
### Out of Stack (명시적 거부)
|
||
|
||
본 stack commit 은 다음 *대안* 들을 명시적으로 거부:
|
||
|
||
- **DB**: MySQL / Oracle / MariaDB / SQL Server — PostgreSQL 16 단일
|
||
- **Language**: Kotlin / Scala / Groovy (응용 코드) — Java 21 단일 (Gradle Groovy DSL 은 빌드 도구 한정)
|
||
- **Framework**: Micronaut / Quarkus / Helidon — Spring Boot 3.5.14 단일
|
||
- **Build tool**: Maven / Bazel — Gradle Groovy DSL 단일
|
||
- **Test framework**: TestNG / Spock — JUnit 5 단일
|
||
|
||
도메인이 위 alternative 를 요구할 경우 본 § 를 갱신 (cascade) 또는 별도 project-fork.
|