Files
llm-wiki/raw/branch-notes/feature-repository-access-permission-contract.md

53 KiB

title, source_type, status, branch, parent_branch, governing_docs, related_projects, 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 governing_docs related_projects tags created target_merge status_label id kind project work_item inherits refines overrides depends_on contract_packet contract_packet_sha256
branch / feature-repository-access-permission-contract branch-note raw feature-repository-access-permission-contract
wiki/projects/ca-tmpl/clean-architecture-package-layout
wiki/projects/ca-tmpl/transaction-boundary-abstraction
ca-skeleton
branch
ca-skeleton
repository
permission
use-case
2026-05-21 in-progress BR-CA-SKELETON-OPERATIONAL-CONTRACT-005 project-work-item ca-skeleton-operational-contract WI-CA-SKELETON-OPERATIONAL-CONTRACT-005
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-TRANSACTION-001@1
1 50c7cd20afc5ff3d2eb1c7aea5ff6409e78e87aa3263173240c362ad7f1ac330

branch: feature-repository-access-permission-contract

Layer: raw/branch-notes/ — use case 단위 repository capability 정책을 정의합니다. 구조 메모: 이 노트는 2026-05-21 생성(현 branch-note 템플릿 이전 포맷). 2026-06-05 /branch-spec 에서 템플릿 순서로 재정렬했고, 템플릿에 없는 pre-template 결정 보조 섹션(판정 기준 / Work Item Contract / Decisionized Work Items / 테스트 계약)은 capabilities.yaml 주석이 이름으로 참조하므로 삭제하지 않고 말미 §부록으로 분리·보존했다.

부모 (필수)

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

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 1
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: repository access rule과 forbidden fixture가 통과한다

상속한 프로젝트 결정

Decision Ref Project Summary Branch Application Source
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1 Gradle multi-module에서 domain-core·application-core·adapter-*·shared-contract·app-bootstrap·sample-portfolio 책임을 분리한다 Work Item 완료 조건에 적용 raw/project-notes/ca-skeleton-operational-contract
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-TRANSACTION-001@1 application은 Spring transaction annotation 대신 TransactionPort 또는 TransactionalUseCaseRunner를 사용한다 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

목표

read/write repository 분리는 기본입니다. 추가로 어떤 use case가 어떤 repository capability를 사용할 수 있는지 annotation/policy로 제한해야 합니다. 특정 상황에서 허용되지 않은 repo 사용은 skeleton contract violation입니다.

  • 이슈:
  • PR:

범위

포함 범위

  • use case capability annotation 기준.
  • repository capability vocabulary.
  • read/write/sensitive/bulk/transaction/outbound capability 분류.
  • policy violation error 분류.
  • architecture/contract test 기준.

제외 범위

  • 세부 도메인별 repository 구현.
  • runtime authorization과 repository access policy 혼동.
  • DB row-level security 구현.

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

본 branch의 결정 근거. 상세 비교는 아래 §외부 근거 / 대안 조사 참조.

Source 정당화하는 결정
raw/official-docs/multitenancy-aws-saas-tenant-isolation-whitepaper Silo/Pool/Bridge 어느 모델이든 admin은 cross-tenant
raw/official-docs/multitenancy-hibernate-user-guide DISCRIMINATOR/SCHEMA/DATABASE 어느 strategy든 admin은 filter bypass 필요
raw/company-tech-blogs/multitenancy-atlassian-tenant-context admin context override 운영 사례
raw/company-tech-blogs/multitenancy-auth0-tenant-resolution JWT/header/subdomain
raw/company-tech-blogs/multitenancy-subdomain-resolution-patterns subdomain 대안
raw/company-tech-blogs/multitenancy-stripe-citus-schema-per-tenant schema-per-tenant 대안
raw/official-docs/multitenancy-microservices-io-pattern db-per-tenant 대안
raw/official-docs/multitenancy-azure-architecture-patterns raw/company-tech-blogs/multitenancy-hybrid-pooled-siloed-mix — hybrid 대안
raw/company-tech-blogs/multitenancy-hybrid-pooled-siloed-mix hybrid 대안
raw/official-docs/arch-clean-architecture-uncle-bob D1 (use case 기준 capability), D5 (domain framework 의존 회피)
raw/official-docs/arch-hexagonal-cockburn D3 (capability = use case infra power, not user auth), D4 (TransactionPort port-adapter), D5 (port-external metadata 분리)
raw/official-docs/cqrs-fowler-bliki D10 (read/write repo 물리 분리 안 함, 메서드 단위 capability)
raw/official-docs/microservices-io-transactional-outbox D7 (EXTERNAL_OUTBOUND_ALLOWED = polling publisher broker publish)
raw/official-docs/archunit-user-guide D8 (enforcement SSOT = ArchUnit annotation-based rule), D12 (coherence rule)
raw/official-docs/spring-tx-management-reference D4 (TRANSACTION_REQUIRED ↔ TransactionPort, Spring @Transactional 직접 import 금지)

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

본 branch의 CROSS_TENANT_ADMIN capability 결정에 대한 외부 source. tenant resolution과 isolation은 feature-tenant-context-policy SSOT consume.

TODO

TODO drained 2026-05-22 — 결정은 아래 "결정 사항" / 부록 "판정 기준" / "Decisionized Work Items" 참조. @UseCaseRepositoryAccess annotation / capability enum / read·write·sensitive·bulk·transaction·outbound 의미 / use case-operation 매칭 / 위반 error code / architecture·contract test 기준 모두 결정 라인 또는 표로 반영됨. 잔존 TODO 없음.

진행 중 메모

  • 이 권한은 사용자 권한이 아니라 application use case가 infrastructure capability를 사용할 수 있는지의 권한입니다.

