Skip to content
Skip to content
CHIMBUK.

Try flutter, ai, pricing or sudoku

[Engineering Insights]SaaS

Building a production B2B micro-SaaS: multi-tenant schema, Stripe billing, and audit logs

Building a multi-tenant SaaS requires three foundational decisions: tenant data isolation, billing state synchronization without race conditions, and compliance audit logging. A battle-tested blueprint.

Chimbuk Engineering Studio10 min readPeer Reviewed

Every developer wants to build a SaaS. Most fail not because the product idea was flawed, but because the foundational architecture was built like a single-user prototype: tenant data mixed in flat tables without isolation guarantees, Stripe webhooks handled synchronously with intermittent dropping, and no audit trail for business compliance.

Tenant isolation: PostgreSQL Row Level Security (RLS)

Separating tenant data with database-per-tenant is operationally expensive at small scale. Mixing tenants in one database without enforcement leads to catastrophic data leaks when someone forgets a WHERE tenant_id = ? clause. PostgreSQL Row Level Security provides the sweet spot: single database, shared tables, but hardware-enforced isolation at the database engine level.

sql
-- Enable RLS on core application table
ALTER TABLE workspaces ENABLE ROW LEVEL SECURITY;
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;

-- Tenant policy: current session user can only see rows from their active tenant
CREATE POLICY tenant_isolation_policy ON projects
  AS RESTRICTIVE
  FOR ALL
  TO authenticated_app_user
  USING (tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid);

-- Next.js connection pool hook before executing query
-- SET LOCAL app.current_tenant_id = 'c4b8b9f1-3329-4e78-831d-b657497d3ef2';

Stripe subscription state synchronization

Never gate feature access by querying the Stripe API in your request pipeline. Stripe API calls add 200–600ms of latency and create an external availability dependency. Your database must store the synchronized subscription state: plan tier, status ('active', 'past_due', 'canceled'), current period end, and seat count. All webhook processing must be idempotent.

typescript
// Idempotent Stripe webhook subscription handler
export async function handleSubscriptionUpdated(subscription: Stripe.Subscription) {
  const customerId = subscription.customer as string;
  const tenant = await db.tenant.findUnique({ where: { stripeCustomerId: customerId } });
  
  if (!tenant) throw new Error(`Tenant missing for customer ${customerId}`);

  const currentPriceId = subscription.items.data[0]?.price.id;
  const plan = mapPriceToPlan(currentPriceId);

  await db.tenantSubscription.upsert({
    where: { tenantId: tenant.id },
    create: {
      tenantId: tenant.id,
      stripeSubscriptionId: subscription.id,
      status: subscription.status,
      plan: plan,
      currentPeriodEnd: new Date(subscription.current_period_end * 1000),
      cancelAtPeriodEnd: subscription.cancel_at_period_end,
    },
    update: {
      status: subscription.status,
      plan: plan,
      currentPeriodEnd: new Date(subscription.current_period_end * 1000),
      cancelAtPeriodEnd: subscription.cancel_at_period_end,
    },
  });
}

Compliance audit trails: write-only append logs

Enterprise B2B clients demand audit logs for SOC2 and GDPR compliance. Who invited a new member? Who exported the customer dataset? Who updated the billing card? We model audit trails as append-only tables with JSONB diffs, protected from UPDATE and DELETE operations by database triggers.

Architecting a SaaS for B2B scale from commit one saves you from painful data migrations later. Row-level security for tenant safety, local subscription caching for speed, and append-only audit trails for enterprise credibility.

CK
Chimbuk Engineering StudioVerified Engineering

Field notes authored by the core engineering and systems team at Chimbuk. We build and maintain production Flutter mobile applications, Next.js web architectures, and cloud backends. No recycled marketing theory — only architecture decisions, code patterns, and performance budgets from real production deployments.

Share:
★★★★★4.9 Clutch & Google Reviews

We architect and build the systems we write about.

From vector search pipelines to high-concurrency payment gateways — schedule a technical discovery call.