필사 모드: SaaS 아키텍처 완전 가이드 — Multi-tenancy·Billing·Feature Flag·Audit·RBAC·SSO를 2025년 기준으로 한 번에 정리
한국어프롤로그 — "API를 SaaS로 팔려면?"
당신에게 훌륭한 API(Ep 19)가 있다. 이걸 **SaaS(Software as a Service)**로 팔려면?
"그냥 signup 페이지 만들고 Stripe 연결하면 되죠?" — 2018년이라면.
2025년엔 더 어려워졌다:
- **Multi-tenancy**: 고객 데이터 격리는 기본값
- **Billing**: 월 구독, 사용량, 연간 할인, prorated 변경
- **Feature Flag**: 일부 고객만 새 기능
- **Audit Log**: 엔터프라이즈가 요구
- **RBAC/SSO**: Admin/Viewer 권한, SAML 로그인
- **SOC 2**: 보안 감사 준수
- **Usage Metering**: API call당 과금
- **Data Export**: 고객이 언제든 자기 데이터 가져가야
좋은 SaaS는 **차별화된 기능**이 아니라 **신뢰할 수 있는 플랫폼**에서 시작한다.
이 글은 Season 2 Ep 20 — **SaaS 아키텍처**.
Multi-tenant 전략, Billing, Feature Flag, Audit, RBAC/ABAC, SSO, Usage Metering까지.
1부 — Multi-tenancy 3전략
1. Silo (격리) — DB per tenant
Tenant A → DB-A
Tenant B → DB-B
Tenant C → DB-C
**장점**:
- 강한 격리
- Tenant별 성능/보안/규정 분리
- "한 고객 데이터가 다른 고객에게 유출" 불가능
**단점**:
- 비용 (DB 수백 개)
- 마이그레이션 지옥 (스키마 변경 시 모든 DB)
- 엔터프라이즈 단독 고객 적합
**사용처**: 금융, 의료, 정부. 고가 플랜.
2. Pool (공유) — 같은 DB, tenant_id로 구분
CREATE TABLE users (
id UUID PRIMARY KEY,
tenant_id UUID NOT NULL,
email TEXT,
...
);
CREATE INDEX idx_users_tenant ON users(tenant_id);
**Row-Level Security (Postgres)**:
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON users
USING (tenant_id = current_setting('app.current_tenant')::UUID);
**장점**:
- 비용 효율
- 마이그레이션 쉬움
- 스타트업 친화
**단점**:
- 격리 약함 (코드 버그 시 cross-tenant 유출 위험)
- Noisy neighbor (한 tenant가 DB 독점)
- 규정 어려움
3. Bridge (하이브리드) — 플랜별 구분
Free, Starter: Pool DB
Pro: Pool DB + 격리된 schema
Enterprise: Silo (dedicated DB)
**현실의 표준**. 성장 단계별 다른 모델.
Schema-per-tenant (Postgres 특화)
CREATE SCHEMA tenant_abc;
CREATE TABLE tenant_abc.users (...);
-- connection string: search_path=tenant_abc,public
**장점**: 코드는 Pool, 격리는 Silo 중간
**단점**: Postgres는 스키마 1000+개부터 느려짐
테넌트 식별 전략
방법 1: Subdomain (acme.example.com)
방법 2: Path prefix (/t/acme/...)
방법 3: Header (X-Tenant-ID)
방법 4: JWT claim
**2025 권장**: Subdomain + JWT claim (안전 2중 확인).
Middleware 패턴
// Express middleware
async function tenantMiddleware(req, res, next) {
const subdomain = req.hostname.split('.')[0];
const tenant = await db.tenant.findFirst({ where: { slug: subdomain } });
if (!tenant) return res.status(404).json({ error: 'Tenant not found' });
req.tenant = tenant;
// Row-Level Security용 세션 변수
await db.$executeRaw`SET LOCAL app.current_tenant = ${tenant.id}`;
next();
}
2부 — Billing 시스템 설계
과금 모델 5가지
| 모델 | 예시 | 특징 |
|---|---|---|
| **Flat-rate** | Basecamp | 단순, seat 무제한 |
| **Per-seat** | Slack, Notion | 사용자 수 |
| **Tiered** | Stripe, Twilio | 사용량 구간별 |
| **Usage-based** | AWS, OpenAI | API call당, 저장량 |
| **Hybrid** | 기본 + 초과분 | 현실의 표준 |
도구 비교
| 도구 | 특징 |
|---|---|
| **Stripe Billing** | 구독 + usage, 세금 자동(Stripe Tax), 사실상 표준 |
| **Lago** (오픈소스) | Event-driven, self-host, 복잡한 pricing 유연 |
| **Metronome** | 복잡 usage-based SaaS 전용 |
| **Paddle** | Merchant of Record, 세금/환불 대행 |
| **Chargebee** | 엔터프라이즈, 복잡한 workflow |
| **RevenueCat** | 모바일 앱 구독 전용 |
| **Orb** | Usage-based 2024 신흥 |
Stripe Billing 모델
Product — 논리적 상품 ("Pro Plan")
└── Price — 실제 가격 ("Pro Monthly $10")
└── Subscription — 고객의 구독
└── Invoice — 월마다 생성
└── Charge — 실제 결제
Usage-based 구현
// 사용자가 API 호출할 때
await stripe.subscriptionItems.createUsageRecord(
subscriptionItem.id,
{
quantity: 1, // 또는 배치 처리 후 총합
timestamp: Math.floor(Date.now() / 1000),
action: 'increment',
}
);
**2025 best practice**: Stripe의 usage를 실시간 X, **배치(시간당/일일)**로 집계 후 전송. 이벤트 로그 자체 보관.
흔한 함정
1. **Upgrade/Downgrade prorated** — 계산 복잡, Stripe 자동 OK
2. **무료 trial → paid 전환** — 실패 처리 (카드 만료, 잔액 부족)
3. **Tax 처리** — 한국 부가세, EU VAT, 미국 주별 세금
4. **Dunning** (연체 추심) — 실패 시 3-7-14일 재시도
5. **Refund + partial refund**
6. **Chargeback** (사용자가 카드사에 이의 제기)
Revenue Recognition (매출 인식)
$120/연 일시불 → 매출 인식은 매월 $10씩 12개월
이유: 서비스 제공 시점에 매출 인식 (GAAP/IFRS)
도구: Stripe Revenue Recognition, Sage Intacct
3부 — Feature Flag
왜 필요한가
배포 = 릴리즈 분리
- 배포는 코드가 서버에 가는 것
- 릴리즈는 사용자에게 보이는 것
- Feature Flag가 둘을 분리
**혜택**:
- **Canary**: 1% → 10% → 50% → 100%
- **Kill switch**: 장애 시 즉시 끄기
- **A/B 테스트**: 버전 A vs B 비교
- **Premium feature**: 플랜별 기능 다르게
- **Dark launch**: 내부만 먼저
도구 비교
| 도구 | 특징 |
|---|---|
| **LaunchDarkly** | 시장 선도, 비쌈 |
| **Unleash** (오픈소스) | Self-host, 기업 친화 |
| **Flagsmith** | Self-host + Cloud |
| **PostHog** | Feature flag + Analytics 통합 |
| **Statsig** | A/B 테스트 강력 |
| **ConfigCat** | 단순, 저렴 |
| **OpenFeature** | **CNCF 표준 인터페이스** |
OpenFeature — 벤더 중립 표준
const client = OpenFeature.getClient();
const showNewFeature = await client.getBooleanValue('new-feature', false, {
targetingKey: user.id,
email: user.email,
plan: user.plan,
});
**장점**: LaunchDarkly ↔ Unleash ↔ PostHog 교체 시 코드 변경 최소.
규칙 예시
flag: new-checkout-flow
defaultValue: false
rules:
- if: plan == "enterprise"
then: true
- if: email endsWith "@example.com"
then: true
- percentage: 10 # 10%
then: true
안티패턴
1. **Flag debt** — 오래된 플래그 수천 개 → 분기 지옥
2. **Flag 안에 또 flag** → 테스트 불가
3. **Kill switch만 쓰고 제거 안 함** → 영구 코드
4. **매 요청 flag 서비스 호출** → 지연 폭발 (SDK는 캐싱 필수)
Cleanup 전략
Flag 생성 시 deprecation date 설정
30일 후 자동 알림
90일 후 강제 제거 issue 생성
4부 — Audit Log 설계
왜 필요한가
- **SOC 2**, **ISO 27001**, **GDPR** 요구
- **보안 사고 포렌식**
- **내부 조사** (누가 뭘 언제 했나)
- **고객 요구** (엔터프라이즈 필수)
이벤트 포맷 (CloudEvents 호환)
{
"id": "aud_01HX...",
"specversion": "1.0",
"type": "user.permission.granted",
"source": "/api/users/123",
"time": "2026-04-15T12:34:56Z",
"subject": "usr_abc",
"data": {
"actor": { "type": "user", "id": "usr_admin", "email": "admin@example.com" },
"target": { "type": "user", "id": "usr_abc" },
"action": "permission.granted",
"before": { "role": "viewer" },
"after": { "role": "admin" },
"ip": "1.2.3.4",
"userAgent": "...",
"requestId": "req_xyz"
}
}
저장소 선택
옵션 1: Postgres (간단한 경우)
+ ACID, 기존 DB
- 스케일 한계
옵션 2: ClickHouse / BigQuery (대규모)
+ 빠른 분석
- 별도 시스템
옵션 3: S3 + Athena (아카이브)
+ 매우 저렴
- 쿼리 느림
옵션 4: 전용 SaaS (Vanta, OneSchema)
**2025 패턴**: Primary는 Postgres, 30일 이후 S3 아카이브, ClickHouse로 분석.
위변조 방지
- **Append-only**: UPDATE/DELETE 금지, 트리거로 강제
- **Hash chain**: 블록체인 아이디어 (각 레코드가 이전 hash 포함)
- **Database-level audit**: pgaudit, AWS RDS audit
- **WORM storage**: Write Once Read Many (S3 Object Lock)
쿼리 UX
고객이 볼 수 있는 Audit Log UI:
- Filter: actor, action, date range, resource
- Export: CSV, JSON
- Webhook: 특정 이벤트 발생 시 알림
민감정보 처리
- 비밀번호, 토큰은 **절대 기록 X**
- PII는 **해시화 또는 마스킹**
- GDPR: 사용자 삭제 시 audit log는 **보존 의무**와 충돌 → 법무 확인
5부 — RBAC vs ABAC vs PBAC
RBAC (Role-Based) — 간단
Role: Admin, Editor, Viewer
Permission: read/write/delete + resource
Admin → 모든 권한
Editor → read/write
Viewer → read only
**장점**: 단순, 이해 쉬움
**단점**: 세밀한 권한 표현 어려움 ("A 프로젝트만 편집")
ABAC (Attribute-Based) — 유연
rule: allow if
user.role == "editor" AND
resource.owner == user.id AND
environment.ip.country == "KR"
**도구**:
- **OPA (Open Policy Agent)** + Rego
- **Cedar** (AWS, 2023)
- **Casbin**
- **Oso**
Cedar 예시
permit(
principal == User::"alice",
action == Action::"read",
resource
) when {
resource.owner == principal ||
resource.sharedWith.contains(principal)
};
RBAC 구현 (Postgres)
CREATE TABLE roles (id UUID PRIMARY KEY, name TEXT);
CREATE TABLE permissions (id UUID PRIMARY KEY, action TEXT, resource TEXT);
CREATE TABLE role_permissions (role_id UUID, permission_id UUID, PRIMARY KEY (role_id, permission_id));
CREATE TABLE user_roles (user_id UUID, role_id UUID, PRIMARY KEY (user_id, role_id));
실전 조합
Core RBAC (Admin/Editor/Viewer)
+ Resource-level permissions (Project membership)
+ Attribute rules (Time, IP, MFA)
2025 도구
- **Permit.io**, **Oso**, **Cerbos** — 권한 SaaS
- **Clerk, Kinde, WorkOS** — 인증 + 권한 SaaS
6부 — SSO (Single Sign-On)
왜 엔터프라이즈가 요구
- **IT 관리**: 직원 입/퇴사 시 한 곳(Okta, Entra)에서 관리
- **보안**: MFA 한 번, 모든 앱 공통
- **감사**: 중앙 로그
프로토콜
| 프로토콜 | 연식 | 특징 |
|---|---|---|
| **SAML 2.0** | 2005 | 엔터프라이즈 표준, XML |
| **OIDC (OpenID Connect)** | 2014 | OAuth 2.0 기반, JSON, 현대적 |
| **OAuth 2.0** | 2012 | 인증 아닌 인가 (자주 혼동) |
| **SCIM** | 2015 | 사용자 프로비저닝 (직원 입/퇴사) |
SAML 기본 흐름
1. 사용자 → SP (Service Provider, 우리 SaaS)
2. SP → IdP (Identity Provider, Okta)로 redirect
3. IdP: 사용자 인증 (MFA)
4. IdP → 브라우저 → SP로 SAML Response 전달
5. SP: 서명 검증 → 세션 생성
OIDC 기본 흐름
Authorization Code + PKCE:
1. Client → /authorize (IdP)
2. 사용자 로그인
3. IdP → Client로 code 반환
4. Client → /token으로 code 교환 → access_token + id_token(JWT)
구현 방법
**옵션 1: 직접 구현**
- `passport-saml`, `openid-client`
- 장점: 통제
- 단점: 복잡, 고객별 설정 지옥
**옵션 2: SSO SaaS (2025 권장)**
- **WorkOS**: B2B SSO 전문
- **Clerk**: SSO + 인증 전반
- **Auth0 (Okta)**: 엔터프라이즈
- **Supabase Auth, Firebase Auth**: 스타트업
**장점**: 수백 개 IdP 통합 지원, IT 관리자 셀프 서비스 UI.
SCIM — 자동 프로비저닝
회사 A가 직원 50명 입사:
Okta → SCIM → 우리 SaaS에 자동 생성
직원 퇴사 시:
Okta → SCIM → 계정 비활성화
수동 관리 안 해도 됨 (엔터프라이즈 필수)
7부 — Usage Metering
이벤트 수집 파이프라인
App → Kafka/Kinesis → Aggregator → Billing engine → Invoice
↓
Analytics DB (ClickHouse)
설계 원칙
1. **이벤트는 불변** (절대 수정 X)
2. **멱등성**: 같은 event_id 두 번 받아도 1번 계산
3. **Idempotency 윈도우**: 중복 제거 7일까지
4. **Ordered? No**: 분산 시스템에서 순서 기대 X
5. **Granularity**: 원본 이벤트 보관 (집계만 보관하면 회귀 불가)
Aggregation 예시
-- 시간별 집계 (ClickHouse)
SELECT
tenant_id,
toStartOfHour(timestamp) as hour,
count() as api_calls,
sum(bytes) as bytes_total
FROM events
WHERE timestamp >= today()
GROUP BY tenant_id, hour;
Lago / Metronome
Lago (오픈소스):
- Event ingestion API
- Aggregation (count, sum, max, unique)
- Pricing rules (tier, package, graduated)
- Invoice 자동 생성
- Stripe 연동
Metronome (상용):
- 더 복잡한 enterprise pricing
- Commitment, Credits 모델
8부 — Customer Data Isolation
Tenant-level Encryption
각 tenant마다 고유 암호화 키
Master Key → Tenant Key (envelope encryption)
Tenant Key로 데이터 암호화
장점: 규정 (HIPAA, PCI) 만족
도구: AWS KMS, HashiCorp Vault
BYOK (Bring Your Own Key)
엔터프라이즈 고객이 자신의 KMS 키 가져옴 → 해지 시 데이터 사용 불가.
Data Residency
미국 고객 → US region
EU 고객 → EU region (GDPR)
한국 고객 → AP region (금융 규정)
구현: tenant 레코드에 region 저장 → 라우팅
복잡: cross-region 백업, 장애 조치
9부 — SOC 2, ISO 27001, GDPR
SOC 2 (미국 엔터프라이즈 필수)
Type I: 설계 감사 (한 시점)
Type II: 운영 감사 (6-12개월)
5 Trust Services Criteria:
- Security (필수)
- Availability
- Processing Integrity
- Confidentiality
- Privacy
**핵심 요구**:
- 접근 제어 (MFA, 최소 권한)
- 변경 관리 (Code review, CI)
- 침입 탐지 (SIEM)
- Audit log
- 백업 + DR
- Vendor management
도구
- **Vanta, Drata, Secureframe**: SOC 2 자동화 ($20K-50K/년)
- **Vanta AI Questionnaire**: 보안 설문 자동 응답
GDPR (EU)
- **Data export** (right to access)
- **Data deletion** (right to be forgotten)
- **Consent** (cookie banner)
- **DPA** (Data Processing Agreement)
- **Breach notification** (72시간 이내)
코드에 녹여놓기
// 사용자 삭제
async function deleteUser(userId: string) {
await db.$transaction(async (tx) => {
await tx.user.update({
where: { id: userId },
data: {
email: `deleted-${userId}@example.com`,
name: 'Deleted User',
phoneNumber: null,
deletedAt: new Date(),
},
});
await tx.session.deleteMany({ where: { userId } });
await tx.auditLog.create({
data: { action: 'user.deleted', userId, ... },
});
});
// 비동기: 백업, S3, 외부 시스템 삭제
await jobs.enqueue('gdpr.delete', { userId });
}
10부 — Onboarding과 Activation
Time-to-Value (TTV) 최소화
좋은 SaaS의 목표: 회원가입 → 첫 "와우" 순간까지 5분 이내
나쁜 예:
1. 회원가입 → 이메일 인증 (5분)
2. 긴 설정 위저드 (10분)
3. 샘플 데이터 직접 추가 (20분)
좋은 예:
1. Google OAuth (10초)
2. 샘플 프로젝트 자동 생성
3. 즉시 "와우" 경험
체크리스트 패턴
"완료 진행 4/10"
- [x] 프로필 작성
- [x] 팀 초대
- [ ] 첫 프로젝트 만들기
- [ ] Integration 연결
...
Product Tour
- **Intro.js, Shepherd.js** — 오픈소스
- **Pendo, Userflow, Chameleon** — SaaS
Empty States
Before: "No data" (나쁨)
After: "첫 프로젝트를 만들어 보세요" + 가이드 + 샘플 템플릿
11부 — Analytics와 Observability
3가지 Analytics
1. **Product Analytics** — Mixpanel, Amplitude, PostHog
2. **Marketing Analytics** — GA4, Plausible (privacy)
3. **Business Metrics** — MRR, Churn, LTV (Baremetrics, ChartMogul)
SaaS KPI 10개
| 지표 | 설명 |
|---|---|
| MRR (Monthly Recurring Revenue) | 예측 가능한 월 매출 |
| ARR | 연 매출 (MRR × 12) |
| Churn | 이탈률 (월 5% = 위험) |
| Net Revenue Retention (NRR) | 기존 고객 매출 유지/확장 |
| CAC (Customer Acquisition Cost) | 고객 획득 비용 |
| LTV (Lifetime Value) | 고객 생애 가치 |
| LTV:CAC | 3:1 이상 권장 |
| Payback Period | CAC 회수 기간 |
| Activation Rate | 가입 → 핵심 행동 % |
| DAU/MAU | 참여도 |
PostHog — 오픈소스 올인원
posthog.init('<api_key>', { api_host: 'https://app.posthog.com' });
posthog.identify(user.id, { email: user.email, plan: user.plan });
posthog.capture('project_created', { project_id: '...', template: 'blank' });
**기능**: Events, Feature Flag, Session Replay, A/B test, Heatmap, Funnels.
12부 — 운영 체크리스트
Day-one SaaS Checklist
- [ ] Multi-tenant 모델 결정 (Pool/Silo/Bridge)
- [ ] Stripe Billing + Webhook
- [ ] SSO 준비 (OIDC + SAML 지원)
- [ ] Audit Log 인프라
- [ ] Feature Flag (OpenFeature + 벤더)
- [ ] Rate Limiting per tenant
- [ ] Email (Resend, Postmark) + template
- [ ] Support chat (Intercom, Crisp, Front)
- [ ] Docs (Mintlify, Docusaurus)
- [ ] Status page (Atlassian Statuspage, Better Stack)
- [ ] Uptime monitoring (Pingdom, Better Uptime)
- [ ] Error tracking (Sentry)
- [ ] Analytics (PostHog)
- [ ] SOC 2 준비 (Vanta)
Day-1K Customers Checklist
- [ ] 다중 리전 배포
- [ ] Dedicated enterprise 인프라
- [ ] BYOK (Bring Your Own Key)
- [ ] SCIM 프로비저닝
- [ ] IP allowlist per tenant
- [ ] Data export API
- [ ] 24/7 on-call rotation
- [ ] SLA 문서
- [ ] ISO 27001, SOC 2 Type II
13부 — 6개월 로드맵
**1개월차**: Multi-tenant 모델 결정, RLS(Postgres) 적용, 기본 인증
**2개월차**: Stripe Billing, Webhook, Subscription lifecycle
**3개월차**: Feature Flag (OpenFeature), Audit Log 기본
**4개월차**: SSO (OIDC + SAML), WorkOS 연동, SCIM 기본
**5개월차**: RBAC + ABAC(OPA), tenant-level encryption
**6개월차**: SOC 2 준비 (Vanta), Data export, GDPR 대응
14부 — 체크리스트 12개
- [ ] Multi-tenant 데이터 격리 (RLS or 분리 DB)
- [ ] Stripe Billing + 재시도 + Dunning
- [ ] Feature Flag 도구 도입 (OpenFeature)
- [ ] Audit Log 수집 + 보관 정책
- [ ] RBAC + Resource-level permission
- [ ] SSO (OIDC 기본, SAML 엔터프라이즈)
- [ ] SCIM 프로비저닝
- [ ] Rate Limiting per tenant
- [ ] Data export (GDPR)
- [ ] SOC 2 준비 (Vanta)
- [ ] Status page + uptime monitor
- [ ] PostHog 또는 Mixpanel로 product analytics
15부 — 안티패턴 10가지
1. **Multi-tenancy를 나중에 결정** → 재구조화 지옥
2. **Billing을 직접 구현** → 세금, 환불, prorated에서 자멸
3. **Feature Flag 없이 배포** → Kill switch 없는 장애
4. **Audit Log 없음** → 엔터프라이즈 포기
5. **RBAC 없이 if문 분기** → 권한 지옥
6. **SSO 안 지원** → 엔터프라이즈 영업 실패
7. **Free plan에 제한 없음** → 악용 + 비용 폭탄
8. **Data export 없음** → 고객 락인 불만
9. **Rate limit 없음** → API 남용 + DB 부하
10. **SOC 2 "나중에"** → 큰 계약 놓침
마무리 — "SaaS는 신뢰 게임"
2025년 SaaS의 본질은 **신뢰**:
- 데이터 격리 = 신뢰
- Audit Log = 신뢰
- SSO/SCIM = 기업 IT 신뢰
- SOC 2 = 감사 신뢰
- Status page = 투명성
- Feature Flag = 점진적 신뢰
"기능 더 많이"가 아니라 **"덜 망가지고, 안전하게, 예측 가능하게"**가 엔터프라이즈 판매의 본질.
Season 2의 기술 딥다이브는 여기까지. 다음은 **기술을 넘어선** 것들.
다음 글은 Season 2 Ep 21 — **엔지니어링 매니지먼트 완전 가이드**.
1:1, 피드백, Hiring, Performance Review, Tech Debt 협상, IC → Manager 전환까지.
시스템을 만들었다면, **시스템을 만드는 사람들**을 이끄는 법.
다음 글 예고 — "엔지니어링 매니지먼트 완전 가이드: 1:1·피드백·Hiring·Tech Debt·Career Ladder"
Season 2 Ep 21은:
- 1:1 미팅 베스트 프랙티스
- Feedback: SBI, Radical Candor
- Hiring: Scorecard, Interview Loop
- Performance Review + Calibration
- Tech Debt 협상 (Product와)
- IC vs Manager trade-offs
- Career Ladder (Junior → Staff → Principal)
- 팀 건강 (Retention, Burnout)
코드보다 사람이 더 복잡하다. 다음 글에서.
현재 단락 (1/452)
당신에게 훌륭한 API(Ep 19)가 있다. 이걸 **SaaS(Software as a Service)**로 팔려면?