결정 사항

  • 2026-05-21: use case 기준 capability 선언을 기본으로 함.
  • 2026-05-22: capability annotation 이름은 @UseCaseRepositoryAccess를 기본값으로 둠. → 2026-06-05 정합(사용자 결정 — as-built 채택): 실제 구현·테스트된 @UseCaseCapability(TYPE target, 4-attribute)를 SSOT 로 채택. flat-enum @UseCaseRepositoryAccess 원안은 superseded. 코드 재작성 대신 문서를 코드에 맞춤(§Audit F1·F2 RESOLVED).
  • 2026-05-22: repository capability는 사용자 권한이 아니라 application use case가 infrastructure 능력을 사용할 수 있는지에 대한 계약.
  • 2026-05-22: TRANSACTION_REQUIRED는 application-port branch의 TransactionPort contract와 연결되어야 하며 Spring @Transactional 직접 import로 충족하지 않음.
  • 2026-05-22: SENSITIVE_READ marker = registry-managed metadata table (entity FQN + field name 단위). domain annotation 또는 JPA entity annotation 금지(domain에 framework 의존 회피). registry 표 위치는 contract-registry-governance. → 2026-06-05 깊이 결정(사용자 — 플래그만 + 메타표 defer): 본 branch 는 capability 어휘(sensitiveRead boolean + capabilities.yaml row)만 소유. sensitive-field 메타표(entity FQN+field)와 위반 차단 enforcement 는 owner 인 raw/branch-notes/feature-contract-registry-governance 로 위임(documented-defer). scope 침범·ArchUnit static-analysis 한계 회피.
  • 2026-05-22: BULK_WRITE threshold = N > 100 또는 batch size > 100. 미만은 일반 WRITE_REPOSITORY로 충분.
  • 2026-05-22: EXTERNAL_OUTBOUND_ALLOWED 분류 = outbox row INSERT는 in-process(불요), polling publisher의 broker publish는 outbound(필요).
  • 2026-05-22: enforcement SSOT = ArchUnit annotation-based rule. compile-time annotation processor는 alternative, runtime AOP는 forbidden.
  • 2026-05-22: CROSS_TENANT_ADMIN capability를 capability vocabulary에 추가 (tenant branch feature-tenant-context-policy와 cross-link).
  • 2026-05-22: read repo vs write repo 분리는 강제하지 않음. 한 repository 내 메서드 단위 capability 선언으로 충분.
  • 2026-05-22: capability marker 표준 = Java annotation @UseCaseRepositoryAccess(value=Capability[]) (METHOD target, flat 7-enum). → 2026-06-05 정합(사용자 — as-built 채택). 아래는 superseded 원안이며 SSOT 아님:
    • retention: RetentionPolicy.RUNTIME (RUNTIME 은 as-built 와 일치)
    • target: ElementType.METHOD (use case method 단위) → as-built ElementType.TYPE (use case 클래스 단위)
    • value: Capability[] array → as-built 4개 typed attribute
    • Capability enum 7개 flat → as-built 차원별 분리(아래 정식 결정)
    • consumer branches(feature-application-port-usecase-contract, feature-business-rule-validation-contract, feature-tenant-context-policy)는 본 annotation을 consume only. (유지)
  • 2026-06-05: capability marker 표준 (as-built SSOT) = @UseCaseCapability@Retention(RUNTIME), @Target(TYPE), use case 클래스 단위. 속성:
    • 구현됨(actually-implemented): transactionMode(enum WRITE/READ_ONLY/REQUIRES_NEW), idempotency(enum IDEMPOTENT/KEYED/NOT_IDEMPOTENT), repositoryAccess(enum NONE/READ_REPOSITORY/WRITE_REPOSITORY), externalOutboundAllowed(boolean default false).
    • 확장 예정(planned): 누락 3종을 externalOutboundAllowed 패턴의 boolean 으로 추가 — sensitiveRead / bulkWrite / crossTenantAdmin (각 default false). enum 신설이 아니라 boolean 속성 추가로 기존 코드 최소 변경.
    • 미명시 시 ArchUnit presence rule inbound_port_implementations_declare_capability fail (owner: application-port).

결정-근거 매핑

본 branch 의 각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시한다. Decision ID 는 안정적으로 유지한다. company-tech-blog 출처는 company-case-study 로 표기하며 공식 best practice 로 일반화하지 않는다.

