init: llm-wiki-haness 하네스 설계

This commit is contained in:
DongHyeonka
2026-07-24 14:21:35 +09:00
parent 42bf3db4fd
commit 6c53ded9cb
2436 changed files with 194486 additions and 1 deletions
@@ -0,0 +1,125 @@
---
title: ca-tmpl - Multi-tenancy 결정 (opt-in shared DB + tenant_id)
source_type: project
status: verified
confidence: high
tags: [ca-tmpl, multi-tenancy, saas, actually-implemented, locally-verified, documented-only]
related_projects: [ca-tmpl]
last_reviewed: 2026-07-02
---
# ca-tmpl - Multi-tenancy 결정 (opt-in shared DB + tenant_id)
> Layer: `wiki/projects/` — 내 프로젝트 사실. 일반 개념은 [[wiki/concepts/multi-tenancy-isolation-patterns]] 참조.
## 프로젝트 컨텍스트
ca-tmpl(Clean Architecture skeleton)에서 multi-tenancy를 어떻게 다룰지 정한 결정 문서다. baseline은 다음 조합이다.
- **opt-in**: `APP_TENANT_ENABLED=true`일 때만 tenant 로직 활성. single-tenant deployment에서는 비활성화하여 skeleton 적용 범위를 넓힘.
- **shared DB + `tenant_id` column (ULID)**: AWS Pool 모델 / Hibernate DISCRIMINATOR 전략에 해당.
- **Tenant resolution**: JWT claim 우선, `X-Tenant-Id` header는 **admin only(`CROSS_TENANT_ADMIN` capability 보유자)** 에 한해 허용.
- B2B 초기 단계(tenant 수 수십~수백 단위) 가정. isolation 비용 대비 운영 단순성 우선.
**현재 진행 상태**: tenant-aware registry/runbook/capability/idempotency scope 일부 구현 + repository tenant filter는 planned. 본 문서는 구현된 tenant support surface와 아직 없는 storage isolation enforcement를 분리한다.
## 실제 구현 내용 (`actually-implemented`)
- `docs/registries/env-keys.yaml``APP_TENANT_ENABLED`, `docs/registries/headers.yaml``X-Tenant-Id`, `docs/registries/capabilities.yaml``CROSS_TENANT_ADMIN`, `docs/registries/error-codes.yaml`에 tenant error code가 존재한다.
- `docs/runbooks/authz-tenant-mismatch.md`, `docs/runbooks/authz-cross-tenant-violation.md`가 cross-tenant incident response stub을 제공한다.
- `AuthorizationPrincipal`, `RequiresPermission`, `AuthorizationPort`, role/permission registry와 `AuthorizationContractTest`가 capability 기반 authorization foundation을 제공한다.
- `IdempotencyScope``IdempotencyKeySupport`는 tenant-aware scope를 표현할 수 있다.
- repository-level tenant predicate 강제, tenant resolver filter, storage isolation은 아직 구현되지 않았다.
## 로컬/dev 검증 (`locally-verified`)
- `./gradlew check` 통과(2026-07-02, `BUILD SUCCESSFUL`, 114 tasks).
- `AuthorizationContractTest`, `IdempotencyScopeTest`, `IdempotencyKeySupportTest`, registry governance tests가 tenant/capability/registry surface 일부를 검증한다.
- repository tenant filter와 cross-tenant E2E isolation은 검증되지 않았다.
## 운영 검증 (`prod-verified`)
**없음.** ca-tmpl은 skeleton이며 prod 배포 이력 없음.
## 문서/계획만 존재 (`documented-only` / `planned`)
### Tenant resolution + isolation 정책 (partially-implemented)
- JWT claim 우선 → admin only `X-Tenant-Id` header fallback → 해석 실패 시 reject.
- repository 진입점에서 tenant filter 강제(`CROSS_TENANT_ADMIN` capability 없이는 모든 query에 `tenant_id` predicate).
- **status: partially-implemented** — registry/header/capability/runbook/idempotency scope는 존재하지만 repository filter와 tenant resolver filter는 planned.
### 6종 대안 검토 → Pool 채택
검토한 6가지와 채택/기각 사유:
| 대안 | 분류 | 채택 여부 | 사유 |
|------|------|-----------|------|
| **shared DB + tenant_id** (ULID) | AWS Pool / Hibernate DISCRIMINATOR | **채택** | B2B 초기, tenant 수 수십~수백 예상. 운영 단순성. |
| subdomain-based | resolution-only | 기각 | wildcard DNS/TLS·subdomain takeover·local dev 비용. resolution은 isolation을 보장하지 않음. |
| JWT claim only (storage 분리 없음) | resolution-only | 기각 | claim 검증 누락 시 cross-tenant leak. storage layer 강제 필요. |
| schema-per-tenant | Hibernate SCHEMA | 기각 | catalog bloat·`search_path` 전환 plan cache 무효화·HikariCP 설계 복잡. 초기 단계 ROI 부정. |
| db-per-tenant | AWS Silo | 기각 | 운영 비용 폭증(마이그레이션·백업·connection pool 폭발). 규제 요구 부재. |
| hybrid (Azure Deployment Stamps / AWS Bridge) | mixed | 기각 | 운영 복잡도 최고. PMF 이후 단계 검토 사항. |
근거: ca-tmpl은 skeleton이며 초기 도입 대상은 B2B 소규모 SaaS. 결정은 verified 되었지만 storage isolation enforcement는 아직 planned다.
### Migration trigger 3가지 정의
shared DB → schema/db-per-tenant로 전환을 검토할 조건:
1. **규제**: 금융·의료(HIPAA·FedRAMP·data residency) isolation 강제.
2. **규모**: tenant 수 hundreds 도달 + 단일 row 수 억대 진입(noisy neighbor·index 비용 임계).
3. **상품 tier**: enterprise tier 등장으로 isolation을 가격에 반영해야 할 때.
**status: documented-only** — migration trigger는 아직 관측 지표/자동 경보로 구현되지 않았다.
### `CROSS_TENANT_ADMIN` capability 정의
- admin/support 운영 동선용. 보유자만 `X-Tenant-Id` header로 tenant 전환 가능.
- 일반 사용자 경로는 JWT claim 단독, header 무시.
- **status: partially-implemented** — capability vocabulary와 authorization foundation은 존재하지만, repository tenant filter와 admin tenant switching E2E는 미구현.
## 면접에서 말할 수 있는 범위
### 자신 있게
- "Pool / Silo / Bridge의 차이와 각각의 비용·isolation trade-off."
- "tenant resolution에서 JWT claim과 `X-Tenant-Id` header의 trust 차이, header를 admin only로 제한하는 이유."
- "shared DB → 격리 강화 모델로 가는 **migration trigger 3가지**(규제 / 규모 / enterprise tier)."
### 적당히
- ULID vs UUID 선택 이유(정렬 가능성·index locality·시간 정보 노출 trade-off).
- Hibernate multi-tenancy strategy(DATABASE / SCHEMA / DISCRIMINATOR) 차이와 `CurrentTenantIdentifierResolver` 동작 개요.
### 답하면 안 됨 (모른다고 해야 함)
- "tenant 격리를 어떻게 **측정**했는가" — 측정·테스트 부재.
- "cross-tenant 침해 시도/penetration test 결과" — 수행 안 함.
- "schema-per-tenant 운영 경험" — 검토만 했고 운영해 본 적 없음.
- "실제 tenant 수, row 수, 성능 지표" — skeleton에 데이터 없음.
## 과장 금지 지점
- "shared DB + tenant_id가 항상 우월하다" → 금지. 규제 산업(HIPAA·금융·data residency)에서는 Silo가 사실상 강제다. 본 선택은 **B2B 초기 단계 가정에 종속된 결정**이라는 점을 함께 말할 것.
- **Stripe/Citus schema-per-tenant 한계치 단언 금지** — 정확 인용 wording이 미완(raw 자료 `needs-confirmation`). "수백~수천 단위에서 catalog overhead가 보고된다" 정도로 출처와 함께만 언급.
- "ca-tmpl에 multi-tenancy를 **완성했다**" → 금지. tenant-aware registry/capability/scope foundation은 구현됐지만, repository-level tenant filter와 E2E isolation은 planned다.
- "JWT claim만 검증하면 안전하다" → 금지. repository 레벨 tenant filter가 별도로 필요하다.
- "Atlassian이 그렇게 하니까 best practice" → 금지. company-tech-blog는 관점이지 공식 기준이 아니다.
## 관련 개념
- [[wiki/concepts/multi-tenancy-isolation-patterns]] — Pool/Silo/Bridge, Hibernate strategy, resolution 방식 공식 기준
## Sources
- [[raw/project-notes/ca-skeleton-operational-contract]] — §10 Repository Access Permission Contract, §29 Topic 6 Multi-tenancy Isolation
- [[raw/branch-notes/feature-tenant-context-policy]] — tenant resolution(JWT > header admin only) SSOT
- [[raw/branch-notes/feature-repository-access-permission-contract]] — `CROSS_TENANT_ADMIN` capability, repository 레벨 tenant filter contract
## Cluster / 묶음
<!-- GENERATED: derived-blogs:start -->
- [[wiki/blog/ca-tmpl-multi-tenancy-isolation-patterns-2026-07-02]]
<!-- GENERATED: derived-blogs:end -->