Files
2nd/10_Wiki/Topics/DevOps_and_Security/SaaS (Software as a Service).md
T
2026-05-10 22:08:15 +09:00

5.4 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-saas-software-as-a-service SaaS (Software as a Service) 10_Wiki/Topics verified self
Software as a Service
Multi-tenant SaaS
Cloud Software
none A 0.9 applied
business-model
cloud
multi-tenant
devops
2026-05-10 pending
language framework
typescript stripe-postgres

SaaS (Software as a Service)

매 한 줄

"매 software 의 매 product 가 매 service 가 된다". SaaS 는 매 vendor-hosted 매 multi-tenant application 의 매 subscription 으로 매 deliver — 매 install 없음, 매 patch 없음, 매 elastic. Salesforce(1999) 가 매 시작, 2026 현재 매 vertical SaaS (industry-specific) 가 매 horizontal 을 매 outpace; 매 AI-native SaaS (Cursor, Linear AI) 가 매 per-seat → 매 outcome-based pricing 으로 매 transition 중.

매 핵심

매 Architecture archetypes

  • Pool model: 매 single DB, 매 tenant_id column. 매 cheapest, 매 noisy-neighbor risk.
  • Bridge model: 매 schema-per-tenant. 매 isolation 좋음, 매 migration 복잡.
  • Silo model: 매 DB-per-tenant. 매 max isolation, 매 expensive.
  • Hybrid: free tier pool, enterprise silo.

매 Economics

  • MRR/ARR: monthly/annual recurring revenue.
  • Churn: gross (lost) vs net (incl. expansion).
  • CAC payback: < 12 months 매 healthy.
  • NRR (Net Revenue Retention): > 110% 매 best-in-class.

매 응용

  1. CRM (Salesforce, HubSpot).
  2. Dev tools (GitHub, Vercel).
  3. Vertical (Toast — restaurant, Veeva — pharma).
  4. AI-native (Cursor, Granola, Linear).

💻 패턴

Tenant isolation (Postgres RLS)

CREATE TABLE invoices (
  id uuid PRIMARY KEY,
  tenant_id uuid NOT NULL,
  amount_cents integer NOT NULL
);
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON invoices
  USING (tenant_id = current_setting('app.current_tenant')::uuid);

-- Per-request
SET LOCAL app.current_tenant = 'abc-123';
SELECT * FROM invoices; -- only abc-123's rows

Stripe subscription webhook

import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_KEY!);

app.post("/webhook", async (req, res) => {
  const event = stripe.webhooks.constructEvent(
    req.rawBody, req.headers["stripe-signature"]!, process.env.STRIPE_WH_SECRET!
  );
  switch (event.type) {
    case "customer.subscription.updated":
      await db.tenant.update({
        where: { stripeCustomerId: event.data.object.customer },
        data: { plan: event.data.object.items.data[0].price.lookup_key },
      });
      break;
    case "customer.subscription.deleted":
      await scheduleTenantOffboarding(event.data.object.customer);
      break;
  }
  res.json({ received: true });
});

Feature flag per plan

const PLAN_FEATURES = {
  free: ["basic_export"],
  pro: ["basic_export", "api_access", "sso"],
  enterprise: ["basic_export", "api_access", "sso", "audit_log", "custom_domain"],
};
function hasFeature(tenant: Tenant, feature: string): boolean {
  return PLAN_FEATURES[tenant.plan]?.includes(feature) ?? false;
}

Usage metering (event-based)

async function recordUsage(tenantId: string, metric: string, qty: number) {
  await db.usageEvent.create({ data: { tenantId, metric, qty, ts: new Date() } });
  await stripe.subscriptionItems.createUsageRecord(
    tenant.stripeSubItemId,
    { quantity: qty, timestamp: Math.floor(Date.now() / 1000), action: "increment" }
  );
}

Per-tenant rate limit

import { Ratelimit } from "@upstash/ratelimit";
const limiters = new Map<string, Ratelimit>();
function getLimiter(tenant: Tenant) {
  const limit = tenant.plan === "enterprise" ? 1000 : 100;
  if (!limiters.has(tenant.id)) {
    limiters.set(tenant.id, new Ratelimit({
      redis, limiter: Ratelimit.slidingWindow(limit, "1 m"),
    }));
  }
  return limiters.get(tenant.id)!;
}

매 결정 기준

상황 Tenancy model
매 SMB, 매 < $50 ARR / tenant Pool (RLS)
매 mid-market Bridge (schema-per)
매 enterprise, 매 compliance Silo (DB-per or single-tenant cluster)
매 AI inference heavy Pool + per-tenant queue

기본값: Pool with RLS, escape-hatch to silo for enterprise.

🔗 Graph

🤖 LLM 활용

언제: Onboarding email personalization, churn-risk classification from usage signals, customer success summary, AI copilot as product feature. 언제 X: 매 contract pricing — human sales.

안티패턴

  • No tenant_id: 매 cross-tenant data leak — 매 existential.
  • Single noisy tenant: 매 1 enterprise = 매 80% load → 매 SLO collapse for all. 매 tier-isolate.
  • Free forever: 매 conversion 0% → 매 unit economics 의 매 broken.
  • Hand-rolled billing: edge case 의 매 hell. Stripe / Lago / Orb 의 매 사용.

🧪 검증 / 중복

  • Verified (AWS SaaS Lens 2024, OpenView SaaS Benchmarks, Tomasz Tunguz reports).
  • 신뢰도 A.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — multi-tenant + AI-native SaaS 2026