Files
llm-wiki/raw/branch-notes/feature-business-rule-validation-contract.md
T

36 KiB
Raw Blame History

title, source_type, status, branch, parent_branch, related_projects, governing_docs, tags, created, target_merge, status_label, id, kind, project, work_item, inherits, refines, overrides, depends_on, contract_packet, contract_packet_sha256
title source_type status branch parent_branch related_projects governing_docs tags created target_merge status_label id kind project work_item inherits refines overrides depends_on contract_packet contract_packet_sha256
branch / feature-business-rule-validation-contract branch-note raw feature-business-rule-validation-contract
ca-skeleton
wiki/projects/ca-tmpl/clean-architecture-package-layout
wiki/projects/ca-tmpl/api-error-envelope-design
branch
ca-skeleton
validation
business-rule
domain
2026-05-22 in-progress BR-CA-SKELETON-OPERATIONAL-CONTRACT-037 project-work-item ca-skeleton-operational-contract WI-CA-SKELETON-OPERATIONAL-CONTRACT-037
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MAPPING-001@1
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-ERROR-ENVELOPE-001@1
1 9fe64ae8128001379c77396ee11cfe7afe9196c837a5de4b2500c0c443b6213b

branch: feature-business-rule-validation-contract

Layer: raw/branch-notes/ — syntax validation, use case policy, business invariant, persistence integrity 검증 책임을 분리합니다.

부모 (필수)

ca-skeleton 은 별도 root branch 없이 project-note 가 SSOT 역할. 본 feature branch 는 project-note 의 운영 계약 중 해당 영역 (§<관련 섹션>) 의 결정/근거/금지 사항을 정제한다.

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 1
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: validation ownership·mapper failure contract test가 통과한다

상속한 프로젝트 결정

Decision Ref Project Summary Branch Application Source
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MAPPING-001@1 수기 mapper와 record canonical constructor가 default이며 MapStruct는 optional profile이다 Work Item 완료 조건에 적용 raw/project-notes/ca-skeleton-operational-contract
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-ERROR-ENVELOPE-001@1 foundation이 envelope schema와 error.category enum의 단일 owner다 Work Item 완료 조건에 적용 raw/project-notes/ca-skeleton-operational-contract

브랜치 지역 결정

기존 branch-local 결정은 아래 ## Decision Evidence Map / 결정-근거 매핑의 D-row가 소유하며 이 packet에서 복제하지 않는다.

Decision ID Decision Relation Supporting Claims Status

선언한 예외

Override ID Overrides Reason Approval Status

목표

validation이라는 이름으로 모든 규칙이 controller DTO나 DB constraint에 몰리면 도메인 적용 후 유지보수가 무너집니다. 어떤 규칙을 어느 경계에서 검증할지 명확히 분리합니다.

  • 이슈:
  • PR:

범위

포함 범위

  • request syntax/shape validation.
  • application policy validation.
  • domain invariant validation.
  • persistence uniqueness/integrity handling.
  • duplicate validation 허용 기준.
  • validation error response/log 기준.

제외 범위

  • 특정 비즈니스 규칙 설계.
  • frontend validation 정책.
  • database schema design 전체.

TODO

TODO drained 2026-05-22 — 결정은 아래 "결정 사항" / "Decisionized Work Items" / "판정 기준" 참조. syntax/policy/invariant/persistence/duplicate/validation details 모두 표 row로 반영됨. 잔존 TODO 없음.

진행 중 메모

작업하며 떠오른 메모. 자유 형식.

  • 현재 documented-only 단계 — D1~D9 결정·근거 + §구현 가이드 명세 작성 완료, 실제 코드 미착수.
  • D5/D6/D7 (envelope shape + code→category 매핑) 은 sibling feature-boundary-validation-mapping-contract 와 결정이 중첩 — 구현 명세는 sibling 소유로 정제(§Audit F1/F3). 본 branch 는 4-layer 책임 view 에 집중.
  • 2026-06-02 ca-tmpl ground-truth 패스 (실 코드/registry 대조):
    • F5 RESOLVEDPERSISTENCE enum 은 실재하지 않음(Category.java 10-enum). 실제 매핑 DB_UNIQUE_VIOLATION→CONFLICT / DB_NULL·FK·CHECK→DATA_INTEGRITY 로 전 표 정합.
    • persistence integrity 핸들러 미구현 확인GlobalExceptionHandlerDataIntegrityViolationException 핸들러 없음. owner feature-persistence-failure-baseline(documented-only). §2 에 planned 명시.
    • F2 보강 — policy → AUTHZ 실재 코드(AUTHZ_INSUFFICIENT_PERMISSION/AUTHZ_TENANT_MISMATCH) 확인, 단 owner 는 security/tenant branch → consume. D-ID gap 은 여전히 open.
  • open gap (잔존): use case policy layer D-ID 미부여(§Audit F2). D1/D2 외부 근거 보강 deferred(§Audit F4). error-codes.yaml:580 주석의 stale PERSISTENCE 는 ca-tmpl 레포 측 정리 대상.