Decision ID Decision Supporting Claims Evidence Strength Open Risk
D1 use case 기준 capability 선언을 기본 raw/official-docs/arch-clean-architecture-uncle-bob.md#CLEAN-ARCH-UB-C1 (use case 가 application layer SSOT), #CLEAN-ARCH-UB-C2 (dependency rule — inner layer 가 outer infrastructure 능력을 선언), #CLEAN-ARCH-UB-C7 (use case 단위 boundary 가 frameworks/drivers 능력 제어) engineering-blog + engineering-blog + engineering-blog (Uncle Bob personal blog — 공식 표준 아님) Uncle Bob blog 는 personal opinion. Clean Architecture 책 (Pearson) 의 ISO/IEEE 표준 인용 부재
D2 capability annotation = @UseCaseCapability (as-built SSOT, 2026-06-05 정합). flat-enum 원안 @UseCaseRepositoryAccess 는 superseded as-built 코드 = SSOT — application-core/.../capability/UseCaseCapability.java (actually-implemented + locally-verified) actually-implemented (코드 grep + UseCaseCapabilityTest 통과) naming 은 여전히 branch 자체 정합성 규칙이나 코드에 실재하므로 UNSUPPORTED_DECISION 해소. §Audit F1 RESOLVED
D3 repository capability = application use case 의 infrastructure 능력 사용 권한 (사용자 권한 아님) raw/official-docs/arch-hexagonal-cockburn.md#HEX-COCKBURN-ORIG-C3 (port = application 이 outside world 와 talk 하는 use case-shaped contract), #HEX-COCKBURN-ORIG-C4 (adapter 가 port 를 외부 기술로 구현 — capability 는 application 의 infrastructure 능력), #HEX-COCKBURN-ORIG-C7 (application 은 외부 기술 종류와 독립 — user auth 와 별개) engineering-blog + engineering-blog + engineering-blog (Cockburn personal blog — 공식 표준 아님) Cockburn 의 hexagonal 은 personal architectural article. user auth 와 명시 구분은 본 branch 의 해석
D4 TRANSACTION_REQUIRED = application-port branch 의 TransactionPort contract 연결 (Spring @Transactional 직접 import 로 충족 금지) raw/official-docs/arch-hexagonal-cockburn.md#HEX-COCKBURN-ORIG-C3 (port = application contract), #HEX-COCKBURN-ORIG-C4 (adapter 가 port 를 framework 구현), raw/official-docs/spring-tx-management-reference.md#SPRING-TX-MGR-C3 (PlatformTransactionManager API 추상화), #SPRING-TX-MGR-C5 (@Transactional 은 framework-specific annotation) engineering-blog + engineering-blog + official-vendor-doc + official-vendor-doc (Cockburn blog + Spring official reference) Cockburn port-adapter 와 Spring TX API 의 결합 (TransactionPort 추상화) 은 본 branch 해석 — official 표준은 직접 결합을 명시하지 않음
D5 SENSITIVE_READ: 본 branch 는 capability 어휘(sensitiveRead boolean + capabilities.yaml row)만 소유. metadata table(entity FQN+field; domain/JPA annotation 금지)과 위반 차단 enforcement 는 raw/branch-notes/feature-contract-registry-governance 로 위임(2026-06-05 깊이 결정 — 플래그만 + 메타표 defer) 선택 조건: 메타표 위치·강제는 registry-governance owner / 본 branch 는 어휘만. 근거 — raw/official-docs/arch-clean-architecture-uncle-bob.md#CLEAN-ARCH-UB-C5 (entity = framework 독립), #CLEAN-ARCH-UB-C7 (entity 가 framework annotation 의존 금지), raw/official-docs/arch-hexagonal-cockburn.md#HEX-COCKBURN-ORIG-C3 (metadata 는 port 외부 registry 로 분리) engineering-blog + engineering-blog + engineering-blog (Uncle Bob + Cockburn personal blogs) — 분리 원칙만; 위임 경계는 본 branch 운영 결정 sensitiveRead 어휘 planned; 메타표·enforcement documented-defer(owner: registry-governance). scope·ArchUnit 한계 회피
D6 BULK_WRITE threshold = N > 100 또는 batch size > 100 UNSUPPORTED_DECISION — 운영 threshold default. 외부 official 근거 없음 none branch 자체 운영 default
D7 EXTERNAL_OUTBOUND_ALLOWED = outbox row INSERT (in-process, 불요); polling publisher broker publish (outbound, 필요) raw/official-docs/microservices-io-transactional-outbox.md#MSIO-OUTBOX-C2 (outbox table INSERT 는 same DB transaction — in-process), #MSIO-OUTBOX-C5 (별도 message relay/polling publisher 가 outbox 를 읽어 broker 로 publish — outbound 분리), #MSIO-OUTBOX-C7 (polling publisher 가 broker 와의 외부 통신 담당) engineering-blog + engineering-blog + engineering-blog (Chris Richardson microservices.io — engineer 운영 가이드, 공식 표준 아님) microservices.io 는 Richardson 개인 사이트 — outbox pattern 의 capability 분류 명명은 본 branch 해석
D8 enforcement SSOT = ArchUnit annotation-based rule (compile-time annotation processor 는 alternative, runtime AOP 는 forbidden) raw/official-docs/archunit-user-guide.md#ARCHUNIT-UG-C1 (ArchUnit 은 Java 아키텍처 규칙 단위 테스트 라이브러리), #ARCHUNIT-UG-C2 (JUnit test 로 실행 — compile/test time 검증), #ARCHUNIT-UG-C5 (annotation-based rule 지원 — @AnnotatedWith 등) official-vendor-doc + official-vendor-doc + official-vendor-doc (ArchUnit official user guide) AOP vs annotation processor 의 forbidden/alternative 분류는 본 branch 의 운영 정책 — ArchUnit doc 자체는 selection 권고 없음. ⚠️ presence rule 의 코드 owner 는 application-port (§Audit F5)
D9 CROSS_TENANT_ADMIN capability 추가 (tenant branch cross-link) raw/official-docs/multitenancy-aws-saas-tenant-isolation-whitepaper.md#AWS-TENANT-C1 ~ C2 (tenant isolation fundamental + boundary breach un-recoverable), raw/official-docs/multitenancy-hibernate-user-guide.md#HBN-MT-C2 (DISCRIMINATOR strategy 공식 지원 — admin 은 filter bypass 필요) official-vendor-doc (AWS main page verbatim) + needs-confirmation (Hibernate body truncated) AWS 는 admin 이 cross-tenant 권한을 요구한다는 직접 명시는 sub-page 영역 (AWS-TENANT-C6 — needs-confirmation). Hibernate body verbatim 도 미확인
D10 read repo vs write repo 물리적 분리는 강제 안 함 — 한 repository 내 메서드 단위 capability 선언으로 충분 raw/official-docs/cqrs-fowler-bliki.md#CQRS-FOWLER-C1 (CQRS 는 command/query 모델 분리), #CQRS-FOWLER-C3 (CQRS 는 일부 영역에 유용 — 전체 시스템에 강제 금지), #CQRS-FOWLER-C4 (Fowler 가 CQRS 의 비용 경고 — most systems 에는 부적합), #CQRS-FOWLER-C5 (단일 모델 단순화가 default — physical 분리는 큰 비용) engineering-blog + engineering-blog + engineering-blog + engineering-blog (Fowler bliki personal blog — 공식 표준 아님) Fowler bliki 는 personal opinion piece. 메서드 단위 capability 가 CQRS 의 대안이라는 해석은 본 branch 적용
D11 capability marker = @UseCaseCapability (as-built SSOT): @Retention(RUNTIME) + @Target(TYPE) (클래스 단위) + typed attributes. 구현됨: transactionMode/idempotency/repositoryAccess/externalOutboundAllowed. 확장 예정: sensitiveRead/bulkWrite/crossTenantAdmin boolean. flat 7-enum 원안 superseded(2026-06-05) as-built 코드 = SSOT — UseCaseCapability.java + RepositoryAccess.java/Idempotency.java/TransactionMode.java (actually-implemented); 신규 3 boolean 은 planned actually-implemented(4속성) + planned(3 boolean) 구조는 코드로 확정. 신규 3 boolean 은 미구현(Phase C2). §Audit F2 RESOLVED
D12 repositoryAccess 선언과 실제 repository 호출의 정합을 강제 (coherence): repositoryAccess = READ_REPOSITORY 선언 use case 가 write 메서드를 호출하면 build fail. presence(선언 유무) 강제와 별개의 관심사. N/A (강제 자체는 항상 적용) — 단 검출 메커니즘은 분기: ArchUnit static-analysis 로 호출 그래프 도달 가능 시 ArchUnit rule, 도달 불가(reflection/동적 호출) 시 runtime guard 또는 review fallback raw/official-docs/archunit-user-guide.md#ARCHUNIT-UG-C1 (Java 아키텍처 규칙 단위 테스트), #ARCHUNIT-UG-C5 (@AnnotatedWith + method-call 분석 API) + governing doc wiki/projects/ca-tmpl/transaction-boundary-abstractionUseCaseCapability Javadoc coherence 제약 (QueryUseCase ⇒ READ_ONLY+READ_REPOSITORY) official-vendor-doc (ArchUnit) + documented-only (Javadoc coherence 명세)

