Files
llm-wiki/raw/branch-notes/feature-tenant-context-policy.md
T

19 KiB

title, source_type, status, branch, related_projects, tags, created, target_merge, status_label, id, kind, project, work_item, inherits, refines, overrides, depends_on, contract_packet, parent_branch, contract_packet_sha256
title source_type status branch related_projects tags created target_merge status_label id kind project work_item inherits refines overrides depends_on contract_packet parent_branch contract_packet_sha256
branch / feature-tenant-context-policy branch-note raw feature-tenant-context-policy
ca-skeleton
branch
ca-skeleton
tenant
context
2026-05-22 in-progress BR-CA-SKELETON-OPERATIONAL-CONTRACT-022 project-work-item ca-skeleton-operational-contract WI-CA-SKELETON-OPERATIONAL-CONTRACT-022
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-FRAMEWORK-001@1
1 a951c6ee8f27ba664f1919eab3d9750a969b5d76a0c0bd1a4ccc0d383c1ea699

branch: feature-tenant-context-policy

Layer: raw/branch-notes/ — tenant context 지원/비지원 정책을 정의합니다.

부모 (필수)

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

묶음

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

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

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

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

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

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 1
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: tenant propagation·clear negative fixture가 통과한다

상속한 프로젝트 결정

Decision Ref Project Summary Branch Application Source
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-FRAMEWORK-001@1 framework는 Spring Boot 3.5.14다 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

목표

멀티테넌트를 기본 지원하지 않더라도, 지원하지 않는다는 기준과 tenant header 처리 정책은 필요합니다. tenant context가 암묵적으로 섞이면 repository, log, security, cache key에서 누출 위험이 생깁니다.

  • 이슈:
  • PR:

범위

포함 범위

  • multi-tenancy 지원 여부 명시.
  • tenant header 허용/금지 기준.
  • tenant context propagation 기준.
  • tenant scoped repository는 tenant branch 활성화 시에만 허용.
  • tenant leakage 테스트 기준.
  • log/cache key tenant field 기준.

제외 범위

  • 실제 SaaS tenant model 구현.
  • tenant billing/plan policy.
  • cross-tenant admin feature.

TODO

TODO drained 2026-05-22 — 결정은 아래 "결정 사항" / "Decisionized Work Items" 참조. multi-tenancy 지원 여부 / tenant header 허용/금지 / propagation / tenant scoped repository / leakage test / log·cache key 기준 모두 결정 라인 또는 matrix row로 반영됨. 잔존 TODO 없음.

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

진행 중 메모

  • 지원하지 않는 기능도 out-of-scope로 명시해야 운영 ambiguity가 줄어듭니다.

결정 사항 (decisions)

  • 2026-05-22: tenant context는 명시 정책이 필요.
  • 2026-05-22: skeleton core는 multi-tenancy 미지원이 기본이며 tenant header는 기본 거부.
  • 2026-05-22: tenant 활성화 시 idempotency/rate-limit/cache/log/repository key의 첫 scope는 tenant.
  • 2026-05-22: tenant identifier는 raw PII가 아니어야 하며 log에는 opaque/pseudonymized id만 허용.
  • 2026-05-22: tenant resolution 우선순위 = (1) JWT claim tenant_id (2) 명시적 X-Tenant-Id 헤더 (admin/internal API only) (3) subdomain. 충돌 시 (1) > (2) > (3).
  • 2026-05-22: tenant ID format = opaque ULID (26 chars Crockford base32). UUID/numeric 금지. PII 아닌 opaque token.
  • 2026-05-22: tenant 미지원 모드에서 X-Tenant-Id 헤더 수신 시 400 TENANT_NOT_SUPPORTED (filter 단계). gateway/interceptor가 아닌 Spring Security filter.
  • 2026-05-22: async/event publish 경로 tenant propagation = TaskDecorator + message header tenant_id. consumer-side는 message에서 tenant 복원 후 SecurityContext에 inject. tenant_id는 background-job-async-contract의 TaskDecorator(SSOT)를 통해 async/event boundary에서 전파. 본 branch는 TaskDecorator의 tenant_id field 의무화만 명시. 별도 decorator chain 작성 금지.
  • 2026-05-22: tenant_id ULID 원본은 metric tag에 직접 사용 금지. metric label 표현은 metrics-alerting-contract SSOT (bounded mapping id 또는 cohort bucket). 본 branch는 log/cache/repository scope에서만 ULID 원본 사용.
  • 2026-05-22: repository-access-permission cross-cut = tenant 활성 시 모든 @UseCaseRepositoryAccess 호출은 tenant_id를 query에 자동 필터링. cross-tenant admin은 CROSS_TENANT_ADMIN capability 명시 선언 필요.

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

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