Work Item Contract

각 TODO는 아래 판정 단위로 재작성되어야 canonical 승급 가능합니다. TODO가 단순히 기준 작성으로 남아 있으면 이 branch는 완료로 보지 않습니다.

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 승급 위치

결정 사항

  • 2026-05-22: request DTO validation은 입력 모양 검증만 담당.
  • 2026-05-22: business invariant는 domain에서 검증.
  • 2026-05-22: persistence integrity error는 operational error로 변환하되 client-safe message만 응답.
  • 2026-05-22: 이 branch의 TODO도 Work Item Contract를 따라야 하며 아래 Decisionized Work Items가 canonical 승급 기준이다.

근거 (필수, 최소 1개+)

본 branch의 결정 근거. 상세 비교는 §외부 근거 / 대안 조사 (있다면) 참조.

Source 정당화하는 결정
raw/company-tech-blogs/stripe-error-format endpoint dimension 명시 사례
raw/company-tech-blogs/toss-payments-error-format 한국 컨벤션 reference
raw/official-docs/problem-detail-rfc-7807 IETF 표준이지만 실패 전용, success/error 비대칭
raw/official-docs/spring-problem-detail Spring 6 기본 지원이지만 ca-tmpl envelope과 충돌
raw/official-docs/google-api-error-format 가장 표현력 풍부, retryable detail 1급
raw/official-docs/json-api-errors-spec
raw/official-docs/graphql-errors-spec partial success 1급
raw/company-tech-blogs/github-api-error-format

외부 근거 / 대안 조사 (2026-05-22 — Topic 4)

본 branch의 business invariant violation → CONFLICT/VALIDATION mapping 결정에 대한 외부 source 조사. error.category enum과 1:1.

Decisionized Work Items

field Decision Allowed Forbidden Required registry update Required contract test Failure condition
syntax/shape request DTO validation frontend duplicate validation domain-only syntax validation error-registry row 변경 시 VALIDATION 코드 추가 malformed request test malformed request가 VALIDATION envelope로 매핑되지 않으면 실패
use case policy application policy validation domain service if pure domain rule controller-only authorization policy error-registry row 변경 시 AUTHZ/CONFLICT 코드 추가 policy conflict test policy violation이 AUTHZ/CONFLICT envelope로 매핑되지 않으면 실패
domain invariant domain model/value object pre-check for UX/perf DB constraint as only invariant error-registry row 변경 시 CONFLICT/VALIDATION 코드 추가 invariant test invariant violation이 infrastructure exception으로 표현되면 실패
persistence integrity infrastructure maps to operational error application pre-check raw SQL/constraint in response error-registry row 변경 시 DATA_INTEGRITY(null/FK/check) / CONFLICT(unique) 코드 추가 integrity mapping unique/integrity failure가 raw SQL/constraint name을 client에 노출하면 실패
duplicate validation allowed with canonical owner documented redundancy contradictory duplicate rules 없음 (boundary 책임만) boundary test canonical owner 없는 duplicate rule이 추가되면 실패
validation details safe field errors only no details for security raw object/body/SQL detail 없음 (error-registry envelope shape에 종속) leakage test raw object/body/SQL detail이 response에 노출되면 실패

판정 기준

구분 기준
Decision validation 책임을 boundary별로 분리
Allowed 같은 규칙을 UX/성능 목적으로 사전 검증하되 canonical owner를 명시
Forbidden DB constraint만으로 business invariant를 대체
Required mapping syntax -> VALIDATION, policy -> AUTHZ/CONFLICT, invariant -> CONFLICT/VALIDATION, persistence -> DATA_INTEGRITY(null/FK/check)/CONFLICT(unique)
Failure condition raw persistence exception이나 domain exception이 presentation까지 새면 실패