구현 가이드

본 §는 as-built 명세다. 이 branch 의 결정(D1~D11)이 무엇을 할 것인가라면, 본 §는 ca-tmpl src/실제로 어떻게 구현됐는지 + 아직 안 된 부분을 명세한다. 중대 주의 — 코드가 D2/D11 의 명세와 다르게 구현됨. annotation 명칭/구조/타깃이 노트 결정과 어긋난다(상세·정합 권고는 §Audit & Findings 의 CONTRACT_DRIFT 참조). 본 §의 anchor 는 코드(SSOT) 기준이며, D2/D11 은 사용자 결정 영역이라 자동 rewrite 하지 않고 drift 만 surface 한다. actually-implementedsrc/ grep 으로 확정한 것만. registry row 만 있고 코드 없는 것은 planned.

1. Capability marker — as-built annotation 모양

Trace: D2/D11(as-built @UseCaseCapability 채택, 2026-06-05 정합) + #CLEAN-ARCH-UB-C7(use case 단위 boundary). 노트 D2/D11 이 as-built 로 정합됐으므로 drift 해소 — 아래는 코드 = 노트 일치 명세.

  • UNSUPPORTED_IMPL_DECISION: (1) 4-attribute 구조(transactionMode/idempotency/repositoryAccess/externalOutboundAllowed)로의 분해는 외부 근거 없는 구현 trade-off — flat enum 대비 "transactional shape·idempotency·repo access·outbound surface 를 body 안 보고 읽게" 한다는 javadoc rationale(코드 주석)만 근거. (2) @Target(TYPE)(클래스 단위) vs METHOD(원안) 선택도 외부 근거 없는 trade-off — "use case = 1 클래스 1 책임" 가정에 기댐(클래스당 capability 1조). 다중 책임 클래스에는 부적합. 둘 다 사용자 결정(2026-06-05)으로 as-built 채택.
항목 as-built (코드 = 노트 SSOT) 원안(superseded) status
annotation 명 @UseCaseCapability @UseCaseRepositoryAccess actually-implemented
위치(파일) application-core/.../application/capability/UseCaseCapability.java actually-implemented
@Target ElementType.TYPE (use case 클래스 단위) ElementType.METHOD actually-implemented
@Retention RUNTIME (ArchUnit reflection) RUNTIME actually-implemented
속성 구조 4개 typed attribute (아래 §2) + 확장 3 boolean(planned) 단일 Capability[] array actually-implemented / planned(확장)

2. Capability vocabulary — 구현된 enum vs registry 선언

Trace: 부록 §판정 기준 "Required capability" 7종 + capabilities.yaml 7 row(owner_branch: feature-repository-access-permission-contract). 코드는 flat 7-enum 이 아니라 차원별 typed enum 으로 구현됐고, 7종 중 3종은 registry row 만 있고 코드 없음.

  • UNSUPPORTED_IMPL_DECISION: RepositoryAccessNONE 추가(registry/노트에 없는 값) — repo 미접근 use case 표현용 구현 trade-off. Idempotency 차원 전체가 노트 capability vocabulary 에 부재(코드에는 존재).
노트/registry capability 코드 구현 위치 as-built 값 status
READ_REPOSITORY / WRITE_REPOSITORY capability/RepositoryAccess.java enum NONE, READ_REPOSITORY, WRITE_REPOSITORY actually-implemented
TRANSACTION_REQUIRED transaction/TransactionMode.java enum (별도 차원) WRITE, READ_ONLY, REQUIRES_NEW actually-implemented
EXTERNAL_OUTBOUND_ALLOWED UseCaseCapability.externalOutboundAllowed() boolean default false actually-implemented
(노트에 없음) idempotency capability/Idempotency.java enum IDEMPOTENT, KEYED, NOT_IDEMPOTENT actually-implemented
SENSITIVE_READ UseCaseCapability.sensitiveRead() boolean boolean default false actually-implemented (2026-06-05; 어휘+플래그만). 메타표(entity-FQN+field)·field-level enforcement 는 raw/branch-notes/feature-contract-registry-governance 위임(D5 documented-defer)
BULK_WRITE UseCaseCapability.bulkWrite() boolean boolean default false actually-implemented (2026-06-05; D6). threshold 100 은 human 가이드(runtime 미강제). bulkWrite=true ⇒ repositoryAccess=WRITE_REPOSITORY coherence 강제됨
CROSS_TENANT_ADMIN UseCaseCapability.crossTenantAdmin() boolean boolean default false actually-implemented (2026-06-05; D9 어휘 owner 본 branch). cross-tenant runtime 정책은 raw/branch-notes/feature-tenant-context-policy 위임

3. Enforcement — ArchUnit fitness function (presence 만 강제, coherence 미강제)

Trace: D8(enforcement SSOT = ArchUnit annotation-based rule), #ARCHUNIT-UG-C5(@AnnotatedWith 지원). 구현된 rule 의 owner attribution 은 raw/branch-notes/feature-application-port-usecase-contract (코드 .as() 메시지) — D8 이 본 branch 를 SSOT 라 한 것과 ownership drift(§Audit).

  • UNSUPPORTED_IMPL_DECISION: "repositoryAccess 선언과 실제 repository 호출의 정합(read-only 가 write 메서드 호출 시 fail)" 강제는 코드에 없음. annotation 은 선언적 문서일 뿐 — 정합 검출은 method-level call 분석 필요(ArchUnit static-analysis 한계). 이 branch 테스트 계약의 핵심 주장(아래 §4)이 대부분 planned 인 이유.
