Skip to content

필사 모드: SaaS 아키텍처 완전 가이드 — Multi-tenancy·Billing·Feature Flag·Audit·RBAC·SSO를 2025년 기준으로 한 번에 정리

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

프롤로그 — "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)**로 팔려면?

작성 글자: 0원문 글자: 12,452작성 단락: 0/452