테스트 계약

  • malformed request는 structured validation error로 변환되어야 함.
  • business invariant violation이 infrastructure exception으로 표현되면 실패.
  • unique constraint failure가 SQL/constraint raw name을 클라이언트에 노출하면 실패.
  • 이 branch의 TODO가 Decision/Allowed/Forbidden/Test 없이 남으면 canonical 승급 실패.

결정-근거 매핑

각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시. company-tech-blog 출처는 company-case-study 로 라벨링하며 공식 best practice 로 격상하지 않는다.

Decision ID Decision Supporting Claims Evidence Strength Open Risk
D1 request DTO validation 은 입력 모양 (syntax/shape) 검증만 담당 (2026-05-22) UNSUPPORTED_DECISION (4-layer validation 분리는 project-internal architectural decision; 외부 표준이 boundary 별 책임 분할을 normative 로 강제하지 않음) N/A layer 책임의 정합성은 sibling branch (feature-boundary-validation-mapping-contract) 와 cross-review 필수 — 동일 4-layer 결정이 양쪽에 분산됨
D2 business invariant 는 domain 에서 검증 UNSUPPORTED_DECISION (DDD aggregate invariant 책임 패턴은 일반 design wisdom 이지만 본 branch 가 cite 한 sources — Stripe/Toss/RFC 7807/Spring/Google/JSON:API/GraphQL/GitHub — 중 normative 진술 없음) N/A DDD aggregate / value object 책임 패턴의 raw 인용 (예: Vaughn Vernon, Fowler anemic vs rich) 별도 보강 필요
D3 persistence integrity error 는 operational error 로 변환하되 client-safe message 만 응답 raw/official-docs/problem-detail-rfc-7807.md#RFC7807-C5 ("detail ... ought to focus on helping the client correct the problem, rather than giving debugging information"), raw/company-tech-blogs/github-api-error-format.md#GH-ERR-C4 (validation error code 어휘 — custom 은 message-driven 의 escape hatch) official-standard + official-vendor-doc RFC7807-C5 는 "ought to" 약한 어조; SQL constraint name 차단은 raw 인용보다 보안 일반 원칙 — 별도 raw (예: OWASP error handling) 보강 권장
D4 이 branch 의 TODO 도 Work Item Contract 준수; Decisionized Work Items 표가 canonical 승급 기준 UNSUPPORTED_DECISION (project-internal process gate; 외부 표준 근거 없음) N/A process gate 가 문서에만 있으면 silent skip — /lint 또는 PR template 으로 enforce 필요
D5 error envelope shape — custom {success, data, error.{code,category,message,retryable,details}, meta} 채택, RFC 7807 ProblemDetail 명시적 거부 raw/official-docs/problem-detail-rfc-7807.md#RFC7807-C1 (canonical model 은 JSON application/problem+json), #RFC7807-C2 (type URI 가 primary identifier — custom code 와 충돌), #RFC7807-C3 (extension 가능하나 unknown 은 ignore), raw/official-docs/spring-problem-detail.md#SPRING-PD-C1 (Spring ProblemDetail 은 RFC 9457 representation), #SPRING-PD-C2 (모든 Spring MVC 예외가 ErrorResponse 구현 — ca-tmpl envelope 와 직접 충돌), raw/company-tech-blogs/stripe-error-format.md#STRIPE-ERR-C5 (Stripe 4-종 type enum 사례), raw/company-tech-blogs/toss-payments-error-format.md#TOSS-ERR-C1 (Toss {code, message} 평면 shape) official-standard + official-vendor-doc + company-case-study RFC 7807 미채택의 trade-off (표준 lock-in 회피 vs client 라이브러리 호환성) 는 인용된 source 들이 직접 권고하지 않음 — ca-tmpl 의 운영 해석. Stripe / Toss 는 company-case-study (best practice 격상 금지)
D6 retryable 1급 필드 + success flag — 어떤 표준에도 1:1 매칭 없음 raw/official-docs/google-api-error-format.md#GOOG-ERR-C3 (details 에 typed payload — RetryInfo 등 포함 가능), #GOOG-ERR-C5 (표준 detail payloads — BadRequest, ErrorInfo, LocalizedMessage 등), raw/official-docs/graphql-errors-spec.md#GQL-ERR-C3 (partial response — data + errors 공존), #GQL-ERR-C4 (extensions free-form map) official-vendor-doc + official-standard Google rpc.Status 만 retryable 을 detail 로 가짐 — top-level 1급 필드는 어떤 표준에도 없음 (ca-tmpl 고유 결정). GraphQL partial success 도 envelope success flag 와 다른 모델
D7 validation error mapping — syntax → VALIDATION, policy → AUTHZ/CONFLICT, invariant → CONFLICT/VALIDATION, persistence → DATA_INTEGRITY(null/FK/check)/CONFLICT(unique) raw/official-docs/json-api-errors-spec.md#JSONAPI-ERR-C3 (source.pointer JSON Pointer 로 field-level 오류 위치), #JSONAPI-ERR-C5 (title 은 호출별 불변), raw/company-tech-blogs/github-api-error-format.md#GH-ERR-C3 (validation 실패 = 422), #GH-ERR-C4 (validation code 어휘 6개); category 명칭은 ca-tmpl/docs/registries/error-codes.yaml + shared/error/Category.java SSOT 확인 (2026-06-02) official-standard + official-vendor-doc + code-verified(category) category 분류 체계 자체의 외부 표준은 없음 — ca-tmpl 운영 결정. 실제 enum 은 10종 (VALIDATION/AUTH/AUTHZ/NOT_FOUND/CONFLICT/RATE_LIMIT/TRANSIENT_DEPENDENCY/PERMANENT_DEPENDENCY/DATA_INTEGRITY/INTERNAL); PERSISTENCE 는 없음
D8 duplicate validation 허용 — canonical owner 명시 시 UX/perf 사전 검증 가능 UNSUPPORTED_DECISION (project-internal architectural decision; 외부 표준 근거 없음) N/A canonical owner 정합성은 PR 단위에서 review — silent duplication 위험
D9 validation details — safe field errors only; raw object/body/SQL detail 금지 raw/official-docs/problem-detail-rfc-7807.md#RFC7807-C5 ("detail ought to focus on helping the client correct the problem"), raw/company-tech-blogs/github-api-error-format.md#GH-ERR-C5 (custom code 의 message-driven escape hatch — i18n 위험 명시) official-standard + official-vendor-doc "safe field error" 정의는 ca-tmpl 운영 해석; SQL/constraint name leak 차단은 일반 보안 원칙 — 별도 raw (OWASP) 보강 권장