ArchUnit rule (실명) 위치 무엇을 강제 owner status
inbound_port_implementations_declare_capability CleanArchitectureTest.java:187 모든 CommandUseCase/QueryUseCase 구현체가 @UseCaseCapability 보유 (presence) feature-application-port-usecase-contract locally-verified (negative fixture: MissingCapabilityUseCase)
inbound_port_implementations_do_not_declare_keyed_idempotency REMOVED (2026-06-09 정합) (없음 — CleanArchitectureTest.java:217 에 제거 NOTE) idempotency = KEYED freeze 였으나 rate-limit-idempotency branch 머지로 freeze 해제 → 룰 + KeyedIdempotencyUseCase fixture 삭제됨(코드 확인). UseCaseCapabilityTest 가 이제 KEYED 를 valid 로 단언. raw/branch-notes/feature-application-port-usecase-contract D14 (freeze 트리거) locally-verified삭제(stale 정합). 노트가 live 룰로 잘못 기재했던 것 정정
application_does_not_use_spring_transactional_annotation CleanArchitectureTest.java ..application..org.springframework.transaction.annotation.Transactional FQN 의존 금지 — D4 의 "Spring @Transactional 직접 import 금지" 충족 raw/branch-notes/feature-application-port-usecase-contract D3 (본 D4 와 정합) locally-verified (fixture: TransactionalAnnotatedFixture)
read_only_use_cases_do_not_call_repository_write_methods CleanArchitectureTest.java (D12/D6 섹션) repositoryAccess != WRITE_REPOSITORY use case 가 *Repository 의 write 메서드(save/delete*/update/insert/persist/merge/…) 직접 호출 시 build fail — 선언 vs 실제 호출 정합 feature-repository-access-permission-contract (D12) locally-verified (2026-06-05; fixture ReadOnlyRepositoryWriteUseCase+FixtureRepository). static-analysis 한계 유지: helper/mapper 경유 write 는 미검출 → code-review 보완
bulk_write_capability_requires_write_repository_access CleanArchitectureTest.java (D12/D6 섹션) bulkWrite=truerepositoryAccess=WRITE_REPOSITORY 강제 (registry bound_to_capability) feature-repository-access-permission-contract (D6) locally-verified (2026-06-05; fixture BulkWriteWithoutWriteAccessUseCase)
external_outbound_calls_require_external_outbound_allowed_capability CleanArchitectureTest.java (D7 섹션) externalOutboundAllowed=false use case 가 outbound port(..adapter.outbound.. 구현 인터페이스) 직접 호출 시 build fail. outbound-port 집합은 adapter 바인딩으로 precompute(application-side 마커 불요) feature-repository-access-permission-contract (D7) locally-verified (2026-06-05; fixture OutboundWithoutPermissionUseCase, RepoStatsPort←RepoStatsPortClient 식별). static-analysis 직접 호출 한정
capabilities.yaml ↔ as-built model 1:1 drift 검출 RepositoryAccessCapabilityRegistryTest.java (bootstrap.contract) registry 7 name:RepositoryAccess enum + @UseCaseCapability typed attribute 1:1 매칭. attribute rename/누락·registry 추가/삭제 시 fail. /docs gitignore → skip-on-absence(Assumptions) feature-repository-access-permission-contract locally-verified (2026-06-05; 로컬 yaml 존재 시 7:7 일치 확인, skipped=0)

4. 테스트 계약 realization — 선언 노출 test 만 존재, 위반 차단 test 는 미구현

Trace: 부록 §테스트 계약 5개 주장 + §Decisionized Work Items 의 Required test 열. 현재 코드는 capability 선언이 reflection 으로 읽히는지(UseCaseCapabilityTest)와 annotation 누락 차단만 검증. capability 위반(read-only 가 write, sensitive 무선언 등) 차단 test 는 미작성.

테스트 계약 주장 대응 test (실명/위치) status
capability 선언이 RUNTIME reflection 으로 노출 UseCaseCapabilityTest.exposes_declared_transaction_mode_idempotency_and_repository_access actually-implemented
externalOutbound default=false / 명시 시 true UseCaseCapabilityTest.external_outbound_defaults_to_false… / …readable_when_explicitly_enabled actually-implemented
미선언 use case build fail inbound_port_implementations_declare_capability + MissingCapabilityUseCase locally-verified
read-only use case 가 write repository 사용 시 fail read_only_use_cases_do_not_call_repository_write_methods (D12) + fixture ReadOnlyRepositoryWriteUseCaseArchitectureViolationFixtureTest.read_only_use_cases_do_not_call_repository_write_methods_catches_read_to_write_upgrade locally-verified (2026-06-05; 직접 호출 한정 — static-analysis 한계)
bulkWrite 선언이 WRITE_REPOSITORY 없이 사용 시 fail bulk_write_capability_requires_write_repository_access (D6) + fixture BulkWriteWithoutWriteAccessUseCaseArchitectureViolationFixtureTest.bulk_write_capability_requires_write_repository_access_catches_read_access_bulk locally-verified (2026-06-05)
sensitive/bulk/cross-tenant 플래그 default false / 명시 시 true UseCaseCapabilityTest.sensitive_bulk_and_cross_tenant_flags_default_to_false_when_unspecified / …are_readable_when_explicitly_enabled actually-implemented (2026-06-05)
capabilities.yaml ↔ enum 1:1 매칭 강제 RepositoryAccessCapabilityRegistryTest (registry/enum drift guard) locally-verified (2026-06-05)
sensitive read 무선언 use case 의 sensitive op 차단 (위임 — 메타표·enforcement 는 raw/branch-notes/feature-contract-registry-governance, D5 documented-defer) delegated
transaction required op 이 boundary 없이 실행 시 fail (미구현 — TransactionBoundaryContractTest 부재, application-port 의존) planned
outbound 금지 use case 의 external adapter 호출 차단 external_outbound_calls_require_external_outbound_allowed_capability (D7) + fixture OutboundWithoutPermissionUseCaseArchitectureViolationFixtureTest.external_outbound_calls_require_external_outbound_allowed_capability_catches_unpermitted_call locally-verified (2026-06-05; outbound-port = ..adapter.outbound.. 구현 인터페이스로 식별 — RepoStatsPort←RepoStatsPortClient. 직접 호출 한정)