Source 정당화하는 결정
raw/official-docs/multitenancy-aws-saas-tenant-isolation-whitepaper AWS의 Pool model (shared schema with row-level filter
raw/official-docs/multitenancy-hibernate-user-guide Hibernate DISCRIMINATOR strategy (ca-tmpl 채택
raw/company-tech-blogs/multitenancy-atlassian-tenant-context 대규모 shared schema + tenant context 운영 사례
raw/company-tech-blogs/multitenancy-auth0-tenant-resolution JWT claim 우선 + subdomain/header 보조 (ca-tmpl과 정합
raw/company-tech-blogs/multitenancy-subdomain-resolution-patterns
raw/company-tech-blogs/multitenancy-stripe-citus-schema-per-tenant raw/official-docs/multitenancy-hibernate-user-guide (SCHEMA strategy
raw/official-docs/multitenancy-microservices-io-pattern Silo model
raw/official-docs/multitenancy-azure-architecture-patterns raw/company-tech-blogs/multitenancy-hybrid-pooled-siloed-mix
raw/company-tech-blogs/multitenancy-hybrid-pooled-siloed-mix

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

본 branch의 multi-tenancy 결정 (opt-in APP_TENANT_ENABLED + shared DB + tenant_id column + ULID + JWT claim 우선 + X-Tenant-Id header admin only)에 대한 외부 source 조사. 비교 분석은 (예정) wiki/concepts/multi-tenancy-isolation-patterns.md 참조.

Decisionized Work Items

item Decision Allowed Forbidden Required test
support mode disabled by default explicit tenant branch activation silent tenant header acceptance unsupported header test
propagation request context -> application -> repository/cache/log async propagation with context wrapper thread-local leak propagation test
repository tenant-scoped query required when enabled cross-tenant admin with explicit capability missing tenant predicate leakage test
key prefix tenant first no tenant for disabled mode tenant in some keys only key consistency test

테스트 계약

  • tenant 미지원 모드에서 tenant header가 조용히 수용되면 실패.
  • tenant 지원 모드에서 repository query에 tenant scope가 빠지면 실패.
  • tenant id가 PII/secret처럼 과도하게 노출되면 실패.
  • cache key에 tenant scope 기준이 없으면 실패.
  • tenant 활성화 시 idempotency/rate-limit/cache/log principal scope가 서로 다르면 실패.

결정-근거 매핑

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

Decision ID Decision Supporting Claims Evidence Strength Open Risk
D1 tenant context 는 명시 정책 필요 raw/official-docs/multitenancy-aws-saas-tenant-isolation-whitepaper.md#AWS-TENANT-C1 (tenant isolation 은 SaaS 의 fundamental), raw/official-docs/multitenancy-aws-saas-tenant-isolation-whitepaper.md#AWS-TENANT-C2 (boundary breach 는 un-recoverable) official-vendor-doc (AWS whitepaper, 2026-05-27 main page verbatim 재확인) AWS whitepaper Silo/Pool/Bridge sub-page 의 verbatim 정의는 needs-confirmation (2026-05-27 sub-page WebFetch truncated)
D2 skeleton core = multi-tenancy 미지원 기본, tenant header 기본 거부 raw/official-docs/multitenancy-aws-saas-tenant-isolation-whitepaper.md#AWS-TENANT-C1, raw/official-docs/multitenancy-aws-saas-tenant-isolation-whitepaper.md#AWS-TENANT-C2 official-vendor-doc AWS whitepaper 는 "opt-in 기본 거부" 권장을 명시하지 않음 — ca-tmpl 운영 안전 default
D3 tenant 활성화 시 idempotency/rate-limit/cache/log/repository key 의 첫 scope = tenant raw/official-docs/multitenancy-aws-saas-tenant-isolation-whitepaper.md#AWS-TENANT-C6 (Authentication is not isolation; resource layer enforcement — needs-confirmation), raw/official-docs/multitenancy-hibernate-user-guide.md#HBN-MT-C2 (DISCRIMINATOR strategy 공식 지원) needs-confirmation (AWS sub-page) + needs-confirmation (Hibernate body truncated, 구조는 official-vendor-doc 수준 확인) AWS-TENANT-C6 의 verbatim 재확인 실패. Hibernate body verbatim 도 truncated — strategy 존재만 확인
D4 tenant identifier = raw PII 아님, log 에는 opaque/pseudonymized id 만 허용 raw/official-docs/privacy-gdpr-article-25-design.md#GDPR-A25-C1 (pseudonymisation as appropriate measure) — cross-link official-standard Art.25 는 tenant id 의 PII 여부를 명시하지 않음 — ca-tmpl 운영 안전 default
D5 tenant resolution 우선순위 = (1) JWT claim tenant_id (2) X-Tenant-Id header (admin/internal API only) (3) subdomain raw/company-tech-blogs/multitenancy-auth0-tenant-resolution.md#AUTH0-TR-C1 ~ C4 (JWT claim 우선 + subdomain/header 보조), raw/company-tech-blogs/multitenancy-subdomain-resolution-patterns.md#MT-SUBDOM-C1 ~ C7 company-case-study (Auth0 + subdomain 패턴 — 공식 best practice 로 일반화 금지) JWT claim 우선의 official standard 근거 없음. OIDC/JWT spec 의 multi-tenancy 관행 raw 미확보
D6 tenant ID format = opaque ULID (26 chars Crockford base32). UUID/numeric 금지 UNSUPPORTED_DECISION — ULID 표준 spec raw 미확보 (Alizain Feerasta ULID spec 등) none ULID spec raw 등록 시 보강 가능
D7 tenant 미지원 모드에서 X-Tenant-Id 헤더 수신 시 400 TENANT_NOT_SUPPORTED (Spring Security filter) raw/official-docs/multitenancy-aws-saas-tenant-isolation-whitepaper.md#AWS-TENANT-C2 (boundary breach un-recoverable — fail-fast 정당화) official-vendor-doc (간접 근거) AWS whitepaper 는 specific HTTP status 또는 filter layer 를 명시하지 않음 — ca-tmpl 구현 선택
D8 async/event tenant propagation = TaskDecorator + message header tenant_id UNSUPPORTED_DECISION — Spring TaskDecorator reference 또는 OpenTelemetry baggage 표준 raw 미확보 none Spring TaskDecorator / OpenTelemetry baggage spec raw 등록 시 보강 가능
D9 tenant_id ULID 원본은 metric tag 직접 사용 금지 (metrics-alerting-contract SSOT 가 bounded mapping 결정) UNSUPPORTED_DECISION — high-cardinality label 회피 운영 결정. Prometheus 공식 doc raw 미확보 none Prometheus best practices raw 등록 시 보강 가능
D10 repository-access-permission cross-cut = tenant 활성 시 모든 @UseCaseRepositoryAccess 호출에 tenant_id 자동 필터링; cross-tenant admin = CROSS_TENANT_ADMIN capability 필수 raw/official-docs/multitenancy-aws-saas-tenant-isolation-whitepaper.md#AWS-TENANT-C6 (resource layer enforcement — needs-confirmation), raw/official-docs/multitenancy-hibernate-user-guide.md#HBN-MT-C2 (DISCRIMINATOR strategy) needs-confirmation + needs-confirmation AWS sub-page 와 Hibernate body verbatim 모두 재확인 실패. capability 강제 enforcement 자체는 ca-tmpl 고유

검증해야 할 주장

Claim Why uncertain How to verify Status
AWS Silo/Pool/Bridge 정의의 verbatim 정확성 2026-05-27 sub-page WebFetch 가 페이지 title 만 반환 — body truncated archive.org snapshot 으로 sub-page 본문 verbatim 재확인 또는 manual browser 검증 needs-confirmation
AWS "Authentication is not isolation" 의 verbatim 정확성 2026-05-27 sub-page WebFetch 가 body truncated archive.org snapshot 으로 sub-page 본문 verbatim 재확인 또는 manual browser 검증 needs-confirmation
Hibernate 3 strategy (DATABASE/SCHEMA/DISCRIMINATOR) 정의의 verbatim 정확성 WebFetch 가 sub-section 구조만 확인, body truncated archive.org snapshot 으로 Hibernate User Guide chapter 24 본문 verbatim 재확인 또는 manual browser 검증 needs-confirmation
@TenantId annotation 적용 시 entity 별 강제 여부 (opt-in 모델과 호환) Hibernate 6 native 지원이라는 본문 verbatim 미확인 Hibernate 6 reference doc + 실제 entity 에 적용 후 자동 필터 동작 contract test needs-confirmation
CurrentTenantIdentifierResolver 의 ThreadLocal vs SecurityContextHolder 선택 Spring Security 와의 통합 검증 미완 Spring Security SecurityContextHolder 와 Hibernate resolver 통합 + thread-local leak 테스트 planned
JWT claim tenant_id 우선이 OIDC/JWT 표준 multi-tenancy 관행 OIDC/JWT multi-tenancy spec raw 미확보 RFC 7519 (JWT) + RFC 7517 (JWK) + OIDC multi-tenancy 가이드 raw 등록 needs-confirmation
ULID format opaqueness 가 PII 분류 회피 보장 ULID spec 의 timestamp 추출 가능성 (앞 48-bit) ULID spec raw 등록 + timestamp embed 의 PII risk 평가 needs-confirmation
TaskDecorator + message header tenant_id propagation 의 thread-local leak 차단 비동기 경로 leak 테스트 미완 TenantPropagationContractTest 구현 + @Async / Kafka publish 시 tenant_id leak 안 함 verify planned
cache key tenant_id 우선 prefix 가 모든 cache 접근 경로에서 동작 cache-consistency-contract 연동 미검증 CacheKeyTenantScopeTest 구현 + Redisson / Caffeine 접근 시 tenant prefix 강제 verify planned
migration trigger (tenant 수 수백~수천 + row 수억 → schema-per-tenant) 의 정량 기준 본 raw 의 비교 핵심은 일반 가이드. 실제 정량 trigger 미정 tenant 증가 추이 + Citus / schema-per-tenant migration runbook 작성 needs-confirmation

마주친 문제

  • 아직 없음.

구현 가이드

  • ingress에서 검증한 tenant ID를 immutable context로 캡처하고 use case·outbound call에 명시적으로 전달한다.
  • thread reuse·async handoff 전후에는 capture/restore/clear를 짝지어 이전 요청의 context가 남지 않게 한다.
  • repository query와 cache key에는 같은 tenant scope를 적용하고 누락 시 fail-closed한다.

엣지·실패·의존

  • context clear 누락은 cross-tenant data leak로 이어질 수 있으며 background job에는 요청 context가 없다는 별도 경계가 필요하다.
  • authentication·runtime context propagation·persistence auditing 계약과 함께 검증한다.

관련 일일 노트

  • 별도 일일 노트 없음.

완료 후 정리

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