구현 가이드

결정 (D1~D9) 이 "무엇 을 검증할 것인가" 라면, 본 §는 "어느 layer 에서 어떤 메커니즘으로" 검증·변환·차단되는가의 사전 명세. 본 branch 의 핵심은 검증 책임의 layer 배치 다.

error envelope 의 shape (D5/D6) 과 error code → HTTP → category 매핑 구현 (D7) 은 본 §에서 재명세하지 않는다 — sibling raw/branch-notes/feature-boundary-validation-mapping-contract §구현 가이드 + canonical raw/project-notes/ca-skeleton-operational-contract §6 이 소유 (R3 정제, §Audit & Findings 참조).

1. 4-layer validation 책임 배치 + 정적 강제

Trace:

  • syntax/shape = controller boundary 전용 → D1 (UNSUPPORTED_DECISION — 외부 표준이 boundary 별 책임 분할을 normative 강제하지 않음; sibling feature-boundary-validation-mapping-contract 와 동일 4-layer 결정 분산이므로 cross-review 필수). 검증은 §Claims To Verify row 1.
  • business invariant = domain model/value object 전용 → D2 (UNSUPPORTED_DECISION — DDD aggregate wisdom, 인용 source 8개 중 normative 진술 없음). 검증은 §Claims To Verify row 2.
  • use case policy layer 는 Decision Evidence Map 에 대응 D-ID 가 없음 (gap — §Audit & Findings F2). 아래 표 row 는 Decisionized Work Items 의 "use case policy" row 에서만 도출되며 외부 근거 미연결.
  • UNSUPPORTED_IMPL_DECISION: ①ArchUnit rule 이름 (valid_only_in_controller, domain_invariant_on_all_mutations 등) 임의 명명. ②"모든 mutation 경로" 의 조작적 정의 (생성자 / setter / 도메인 메서드 중 어디까지를 mutation 으로 보는지) — raw 권고 없음, 사용자 임의. ③layer 별 package glob (..adapter.web.. / ..application.. / ..domain..) — canonical raw/project-notes/ca-skeleton-operational-contract §20 Skeleton Blueprint package convention 에서 도출(SUPPORTED via canonical SSOT), glob 변환만 임의.