엣지·실패·의존

R4 캡처. 정상 경로(use case 가 capability 선언 → ArchUnit presence 통과) 외의 실패/엣지/의존.

  • 실패·엣지 경로:
    • 선언 vs 실제 호출 불일치: repositoryAccess = READ_REPOSITORY 인 use case 가 실제로 write 메서드를 호출 — 현재 검출 안 됨(coherence rule 미구현). 선언은 통과하나 의미상 위반. 기대 동작: build fail 이어야 하나 현재 silent pass → planned Claim (D12).
    • member/anonymous class: presence rule 은 areNotInterfaces/areNotAnonymousClasses/areNotMemberClasses 로 제외 — inner static use case 는 강제 대상 아님(UseCaseCapabilityTeststatic final class example 도 직접 평가 대상 아님). 신규 use case 를 inner class 로 작성 시 capability 누락이 통과되는 엣지. → 정책 결론: 신규 use case 는 top-level class 로만 작성(inner static use case 금지)해야 presence rule 이 의미를 가짐.
    • registry row 만 있고 enum 없음: SENSITIVE_READ/BULK_WRITE/CROSS_TENANT_ADMIN 을 코드에서 사용하려 하면 컴파일 불가(enum 부재). registry 를 SSOT 로 믿고 작성하면 좌초 — drift 명시 필요(§Audit F3).
    • KEYED idempotency freeze 해제됨(2026-06-09): 과거 Idempotency.KEYED 선언 시 build fail 하던 freeze 룰은 rate-limit-idempotency branch 머지로 제거(룰+fixture 삭제, KEYED 이제 valid). 본 항목은 history 로만 보존.
  • 다른 계약 의존:

검증해야 할 주장

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

Claim Why uncertain How to verify Status
ArchUnit annotation-based rule 이 모든 use case method 의 capability 선언 강제를 검출 ArchUnit AbsentCapabilityArchitectureTest 미구현 ArchUnit rule 작성 + use case method 에 annotation 누락 시 build fail verify planned
AWS whitepaper sub-page "Authentication is not isolation" + "resource layer enforcement" verbatim 정확성 2026-05-27 sub-page WebFetch truncated archive.org snapshot 또는 manual browser 재확인 needs-confirmation
Hibernate DISCRIMINATOR strategy 하에서 CROSS_TENANT_ADMIN 구현 메커니즘 (CurrentTenantIdentifierResolver override vs Hibernate Filter disable) Hibernate 6 @TenantId 와 CROSS_TENANT_ADMIN 의 통합 패턴 미검증 Hibernate 6 reference + Spring Security 통합 contract test 구현 needs-confirmation
read-only use case 가 write repository capability 사용 시 build fail ArchUnit 또는 annotation processor 미구현 WriteCapabilityViolationTest ArchUnit rule 구현 + 위반 시 build fail verify planned
SENSITIVE_READ capability 가 없는 use case 의 sensitive repository operation 차단 registry-managed metadata table 미구현 sensitive-fields registry yaml + ArchUnit rule 통합 + 위반 시 build fail verify planned
transaction required operation 이 transaction boundary 없이 실행되면 fail TransactionPort contract 미구현 (application-port branch 의존) TransactionBoundaryContractTest 구현 + boundary 없이 실행 시 fail verify planned
outbound 금지 use case 의 external adapter 호출 차단 ArchUnit rule 미구현 OutboundCapabilityViolationTest ArchUnit rule + external adapter 호출 시 build fail verify planned
TRANSACTION_REQUIRED 가 Spring @Transactional 직접 import 로만 충족하면 fail annotation processor 또는 ArchUnit rule 미구현 TransactionPort 사용 강제 ArchUnit rule + Spring annotation 직접 import 시 fail verify planned
BULK_WRITE threshold 100 의 운영 합리성 threshold 의 정량 근거 없음 actual workload 측정 + threshold 조정 (Phase C2 이후) needs-confirmation
7개 Capability enum 이 모든 ca-tmpl use case 패턴 cover 운영 패턴 미완 use case 패턴 카탈로그 작성 + 누락 capability 식별 needs-confirmation
capabilities.yaml SSOT 와 Capability enum 1:1 매칭 강제 registry scan 미구현 enum vs yaml drift 검출 ArchUnit rule 또는 Gradle task 구현 planned

관심사 커버리지

/coverage 가 채우는 생성물 — 손유지 금지. 기준: rules/coverage-gate.md. governing_docs: clean-architecture-package-layout + transaction-boundary-abstraction. 마지막 감사: 2026-06-05 → Covered (Blocking 0 / Should-fix 0 / Advisory 0, coverage-auditor 재감사).

관심사 상태 owner 심각도 근거
use case 가 repository access 능력을 명시 선언 covered-here D1, D11 / RepositoryAccess enum
모든 inbound port 구현체가 capability 선언 강제 (presence rule) delegated raw/branch-notes/feature-application-port-usecase-contract OK inbound_port_implementations_declare_capability (코드 .as() attribution = application-port). 본 branch 는 capability 어휘 SSOT, presence 강제 는 위임 (§Audit F5)
transaction boundary 추상화 (TransactionPort / TransactionMode / @Transactional 금지) delegated raw/branch-notes/feature-application-port-usecase-contract OK D4 / application_does_not_use_spring_transactional_annotation + TransactionMode enum (application/transaction/)
Idempotency 차원 (IDEMPOTENT/KEYED/NOT_IDEMPOTENT) capability ownership delegated raw/branch-notes/feature-application-port-usecase-contract OK Idempotency enum + KEYED-freeze rule (application-port D14). 본 branch capability 어휘 범위 밖 (§Audit F6)
read/write repository 분리 강제 안 함 (메서드 단위 capability) covered-here D10
outbound 호출 능력 명시 + 강제 covered-here D7 / externalOutboundAllowed + external_outbound_calls_require_external_outbound_allowed_capability locally-verified (2026-06-05). outbound-port = adapter 바인딩 식별. 직접 호출 한정
cross-tenant admin 능력 delegated raw/branch-notes/feature-tenant-context-policy OK (미구현) D9 — vocabulary owner 는 본 branch, cross-tenant 정책 의존은 tenant branch
SENSITIVE_READ 메타표(entity FQN+field) + 위반 차단 enforcement delegated raw/branch-notes/feature-contract-registry-governance OK (documented-defer) D5 — 본 branch 는 sensitiveRead 어휘만 소유, 메타표·강제는 registry-governance
repositoryAccess 선언 vs 실제 호출 정합 강제 (coherence) covered-here D12read_only_use_cases_do_not_call_repository_write_methods + bulk_write_capability_requires_write_repository_access locally-verified (2026-06-05). 직접 호출 한정 — helper/mapper 경유는 review 보완

