7.8 KiB
7.8 KiB
title, source_type, status, confidence, tags, related_projects, last_reviewed
| title | source_type | status | confidence | tags | related_projects | last_reviewed | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ca-tmpl - Multi-tenancy 결정 (opt-in shared DB + tenant_id) | project | verified | high |
|
|
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_idcolumn (ULID): AWS Pool 모델 / Hibernate DISCRIMINATOR 전략에 해당. - Tenant resolution: JWT claim 우선,
X-Tenant-Idheader는 admin only(CROSS_TENANT_ADMINcapability 보유자) 에 한해 허용. - 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-Idheader fallback → 해석 실패 시 reject. - repository 진입점에서 tenant filter 강제(
CROSS_TENANT_ADMINcapability 없이는 모든 query에tenant_idpredicate). - 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로 전환을 검토할 조건:
- 규제: 금융·의료(HIPAA·FedRAMP·data residency) isolation 강제.
- 규모: tenant 수 hundreds 도달 + 단일 row 수 억대 진입(noisy neighbor·index 비용 임계).
- 상품 tier: enterprise tier 등장으로 isolation을 가격에 반영해야 할 때.
status: documented-only — migration trigger는 아직 관측 지표/자동 경보로 구현되지 않았다.
CROSS_TENANT_ADMIN capability 정의
- admin/support 운영 동선용. 보유자만
X-Tenant-Idheader로 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-Idheader의 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_ADMINcapability, repository 레벨 tenant filter contract