layer 검증 책임 배치 위치 정적 강제 (계획) Trace
syntax / shape 입력 모양 (required / type / format / size) @Valid + Bean Validation @ controller DTO (..adapter.web..dto..) @Valid 가 controller package 밖에 등장하면 build 실패 (ArchUnit) D1
use case policy application 권한·상태전이 정책 application service (..application..) 정적 강제 없음 — review-only (근거 없음, 아래 trade-off) Decisionized WI "use case policy" (no D-ID, F2)
domain invariant 비즈니스 불변식 domain model / value object (..domain..) invariant method 가 모든 mutation 경로에서 호출되는지 ArchUnit + bypass test D2
persistence integrity unique / FK / 무결성 infrastructure adapter → operational error 변환 (§2) §2 참조 D3
  • UNSUPPORTED_IMPL_DECISION (policy layer 정적 강제 부재): use case policy 를 ArchUnit 으로 강제하지 않고 review-only 로 두는 것은 사용자 trade-off — application 정책은 도메인/요청 문맥 의존이 커서 정적 규칙의 false positive 가 많다는 판단. 근거 raw 없음.

2. Persistence integrity → operational error 변환 지점

Trace: persistence integrity error 는 operational error 로 변환하되 client-safe message 만 응답 → D3 + raw/official-docs/problem-detail-rfc-7807.md#RFC7807-C5 ("detail ought to focus on helping the client correct the problem, rather than giving debugging information"), raw/company-tech-blogs/github-api-error-format.md#GH-ERR-C4. 검증은 §Claims To Verify row 3.

  • 메커니즘 (ground truth 2026-06-02, ca-tmpl 코드 확인): src/adapter-web/.../error/GlobalExceptionHandler.java (@RestControllerAdvice) + ErrorResponseFactoryactually-implemented 지만, 현재 @ExceptionHandler 목록(MappingException / IllegalArgumentException / ConstraintViolation / MethodArgumentTypeMismatch / InvalidBearerToken / Authentication / AccessDenied / PreconditionFailed / PageValidation / Cursor / Exception)에 DataIntegrityViolationException 핸들러가 없음 — persistence integrity 변환은 planned. owner 는 raw/branch-notes/feature-persistence-failure-baseline (documented-only). 본 branch 는 그 핸들러를 consume 하며, integrity handler 추가는 owner branch 책임.
  • 카테고리 매핑 (registry SSOT, ca-tmpl/docs/registries/error-codes.yaml): unique 위반 → CONFLICT (DB_UNIQUE_VIOLATION, 409); null/FK/check 위반 → DATA_INTEGRITY (DB_NULL_VIOLATION/DB_FK_VIOLATION/DB_CHECK_VIOLATION). PERSISTENCE enum 은 존재하지 않음 (src/shared-contract/.../error/Category.java 10-enum 확인).
  • UNSUPPORTED_IMPL_DECISION: SQL/constraint name 차단은 RFC7807-C5("ought to" 약한 어조)보다 일반 보안 원칙 — 별도 raw (OWASP error handling) 보강 권장(D3 Open Risk).
  • DataIntegrityViolationException / OptimisticLockingFailureException 등 persistence 예외는 infrastructure→presentation 으로 raw 전파 금지. exception handler 가 DATA_INTEGRITY (null/FK/check) 또는 CONFLICT (unique) category 의 operational error envelope 로 변환. 현재 미구현 — owner: feature-persistence-failure-baseline.
  • 응답 error.message 는 client-safe 고정 문구만 (registry client_safe_message, 예: DB_UNIQUE_VIOLATION = "Resource already exists"). SQL 문장·constraint 이름·table/column 명을 message/details 어디에도 노출 금지.
  • 구체적 envelope shape 은 본 branch 범위 밖 → canonical §6 (OUT_OF_BRANCH_SCOPE, §Audit F1).

3. Validation detail leakage 차단