Audit & Findings (2026-06-05 — ca-tmpl 코드 대조)

ca-tmpl src/ ground truth 와 본 노트/registry 대조 결과. 사용자 작성 결정 영역(D2/D11/registry)은 자동 rewrite 하지 않고 정합 권고만 기록(/branch-spec 규칙 §2). 코드가 SSOT.

Finding 유형 노트/registry 코드 (SSOT) 권고
F1 CONTRACT_DRIFTRESOLVED (2026-06-05) annotation 명 @UseCaseRepositoryAccess (D2/D11 원안) @UseCaseCapability (application-core/.../capability/UseCaseCapability.java) D2/D11 노트는 as-built 로 정합 완료. 남은 follow-up (ca-tmpl 레포): capabilities.yaml 6 row 의 annotation: "@UseCaseRepositoryAccess(...)"scope: use_case_method 가 stale — as-built @UseCaseCapability + use_case_class 로 registry-governance owner 가 갱신해야 함.
F2 CONTRACT_DRIFTRESOLVED (2026-06-05) target ElementType.METHOD, value Capability[] flat 7-enum (D11 원안) @Target(TYPE) + 4 typed attribute (transactionMode/idempotency/repositoryAccess/externalOutboundAllowed) D11 as-built 구조로 갱신 완료. flat-enum 모델 superseded.
F3 MISSING_IMPLRESOLVED (2026-06-05) SENSITIVE_READ(D5)/BULK_WRITE(D6)/CROSS_TENANT_ADMIN(D9) — capabilities.yaml row 존재 @UseCaseCapability 의 boolean 속성 sensitiveRead/bulkWrite/crossTenantAdmin (default false) 으로 구현 + UseCaseCapabilityTest reflection 검증. SENSITIVE_READ 메타표(entity-FQN+field)·field-level enforcement 만 raw/branch-notes/feature-contract-registry-governance 위임(D5 documented-defer). 3종 어휘 as-built 완료. RepositoryAccessCapabilityRegistryTest 가 registry 7 row ↔ as-built model 1:1 강제.
F4 MISSING_CONCERNRESOLVED (2026-06-05) §테스트 계약: "read-only 가 write 사용 시 fail" 등 (capability 위반 차단) read_only_use_cases_do_not_call_repository_write_methods(D12) + bulk_write_capability_requires_write_repository_access(D6) ArchUnit 룰 + negative fixtures(ReadOnlyRepositoryWriteUseCase/BulkWriteWithoutWriteAccessUseCase) coherence 강제 구현 완료(locally-verified). 잔여 한계: ArchUnit static-analysis 는 직접 호출만 — helper/mapper 경유 write 미검출은 code-review 보완(D12 §엣지). transaction-boundary 강제는 여전히 application-port TransactionPort 의존.
F5 OWNERSHIP_DRIFT D8: enforcement SSOT = 본 branch presence rule .as() attribution = raw/branch-notes/feature-application-port-usecase-contract D8 을 "vocabulary SSOT = 본 branch / presence 강제 = application-port" 로 분리 명시. 본 branch 는 capability 어휘, application-port 가 선언 강제 owner.
F6 IMPL_NEW_DIMENSION idempotency 차원 노트 capability vocabulary 에 부재 Idempotency {IDEMPOTENT,KEYED,NOT_IDEMPOTENT} 구현 + KEYED-freeze rule idempotency 는 별도 contract(rate-limit-idempotency) 소유 가능 — 본 branch capability vocabulary 와의 경계 확인 권고.

구현 로그

2026-06-05 — Phase C2 as-built (@UseCaseCapability 확장 + coherence/drift 강제)