Trace: validation details — safe field errors only, raw object/body/SQL detail 금지 → D9 + #RFC7807-C5, raw/company-tech-blogs/github-api-error-format.md#GH-ERR-C5 (custom code 의 message-driven escape hatch — i18n/leak 위험). 검증은 §Claims To Verify row 7.

  • UNSUPPORTED_IMPL_DECISION: "safe field error" 의 정의 (어떤 필드 메타까지 허용 — field 경로? rejected value 포함? message?) 는 ca-tmpl 운영 해석, raw 가 권고하지 않음.
  • details 에 허용: field 경로 + validation message (i18n key). 금지: 직렬화된 raw request object/body, SQLException message, stacktrace, constraint name.
  • 의도적 SQLException 발생 → response body grep 으로 leak 회귀를 contract test 로 pin (§Claims row 7).

4. Duplicate validation canonical owner 표기

Trace: duplicate validation 허용 — canonical owner 명시 시 UX/perf 사전 검증 가능 → D8 (UNSUPPORTED_DECISION — project-internal architectural decision, 외부 근거 없음). 검증은 §Claims To Verify row 8.

  • UNSUPPORTED_IMPL_DECISION: owner 표기 메커니즘 (코드 주석 vs annotation vs 문서 표) 전부 사용자 임의 — D8 자체가 무근거이므로 detail 도 무근거.
  • 같은 규칙을 두 layer 에서 검증하는 것은 허용하되, canonical owner 를 명시. owner 없는 duplicate rule 추가 시 silent contradiction → 금지.
  • 기본값 (착수 가능 수준): 코드 주석 // canonical-owner: <layer> (예: // canonical-owner: domain-invariant) — 단순, 도구 불필요. duplicate 검증 지점마다 owner layer 한 줄 명시.
  • (대안) annotation 강제(ArchUnit): raw/branch-notes/feature-boundary-validation-mapping-contract §Mapper Tool Contract 의 annotation 패턴 참조 후 별도 결정 — D8 무근거이므로 도입 여부는 review 판단.

엣지·실패·의존

R4(깊이 게이트) 캡처용. 정상 경로 외 구현 중 부딪힐 실패/엣지/다른 계약 의존.

  • 실패·엣지 경로:
    • malformed JSON (HttpMessageNotReadableException) vs Bean Validation 실패 (MethodArgumentNotValidException) — 둘 다 syntax layer 지만 다른 exception. 둘 다 VALIDATION category 로 수렴해야 함(sibling D10 과 정합).
    • 동시성 하 unique constraint race: application 사전 check(D8 duplicate)가 통과해도 DB 레벨에서 integrity violation 발생 가능 → persistence layer(D3)가 최종 방어선. 사전 check 는 UX 목적일 뿐 invariant 보장 아님.
    • nested DTO @Valid cascade 깊이 — sibling 의 cascade depth ≤ 3 정적 강제(B4)에 의존.
  • 다른 계약 의존:

Audit & Findings

R3 정제 history + 발견된 gap 보존 (§구현 가이드 본문에서 제외한 항목의 이관 근거).

ID 유형 내용 조치
F1 OUT_OF_BRANCH_SCOPE D5 (envelope custom shape), D6 (retryable/success flag) 의 구현 명세EnvelopeBodyAdvice/Envelope/BulkEnvelope 클래스·factory API — 는 sibling raw/branch-notes/feature-boundary-validation-mapping-contract §구현 가이드 §4 + canonical §6 이 소유. 본 §구현 가이드에서 재명세 제외. D5/D6 결정 기록 은 Decision Evidence Map 에 유지(error-format Topic 4 공유 조사 산물). sibling/canonical 참조로 대체
F2 DECISION_GAP Decisionized Work Items 의 "use case policy" row + §1 표의 policy layer 가 Decision Evidence Map 에 대응 D-ID 가 없음. syntax(D1)/invariant(D2)/persistence(D3)/duplicate(D8)/details(D9)는 D-ID 보유하나 policy 만 누락. 착수 기본값 (registry owner_branch 확인 2026-06-02): 인가 정책 violation → AUTHZ (실재 코드 AUTHZ_INSUFFICIENT_PERMISSION + AUTHZ_TENANT_MISMATCH, 403, 둘 다 owner feature-security-operational-baseline); 상태 전이 충돌 → CONFLICT. (주의: feature-tenant-context-policy 는 AUTHZ 코드 소유자 아님 — TENANT_NOT_SUPPORTED(VALIDATION/400) 별도 소유.) 본 branch 는 이 코드들을 consume. 매핑 자체는 여전히 UNSUPPORTED (본 노트 D-ID 없음) — 코드 착수 후 policy layer 책임을 D10(본 노트)로 승격하거나 owner branch 와 cross-link 하여 확정 필요. 추측을 FACT 로 기재 금지.
F3 OUT_OF_BRANCH_SCOPE D7 의 코드→category 매핑 구현 은 sibling D10 영역. 본 branch 는 어느 layer 가 어느 category 후보인지 의 책임 view 만 제공. persistence 코드(DB_UNIQUE_VIOLATION→CONFLICT, DB_NULL/FK/CHECK_VIOLATION→DATA_INTEGRITY)는 owner raw/branch-notes/feature-persistence-failure-baseline 소유. sibling/owner 참조
F4 DEFERRED_RESEARCH D1 (4-layer 분리), D2 (DDD invariant 책임) 의 외부 근거 보강 — D2 Open Risk 가 Vernon/Fowler(anemic vs rich domain) raw 인용을 명시. wiki-decision-researcher 자동조사 후보지만 web-fetch(outward) 라 사용자 opt-in 대기. /branch-spec ... --research D1,D2 또는 수동
F5 CATEGORY_DRIFT → RESOLVED 2026-06-02 본 노트가 쓰던 PERSISTENCE category 는 실재하지 않음 — src/shared-contract/.../error/Category.java 의 10-enum(VALIDATION/AUTH/AUTHZ/NOT_FOUND/CONFLICT/RATE_LIMIT/TRANSIENT_DEPENDENCY/PERMANENT_DEPENDENCY/DATA_INTEGRITY/INTERNAL)에 없음. registry error-codes.yaml 의 실제 매핑: DB_UNIQUE_VIOLATION→CONFLICT(409), DB_NULL/FK/CHECK_VIOLATION→DATA_INTEGRITY. (error-codes.yaml:580 주석에도 동일 stale 매핑이 전파돼 있었음 — ca-tmpl 레포 측 별도 정리 대상.) 반영 완료: D3/D7/§판정 기준/Decisionized WI/§구현 가이드 §2/§엣지/Claims 의 PERSISTENCEDATA_INTEGRITY(null/FK/check)/CONFLICT(unique) 로 정합 (코드+registry 근거).

검증해야 할 주장

공식 문서/사례는 근거지만 내 프로젝트에서의 동작을 자동 보장하지 않는다. 구현 전/중/후 실제로 검증해야 하는 주장.

Claim Why uncertain How to verify Status
request DTO validation 이 controller boundary 에서만 트리거되고 domain layer 로 새지 않는지 @Valid annotation 위치 / interceptor 체인 misconfiguration 가능성 ArchUnit rule (@Valid annotation 은 controller package 만) + integration test planned
business invariant 가 domain model / value object 안에서 강제되며 application service bypass 불가한지 service-layer invariant check 로 domain bypass 가능성 ArchUnit rule (domain model 의 invariant method 가 모든 mutation 경로에서 호출) + 의도적 bypass test planned
persistence integrity exception (e.g., DataIntegrityViolationException) 이 envelope 의 DATA_INTEGRITY(null/FK/check) / CONFLICT(unique) category 로 매핑되며 SQL/constraint name leak 안 되는지 현재 GlobalExceptionHandlerDataIntegrityViolationException 핸들러 자체가 없음(2026-06-02 확인) — owner feature-persistence-failure-baseline 미구현 owner branch 구현 후 exception handler contract test + DLP scan (constraint name regex grep on response) planned (owner: feature-persistence-failure-baseline)
4-layer mapping (syntax → VALIDATION, policy → AUTHZ/CONFLICT, invariant → CONFLICT/VALIDATION, persistence → DATA_INTEGRITY/CONFLICT) 가 모든 exception 에 일관 적용되는지 category 분류의 silent miscategorization 가능성 exception → category 매핑 contract test (각 layer 의 대표 exception 별 category 검증) planned
envelope 의 retryable 플래그가 category 와 정합한지 (registry 확인: VALIDATION/CONFLICT/DATA_INTEGRITY 모두 retryable=false) retryable 은 per-code (registry error-codes.yaml), category 에서 계산 금지 (Category.java javadoc) category × retryable matrix contract test + registry 대조 planned
RFC 7807 ProblemDetail 미채택이 Spring 6 의 autoconfigure (spring.mvc.problemdetails.enabled, SPRING-PD-C4) 와 충돌하지 않는지 Spring Boot default 가 true 인지 모름 → 자동 활성화 시 envelope override 필요 sibling raw/branch-notes/feature-boundary-validation-mapping-contract 가 동일 위험을 actually-implemented 로 해소 (2026-05-29: GlobalExceptionHandlerProblemDetail import 완전 제거, 우리 핸들러 우선이라 자동 활성화와 충돌 없음, BoundaryDemoControllerWireTest 11 케이스 wire-pin) → 본 branch 재검증 불필요 verified (sibling)
details 필드에 raw object / body / SQL detail 이 절대 leak 안 되는지 exception handler 의 detail 직렬화 path 에서 누락 가능 leakage contract test (의도적 SQLException 발생 → response body grep) + production log scrub planned
duplicate validation 의 canonical owner 가 코드 주석 / 문서에 명시되는지 duplication 자체는 허용이지만 owner 누락 시 silent contradiction 가능 code review checklist + ArchUnit rule (duplicate validator 는 owner annotation 필수) needs-confirmation