사용자 결정(2026-06-05 /AskUserQuestion): as-built 확장(flat-enum 재작성 아님) + SENSITIVE_READ 어휘+플래그만(메타표 defer).

  • 변경 파일 (ca-tmpl src/):
    • application-core/.../capability/UseCaseCapability.java — boolean sensitiveRead()/bulkWrite()/crossTenantAdmin() (default false) + coherence/매핑 javadoc.
    • application-core/.../capability/UseCaseCapabilityTest.java — 신규 플래그 default/explicit reflection 검증 2 test + ExampleAdminBulkUseCase fixture.
    • app-bootstrap/.../architecture/CleanArchitectureTest.java — D12 read_only_use_cases_do_not_call_repository_write_methods + D6 bulk_write_capability_requires_write_repository_access + D7 external_outbound_calls_require_external_outbound_allowed_capability 룰 + 3 custom ArchCondition + outbound-port precompute(OUTBOUND_PORT_NAMES, adapter 바인딩 식별) + JavaMethodCall/JavaClasses/ClassFileImporter import.
    • app-bootstrap/.../architecture/violations/application/{FixtureRepository,ReadOnlyRepositoryWriteUseCase,BulkWriteWithoutWriteAccessUseCase,OutboundWithoutPermissionUseCase}.java — negative fixtures (public — .class isolation corpus 가시성).
    • app-bootstrap/.../architecture/ArchitectureViolationFixtureTest.java — isolated corpus 3 + negative assertion 3.
    • app-bootstrap/.../contract/RepositoryAccessCapabilityRegistryTest.java — registry 7 row ↔ as-built model 1:1 drift guard (snakeyaml, skip-on-absence).
    • sample-portfolio/.../application/worklog/BatchCreateWorkLogsUseCase.javabulkWrite = true (canonical bulk write 데모, production-side 룰 positive case).
    • docs/registries/capabilities.yaml (gitignored — 커밋 미포함) — 7 row annotation: 필드 + 헤더를 as-built @UseCaseCapability(...) 표기로 F1/F2 정합.
  • 검증 (cd src):
    • ./gradlew :application-core:test --tests '*UseCaseCapabilityTest' PASS
    • ./gradlew :app-bootstrap:test --tests '*CleanArchitectureTest' / '*ArchitectureViolationFixtureTest' / '*RepositoryAccessCapabilityRegistryTest' PASS, skipped 0. D12/D6/D7 negative test 3종 JUnit XML 확인: tests=3 skipped=0 failures=0 errors=0. 드리프트 테스트 로컬 yaml 7:7 일치.
    • ./gradlew verifyCleanArchitectureDependencies PASS
    • ./gradlew test (full) PASS, 회귀 0
  • 본 branch 소유·정적강제 가능 항목 전부 구현: read/write coherence(D12), bulk coherence(D6), outbound coherence(D7), registry↔model drift, 3 플래그 어휘.
  • 잔여 (cross-branch 위임 — 본 branch 미소유): SENSITIVE_READ entity-FQN+field 메타표·field-level 강제 → raw/branch-notes/feature-contract-registry-governance. transaction-boundary 실행 강제 → raw/branch-notes/feature-application-port-usecase-contract TransactionPort. cross-tenant runtime 정책 → raw/branch-notes/feature-tenant-context-policy.
  • 공통 한계: coherence 룰 3종 모두 ArchUnit static-analysis 직접 호출만 검출 — helper/mapper 경유는 code-review 보완(문서 D12 §엣지 명시).

마주친 문제

  • IDE stale-index false positive: @UseCaseCapability 에 속성 추가 직후 IDE diagnostics 가 bulkWrite is undefined for the annotation type 를 보고. application-core 가 IDE 증분 컴파일러에서 아직 재컴파일되지 않은 stale classpath 문제 — Gradle 빌드가 application-core 를 먼저 재컴파일하여 해소. 코드 오류 아님.
  • .class isolation corpus 가시성: ArchitectureViolationFixtureTest.importClasses(X.class) 로 fixture 를 isolated corpus 로 로드하려면 fixture 가 public 이어야 함(다른 패키지). package-private 로 두면 is not visible 컴파일 오류. importPackages(string) 만 쓰는 기존 fixture 는 package-private 가능 — 참조 방식에 따라 가시성 요건이 다름.

묶음

본 feature branch 는 leaf. 2026-06-05 Phase C2 구현으로 아래 파생 자료 후보 발생.

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

  • 위 §마주친 문제 2건(IDE stale-index, isolation-corpus 가시성) — 둘 다 경미·즉시 해소. 독립 raw/errors/ 노트로 승급할 만큼 재발/심각도 높지 않음 → branch-note 내 기록으로 충분(별도 노트 불요).

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

  • "선언적 capability annotation 의 선언 vs 실제 호출 정합을 어떻게 강제하나? ArchUnit static-analysis 의 한계(helper 경유 호출 미검출)는?" — 본 작업의 D12 coherence 룰이 정직한 답변 소재. 다만 단일 질문 — 독립 interview 노트 승급은 보류, Phase 누적 시 그룹화.

Blog topics

  • "Clean Architecture 에서 repository 접근 권한을 annotation+ArchUnit fitness function 으로 계약화하기 (presence vs coherence vs registry-drift 3층)" — 독립 글감 가능성. 현재는 branch-note 로 충분, canonical 추출 요청 시 분리.

관련 일일 노트

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

  • 2026-06-05 — Phase C2 as-built 구현(위 §구현 로그). (daily note 파일 미생성 — 본 branch-note 가 1차 기록.)

부록 — pre-template 결정 보조 섹션 (registry 참조 보존)

이 노트가 현 템플릿 이전(2026-05-21)에 작성되며 가졌던 섹션들. 내용은 위 Decision Evidence Map / 구현 가이드 / Claims To Verify 로 흡수됐으나, capabilities.yaml 주석이 "판정 기준 / Decisionized Work Items" 를 이름으로 참조하므로 삭제하지 않고 보존한다. 갱신 시 위 정식 섹션이 SSOT — 본 부록은 registry 역참조용 스냅샷.

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

판정 기준

구분 기준
Decision use case가 사용할 수 있는 repository capability를 명시 선언
Allowed AOP 대신 ArchUnit/compile-time checker 사용 가능
Forbidden read-only use case의 write/bulk/sensitive repository 접근
Required capability READ_REPOSITORY, WRITE_REPOSITORY, SENSITIVE_READ, BULK_WRITE, TRANSACTION_REQUIRED, EXTERNAL_OUTBOUND_ALLOWED, CROSS_TENANT_ADMIN
Failure condition 선언되지 않은 repository/outbound capability 사용이 감지되지 않으면 실패

Decisionized Work Items

item Decision Allowed Forbidden Required test
annotation @UseCaseRepositoryAccess default compile-time checker alternative undocumented repo access annotation/rule test
capability enum registry-owned capabilities additive capability with registry row ad hoc string capability registry scan
transaction TRANSACTION_REQUIRED maps to TransactionPort infra Spring implementation direct Spring annotation as proof transaction capability test
sensitive read explicit capability pseudonymized data read without sensitive flag if documented PII read by default sensitive access test
outbound EXTERNAL_OUTBOUND_ALLOWED required domain event without transport hidden HTTP/message call outbound access test

테스트 계약

  • read-only use case가 write repository capability를 사용하면 실패.
  • sensitive read capability가 없는 use case가 sensitive repository operation을 사용하면 실패.
  • transaction required operation이 transaction boundary 없이 실행되면 실패.
  • outbound 금지 use case가 external adapter를 호출하면 실패.
  • TRANSACTION_REQUIRED를 Spring annotation 직접 import로만 충족하면 실패.

완료 후 정리

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