관심사 커버리지 (coverage-auditor 자동 생성)

/coverage 가 생성하는 생성물 — 손유지 금지. 기준: rules/coverage-gate.md. governing_docs: clean-architecture-package-layout + api-error-envelope-design. 마지막 감사: 2026-06-02 → Covered (Blocking 0 / Should-fix 0 / Advisory 4).

관심사 상태 owner 심각도 근거
4-layer validation 책임 배치 (syntax/policy/invariant/persistence) covered-here D1·D2
domain purity — infrastructure exception raw 전파 금지 covered-here D3
@Valid 정적 강제 (controller 패키지 밖 금지) covered-here D1 (Claims row 1, planned)
business invariant violation → error.category 분류 covered-here D7
persistence integrity → DATA_INTEGRITY(null/FK/check) / CONFLICT(unique) 매핑 covered-here D3·D7 (Audit F5 RESOLVED)
exception leak 금지 (SQL/constraint name/stacktrace) covered-here D9
retryable 필드 정합 (VALIDATION/CONFLICT/DATA_INTEGRITY = false) covered-here Claims row 5 (registry SSOT)
web DTO containment — domain 직렬화 금지 delegated raw/branch-notes/feature-boundary-validation-mapping-contract D8 owner actually-implemented (controllers_do_not_return_domain_or_entity_types)
validation 실패 → error.details[] 항목별 오류 매핑 delegated raw/branch-notes/feature-boundary-validation-mapping-contract D10 owner actually-implemented (VALIDATION_FAILED details shape)
i18n 검증 메시지 정책 governing 문서 비열거 Advisory 두 governing 문서 모두 미열거 — 프로젝트 레벨 owner 여부는 /coverage --project 영역
입력 정규화/sanitization before validation governing 문서 비열거 Advisory 미열거. 실코드 trim/sanitize 는 header/pagination 맥락
fail-fast vs collect-all 오류 수집 정책 governing 문서 비열거 Advisory 미열거. 형제 B4 @GroupSequence 가 사실상 결정
cross-field/conditional validation governing 문서 비열거 Advisory 미열거. 형제 B4 class-level constraint actually-implemented

완료 후 wiki 추출 대상

  • wiki/projects/ca-skeleton-operational-contract.md의 business rule validation canonical section.

마주친 문제

  • 아직 없음(문서 단계).

묶음

본 feature branch 는 leaf — 자식 자료 없음. Phase C2 실 코드 작성 단계에서 errors / interview prep / lectures 가 누적되면 본 섹션에서 그룹화.

오류 기록 (본 feature 작업 중 발생)

  • (없음 — 현재 documented-only 단계)

면접 준비 (이 작업에서 나올 수 있는 면접 질문)

  • (없음 — Phase C2 실 구현 단계에 누적)

관련 일일 노트

이 브랜치를 작업한 날짜들. 양방향 nav 유지.

  • (아직 없음 — documented-only 단계. 실 구현 착수 시 [[raw/daily-notes/YYYY-MM-DD]] 누적)

완료 후 정리

머지/종료 시점에 채움.

  • PR 링크:
  • 리뷰 메모:
  • 머지 결과 / 배포 환경:
  • wiki 추출 대상 (verified만, wiki/projects/로만 추출):
    • actually-implemented 항목:
    • locally-verified 항목:
    • prod-verified 항목:
  • 추출하지 않을 항목 (planned / documented-only / abandoned):