mdxui

SaaS Products

Multi-tenant subscription software with workspaces, billing, and feature management

SaaS Products

SaaS (Software-as-a-Service) products are subscription-based applications with web interfaces for human users. They typically charge Monthly Recurring Revenue (MRR) and include both a UI application and programmatic API access. Modern SaaS products are multi-tenant, supporting workspaces, role-based access control, usage metering, and feature flags.


Characteristics

AspectValue
Revenue ModelMRR (Monthly Recurring Revenue)
PricingPer seat, per tier, or usage-based subscription
Primary InterfaceWeb application (human UI)
Secondary InterfaceREST/GraphQL API
Target UserHumans (with optional API access)
ArchitectureMulti-tenant with workspace isolation
Example ComponentsDashboard, Settings, Admin Panel

Multi-Tenant Architecture

SaaS products serve multiple customers (tenants) from a single application instance. Each tenant's data is isolated and secure.

Tenant Isolation Models

Shared Database, Shared Schema

// All tenants share tables, rows filtered by tenant_id
interface User {
  id: string
  tenantId: string              // Workspace/organization ID
  email: string
  role: 'owner' | 'admin' | 'member'
}

// All queries must filter by tenant
const users = await db.users.findMany({
  where: { tenantId: currentTenant.id }
})

Shared Database, Separate Schemas

// Each tenant has their own schema
const tenant = await getTenant(tenantId)
const schema = `tenant_${tenant.id}`

await db.raw(`SET search_path TO ${schema}`)
const users = await db.users.findMany()  // Automatically scoped

Separate Databases

// Each tenant has dedicated database
const tenant = await getTenant(tenantId)
const db = connectToDatabase(tenant.databaseUrl)
const users = await db.users.findMany()  // Complete isolation

Workspace Management

Workspaces (or organizations) are the primary tenant container:

interface Workspace {
  id: string
  name: string
  slug: string                  // acme-corp
  ownerId: string               // User who created workspace
  plan: 'free' | 'starter' | 'pro' | 'enterprise'
  subscriptionId?: string       // Stripe subscription
  settings: WorkspaceSettings
  createdAt: Date
  updatedAt: Date
}

interface WorkspaceSettings {
  // Branding
  logo?: string
  primaryColor?: string

  // Features
  features: {
    apiAccess: boolean
    sso: boolean
    customDomain: boolean
    auditLogs: boolean
  }

  // Limits (based on plan)
  limits: {
    seats: number               // Max users
    storage: number             // GB
    apiRequests: number         // Per month
  }

  // Usage tracking
  usage: {
    seats: number               // Current users
    storage: number             // Current GB used
    apiRequests: number         // This month
  }
}

Workspace Switching

// User can belong to multiple workspaces
interface WorkspaceMembership {
  id: string
  workspaceId: string
  userId: string
  role: 'owner' | 'admin' | 'member' | 'viewer'
  invitedBy?: string
  joinedAt: Date
}

// Component with workspace context
<WorkspaceSwitcher>
  {workspaces.map(workspace => (
    <WorkspaceOption
      key={workspace.id}
      workspace={workspace}
      isActive={workspace.id === currentWorkspace.id}
      onClick={() => switchWorkspace(workspace.id)}
    />
  ))}
</WorkspaceSwitcher>

MDXLD Definition

---
$context: https://schema.org.ai
$type: Product
$id: https://acme.com/products/saas
name: Acme Platform
type: SaaS
business: https://acme.com
description: All-in-one project management platform
isActive: true

# Categorization
industries:
  - B2B SaaS
  - Project Management
productCategories:
  - Collaboration Platform
  - Task Management

# Interfaces
interfaces:
  hasAPI: true
  hasRPC: true
  hasMCP: false
  hasSDK: true
  hasCLI: true

# Pricing Tiers
prices:
  - $id: price_starter
    name: Starter
    amount: 1900
    currency: USD
    type: subscription
    interval: month
    features:
      - Up to 10 users
      - 10 GB storage
      - Basic analytics
  - $id: price_pro
    name: Professional
    amount: 4900
    currency: USD
    type: subscription
    interval: month
    features:
      - Up to 50 users
      - 100 GB storage
      - Advanced analytics
      - API access
  - $id: price_enterprise
    name: Enterprise
    amount: 19900
    currency: USD
    type: subscription
    interval: month
    features:
      - Unlimited users
      - Unlimited storage
      - Enterprise analytics
      - Priority support
      - SSO & SAML
---

# {name}

{description}

<Hero title={name} subtitle={description} />
<Features product={$id} />
<Pricing prices={prices} />
<Testimonials product={$id} />

User Roles and Permissions

Multi-tenant SaaS requires role-based access control (RBAC) to manage what users can do within workspaces.

Role Hierarchy

type Role = 'owner' | 'admin' | 'member' | 'viewer'

interface RolePermissions {
  role: Role
  permissions: Permission[]
  description: string
}

const roleHierarchy: RolePermissions[] = [
  {
    role: 'owner',
    description: 'Full control, cannot be removed',
    permissions: [
      'workspace:delete',
      'workspace:transfer',
      'billing:manage',
      'members:*',
      'settings:*',
      'data:*',
    ]
  },
  {
    role: 'admin',
    description: 'Manage workspace and members',
    permissions: [
      'workspace:update',
      'members:invite',
      'members:remove',
      'members:update',
      'settings:update',
      'data:*',
    ]
  },
  {
    role: 'member',
    description: 'Standard user access',
    permissions: [
      'data:read',
      'data:create',
      'data:update',
      'data:delete',      // Only their own data
      'settings:read',
    ]
  },
  {
    role: 'viewer',
    description: 'Read-only access',
    permissions: [
      'data:read',
      'settings:read',
    ]
  }
]

Permission Checking

// Middleware to check permissions
function requirePermission(permission: string) {
  return async (req, res, next) => {
    const { user, workspace } = req

    const membership = await db.workspaceMemberships.findFirst({
      where: {
        userId: user.id,
        workspaceId: workspace.id
      }
    })

    if (!membership) {
      throw new ForbiddenError('Not a member of this workspace')
    }

    const hasPermission = checkPermission(membership.role, permission)

    if (!hasPermission) {
      throw new ForbiddenError(`Missing permission: ${permission}`)
    }

    next()
  }
}

// Usage
app.delete('/api/workspaces/:id',
  requireAuth,
  requirePermission('workspace:delete'),
  deleteWorkspace
)

Custom Permissions

Advanced SaaS products support custom roles and granular permissions:

interface CustomRole {
  id: string
  workspaceId: string
  name: string
  description?: string
  permissions: string[]           // Custom permission strings
  isDefault: boolean
}

interface Permission {
  resource: string                // 'projects', 'users', 'billing'
  action: 'create' | 'read' | 'update' | 'delete' | 'manage'
  scope?: 'own' | 'team' | 'workspace'
}

// Example: Project Manager role
const projectManagerRole: CustomRole = {
  id: 'role_pm',
  workspaceId: 'ws_123',
  name: 'Project Manager',
  permissions: [
    'projects:*',               // All project actions
    'tasks:*',                  // All task actions
    'members:read',             // View members
    'teams:read',               // View teams
    'reports:read',             // View reports
  ],
  isDefault: false
}

Team-Based Permissions

interface Team {
  id: string
  workspaceId: string
  name: string
  description?: string
  members: TeamMember[]
}

interface TeamMember {
  userId: string
  teamId: string
  role: 'lead' | 'member'
}

// Resource can be owned by team
interface Project {
  id: string
  workspaceId: string
  teamId?: string               // Team ownership
  ownerId?: string              // Individual ownership
  isPublic: boolean             // Visible to entire workspace
}

// Check if user has access to resource
function canAccessProject(user: User, project: Project): boolean {
  // Workspace admins can access everything
  if (user.workspaceRole === 'admin' || user.workspaceRole === 'owner') {
    return true
  }

  // Public projects visible to all members
  if (project.isPublic) {
    return true
  }

  // Owner can access
  if (project.ownerId === user.id) {
    return true
  }

  // Team members can access team projects
  if (project.teamId && user.teams.includes(project.teamId)) {
    return true
  }

  return false
}

Billing Integration

SaaS products integrate with billing providers (typically Stripe) to manage subscriptions and payments.

Stripe Integration

interface StripeIntegration {
  // Product mapping
  stripeProductId: string         // prod_...

  // Price IDs for each tier
  prices: Array<{
    id: string
    stripePriceId: string         // price_...
    name: string                  // 'Starter', 'Pro', 'Enterprise'
    amount: number
    interval: 'month' | 'year'
    features: string[]
  }>
}

// Create Stripe customer when workspace is created
async function createWorkspace(data: CreateWorkspaceInput) {
  const workspace = await db.workspaces.create(data)

  // Create Stripe customer
  const customer = await stripe.customers.create({
    email: data.ownerEmail,
    name: data.name,
    metadata: {
      workspaceId: workspace.id
    }
  })

  await db.workspaces.update({
    where: { id: workspace.id },
    data: { stripeCustomerId: customer.id }
  })

  return workspace
}

// Create subscription
async function subscribe(workspaceId: string, priceId: string) {
  const workspace = await db.workspaces.findUnique({
    where: { id: workspaceId }
  })

  const subscription = await stripe.subscriptions.create({
    customer: workspace.stripeCustomerId,
    items: [{ price: priceId }],
    metadata: {
      workspaceId: workspace.id
    }
  })

  await db.workspaces.update({
    where: { id: workspaceId },
    data: {
      subscriptionId: subscription.id,
      plan: getPlanFromPrice(priceId),
      subscriptionStatus: subscription.status
    }
  })

  return subscription
}

Webhook Handling

// Handle Stripe webhooks
app.post('/api/webhooks/stripe', async (req, res) => {
  const sig = req.headers['stripe-signature']

  const event = stripe.webhooks.constructEvent(
    req.body,
    sig,
    process.env.STRIPE_WEBHOOK_SECRET
  )

  switch (event.type) {
    case 'customer.subscription.created':
    case 'customer.subscription.updated':
      await handleSubscriptionUpdate(event.data.object)
      break

    case 'customer.subscription.deleted':
      await handleSubscriptionCanceled(event.data.object)
      break

    case 'invoice.payment_succeeded':
      await handlePaymentSuccess(event.data.object)
      break

    case 'invoice.payment_failed':
      await handlePaymentFailed(event.data.object)
      break
  }

  res.json({ received: true })
})

async function handleSubscriptionUpdate(subscription: Stripe.Subscription) {
  const workspaceId = subscription.metadata.workspaceId

  await db.workspaces.update({
    where: { id: workspaceId },
    data: {
      subscriptionStatus: subscription.status,
      currentPeriodEnd: new Date(subscription.current_period_end * 1000)
    }
  })
}

Usage-Based Billing

// Track metered usage for hybrid pricing
interface UsageRecord {
  workspaceId: string
  metric: string                  // 'api_requests', 'storage_gb'
  quantity: number
  timestamp: Date
}

// Report usage to Stripe
async function reportUsage(workspaceId: string) {
  const workspace = await db.workspaces.findUnique({
    where: { id: workspaceId }
  })

  // Get usage for this billing period
  const usage = await db.usageRecords.aggregate({
    where: {
      workspaceId,
      timestamp: {
        gte: workspace.currentPeriodStart,
        lt: workspace.currentPeriodEnd
      },
      metric: 'api_requests'
    },
    _sum: { quantity: true }
  })

  // Report to Stripe
  const subscription = await stripe.subscriptions.retrieve(
    workspace.subscriptionId
  )

  const usageItem = subscription.items.data.find(
    item => item.price.lookup_key === 'api_requests'
  )

  if (usageItem) {
    await stripe.subscriptionItems.createUsageRecord(
      usageItem.id,
      {
        quantity: usage._sum.quantity,
        timestamp: Math.floor(Date.now() / 1000),
        action: 'set'
      }
    )
  }
}

Billing Components

// Auto-wired billing components
<Billing workspace={currentWorkspace}>
  <CurrentPlan />
  <UsageMetrics />
  <UpgradePlan />
  <PaymentMethod />
  <BillingHistory />
  <Invoices />
</Billing>

Feature Flags

Feature flags control which features are available to workspaces based on their plan or rollout status.

Feature Flag System

interface FeatureFlag {
  id: string
  name: string
  description: string
  type: 'boolean' | 'plan_based' | 'rollout' | 'custom'
  enabled: boolean

  // Plan-based features
  plans?: Array<'free' | 'starter' | 'pro' | 'enterprise'>

  // Rollout features
  rolloutPercentage?: number

  // Custom logic
  evaluator?: (workspace: Workspace) => boolean
}

const features: FeatureFlag[] = [
  {
    id: 'api_access',
    name: 'API Access',
    description: 'Programmatic API access',
    type: 'plan_based',
    enabled: true,
    plans: ['pro', 'enterprise']
  },
  {
    id: 'sso',
    name: 'Single Sign-On',
    description: 'SAML/SSO authentication',
    type: 'plan_based',
    enabled: true,
    plans: ['enterprise']
  },
  {
    id: 'advanced_analytics',
    name: 'Advanced Analytics',
    description: 'Custom dashboards and reports',
    type: 'rollout',
    enabled: true,
    rolloutPercentage: 50,    // 50% of workspaces
  },
  {
    id: 'ai_features',
    name: 'AI Features',
    description: 'AI-powered suggestions',
    type: 'custom',
    enabled: true,
    evaluator: (workspace) => {
      // Custom logic
      return workspace.plan === 'enterprise' || workspace.betaAccess
    }
  }
]

Feature Checking

// Check if workspace has feature
function hasFeature(workspace: Workspace, featureId: string): boolean {
  const feature = features.find(f => f.id === featureId)

  if (!feature || !feature.enabled) {
    return false
  }

  switch (feature.type) {
    case 'boolean':
      return true

    case 'plan_based':
      return feature.plans?.includes(workspace.plan) ?? false

    case 'rollout':
      // Consistent hash-based rollout
      const hash = hashWorkspaceId(workspace.id)
      const threshold = (feature.rolloutPercentage ?? 0) / 100
      return hash < threshold

    case 'custom':
      return feature.evaluator?.(workspace) ?? false

    default:
      return false
  }
}

// Usage in components
function APIKeysPage() {
  const { workspace } = useWorkspace()

  if (!hasFeature(workspace, 'api_access')) {
    return <UpgradePrompt feature="API Access" />
  }

  return <APIKeysList />
}

Feature Flag Component

// Declarative feature flag component
<FeatureFlag feature="sso" workspace={workspace}>
  <SSOSettings />
</FeatureFlag>

// With fallback
<FeatureFlag
  feature="advanced_analytics"
  workspace={workspace}
  fallback={<UpgradePrompt />}
>
  <AdvancedAnalytics />
</FeatureFlag>

Remote Feature Flags

// Use external feature flag service (LaunchDarkly, etc.)
import { LDClient } from 'launchdarkly-node-server-sdk'

const ldClient = LDClient.initialize(process.env.LAUNCHDARKLY_SDK_KEY)

async function hasFeature(workspace: Workspace, featureId: string) {
  const context = {
    kind: 'workspace',
    key: workspace.id,
    name: workspace.name,
    plan: workspace.plan,
    customAttributes: {
      createdAt: workspace.createdAt.toISOString(),
      memberCount: workspace.memberCount
    }
  }

  return await ldClient.variation(featureId, context, false)
}

Usage Metering

Track and limit resource usage based on workspace plan limits.

Metering Infrastructure

interface UsageMetric {
  workspace: string
  metric: string                  // 'api_requests', 'storage', 'seats'
  value: number
  timestamp: Date
  metadata?: Record<string, any>
}

// Track usage
async function trackUsage(
  workspaceId: string,
  metric: string,
  value: number,
  metadata?: Record<string, any>
) {
  await db.usageMetrics.create({
    data: {
      workspace: workspaceId,
      metric,
      value,
      timestamp: new Date(),
      metadata
    }
  })

  // Check if limit exceeded
  await checkUsageLimit(workspaceId, metric)
}

// Check limits
async function checkUsageLimit(workspaceId: string, metric: string) {
  const workspace = await db.workspaces.findUnique({
    where: { id: workspaceId }
  })

  const limit = workspace.settings.limits[metric]

  if (!limit) return

  const usage = await getCurrentUsage(workspaceId, metric)

  if (usage >= limit) {
    // Send notification
    await notifyLimitExceeded(workspace, metric, usage, limit)

    // Optionally block further usage
    throw new Error(`${metric} limit exceeded`)
  }

  // Warn at 80%
  if (usage >= limit * 0.8) {
    await notifyApproachingLimit(workspace, metric, usage, limit)
  }
}

// Get current usage
async function getCurrentUsage(
  workspaceId: string,
  metric: string
): Promise<number> {
  const workspace = await db.workspaces.findUnique({
    where: { id: workspaceId }
  })

  // For current billing period
  const result = await db.usageMetrics.aggregate({
    where: {
      workspace: workspaceId,
      metric,
      timestamp: {
        gte: workspace.currentPeriodStart,
        lt: workspace.currentPeriodEnd
      }
    },
    _sum: { value: true }
  })

  return result._sum.value ?? 0
}

Usage Components

// Display usage metrics
<UsageMetrics workspace={workspace}>
  <UsageCard
    metric="seats"
    current={workspace.settings.usage.seats}
    limit={workspace.settings.limits.seats}
    label="Team Members"
  />
  <UsageCard
    metric="storage"
    current={workspace.settings.usage.storage}
    limit={workspace.settings.limits.storage}
    label="Storage"
    unit="GB"
  />
  <UsageCard
    metric="api_requests"
    current={workspace.settings.usage.apiRequests}
    limit={workspace.settings.limits.apiRequests}
    label="API Requests"
    period="month"
  />
</UsageMetrics>

Rate Limiting

// API rate limiting per workspace
import rateLimit from 'express-rate-limit'
import RedisStore from 'rate-limit-redis'

function createWorkspaceLimiter(workspace: Workspace) {
  const limit = workspace.settings.limits.apiRequestsPerMinute ?? 60

  return rateLimit({
    windowMs: 60 * 1000,          // 1 minute
    max: limit,
    keyGenerator: (req) => `workspace:${workspace.id}`,
    store: new RedisStore({
      client: redis,
    }),
    handler: (req, res) => {
      res.status(429).json({
        error: 'Rate limit exceeded',
        limit,
        retryAfter: 60
      })
    }
  })
}

// Usage
app.use('/api/*', async (req, res, next) => {
  const workspace = req.workspace
  const limiter = createWorkspaceLimiter(workspace)
  limiter(req, res, next)
})

Component Structure

SaaS products render as full applications:

Site Components (Marketing)

import type { SiteComponents } from 'mdxui'

// Marketing site for the SaaS
<Site product={saasProduct}>
  <Header />
  <LandingPage>
    <Hero />
    <Features />
    <Pricing />
    <Testimonials />
    <CTA />
  </LandingPage>
  <Footer />
</Site>

App Components (Application)

import type { AppComponents } from 'mdxui'

// The actual SaaS application
<App product={saasProduct}>
  <Shell>
    <Sidebar />
    <Header />
    <Dashboard />
  </Shell>
</App>

Typical Features

Core Features

FeatureDescriptionTier
User ManagementInvite, roles, permissionsAll
Team CollaborationWorkspaces, projects, tasksAll
File StorageUpload and manage filesAll
NotificationsEmail, in-app, webhooksAll
AnalyticsUsage insights and metricsPro+
API AccessProgrammatic accessPro+
SSO/SAMLEnterprise authenticationEnterprise
SLA & SupportGuaranteed uptime and responseEnterprise

Auto-Wired Features

// These components auto-wire to Payload collections
<Team product={$id} />           // teams collection
<APIKeys product={$id} />        // apiKeys collection
<Webhooks product={$id} />       // webhooks collection
<Usage product={$id} />          // usage collection
<Billing product={$id} />        // subscriptions collection
<Settings product={$id} />       // settings collection

Pricing Models

Per-Seat Pricing

Charge based on number of users:

interface SeatBasedPricing {
  type: 'subscription'
  interval: 'month' | 'year'
  amount: number          // e.g., $29 per seat
  minSeats?: number       // Minimum seats required
  maxSeats?: number       // Maximum seats allowed
}

Example: $29/user/month, minimum 5 users

Tiered Pricing

Different feature sets at different price points:

interface TieredPricing {
  tiers: Array<{
    name: string          // Starter, Pro, Enterprise
    amount: number        // $0, $49, $199
    features: string[]    // List of included features
    limits: {
      seats?: number      // User limit
      storage?: number    // Storage limit (GB)
      requests?: number   // API request limit
    }
  }>
}

Example: Free, Starter ($19), Pro ($49), Enterprise (Custom)

Usage-Based Subscription

Base subscription + usage charges:

interface UsageBasedPricing {
  baseAmount: number              // $49/month base
  usageCharges: Array<{
    metric: string                // 'api_requests', 'storage_gb'
    amount: number                // $0.01 per request
    includedQuantity?: number     // First 10,000 free
  }>
}

Example: $49/month + $0.01 per API request over 10,000


Business Model

Metrics

Key SaaS metrics:

interface SaaSMetrics {
  // Revenue
  mrr: number               // Monthly Recurring Revenue
  arr: number               // Annual Recurring Revenue
  arpu: number              // Average Revenue Per User

  // Growth
  newMRR: number            // New subscriptions
  expansionMRR: number      // Upgrades
  contractionMRR: number    // Downgrades
  churnedMRR: number        // Cancellations

  // Customers
  totalCustomers: number
  newCustomers: number
  churnRate: number         // % of customers who cancel

  // Engagement
  dau: number               // Daily Active Users
  mau: number               // Monthly Active Users
  dauToMau: number          // Stickiness ratio
}

Customer Lifecycle

1. Visitor → Trial Signup
2. Trial User → Convert to Paid
3. Paid User → Expand (upgrade tier)
4. Paid User → Renew (continue subscription)
5. Paid User → Churn (cancel)

Revenue Recognition

interface Subscription {
  customer: string | Customer
  product: string | Product
  price: string | Price
  status: 'active' | 'past_due' | 'canceled' | 'trialing'
  currentPeriodStart: Date
  currentPeriodEnd: Date
  mrr: number                      // Normalized to monthly
  arr: number                      // Annual run rate
}

Rendering Examples

As Full Application

// Complete SaaS application
<ProductApp product={saasProduct}>
  <Shell>
    <Sidebar />
    <DashboardPage />
  </Shell>
</ProductApp>

As Marketing Site

// Marketing site for the SaaS
<ProductSite product={saasProduct}>
  <LandingPage>
    <Hero />
    <Features />
    <Pricing />
  </LandingPage>
</ProductSite>

As Product Card

// Card in a product directory
<ProductCard product={saasProduct}>
  <ProductLogo />
  <ProductName />
  <ProductDescription />
  <ProductPricing />
  <CTAButton />
</ProductCard>

Integration Points

Stripe Integration

interface SaaSProduct {
  stripeProductId: string           // prod_...
  prices: Array<{
    stripePriceId: string           // price_...
    amount: number
    interval: 'month' | 'year'
  }>
}

// Auto-sync with Stripe
await stripe.products.create({
  name: saasProduct.name,
  description: saasProduct.description,
})

Payload CMS

// Products collection
const saasProducts = await payload.find({
  collection: 'products',
  where: {
    type: { equals: 'SaaS' },
    isActive: { equals: true },
  },
})

// Subscriptions collection
const activeSubscriptions = await payload.find({
  collection: 'subscriptions',
  where: {
    product: { equals: saasProduct.id },
    status: { equals: 'active' },
  },
})

Analytics

// Track SaaS metrics
interface SaaSAnalytics {
  trackSignup(user: User): void
  trackActivation(user: User): void
  trackUpgrade(subscription: Subscription): void
  trackChurn(subscription: Subscription): void

  getMRR(): number
  getChurnRate(): number
  getLTV(): number  // Lifetime Value
}

Examples

Project Management SaaS

name: TaskFlow
type: SaaS
description: Modern project management for distributed teams

interfaces:
  - Web application
  - Mobile app (iOS/Android)
  - REST API
  - Slack integration

pricing:
  - Free: $0/month (up to 3 users)
  - Starter: $19/month (up to 10 users)
  - Pro: $49/month (unlimited users)
  - Enterprise: Custom pricing

features:
  - Task boards & lists
  - Team collaboration
  - File attachments
  - Time tracking
  - Reporting & analytics

CRM SaaS

name: SalesPilot
type: SaaS
description: AI-powered CRM for modern sales teams

interfaces:
  - Web application
  - Browser extension
  - REST API
  - Native integrations (email, calendar)

pricing:
  - Professional: $49/user/month
  - Business: $99/user/month
  - Enterprise: $199/user/month

features:
  - Contact management
  - Deal pipeline
  - Email sequences
  - AI lead scoring
  - Forecasting
  - Custom fields & workflows

Analytics SaaS

name: DataPulse
type: SaaS
description: Real-time analytics and business intelligence

interfaces:
  - Web dashboard
  - REST API
  - JavaScript SDK
  - SQL interface

pricing:
  - Starter: $99/month (100k events)
  - Growth: $299/month (1M events)
  - Scale: $999/month (10M events)
  - Enterprise: Custom (unlimited)

features:
  - Event tracking
  - Custom dashboards
  - Funnels & retention
  - Cohort analysis
  - Data warehouse export

Example Configurations

Basic SaaS Product

import type { SaaSProductProps } from 'mdxui'

const projectManagementSaaS: SaaSProductProps = {
  $type: 'SaaS',
  $id: 'https://taskflow.com',
  name: 'TaskFlow',
  domain: 'taskflow.com',
  description: 'Modern project management for distributed teams',
  category: 'Project Management',

  // Deployment
  deployment: 'cloud',
  targetUser: 'team',

  // Free tier and trial
  freeTier: true,
  trialDays: 14,

  // Pricing
  pricingModel: 'tiered',
  tiers: [
    {
      name: 'Free',
      price: 0,
      currency: 'USD',
      features: [
        'Up to 3 users',
        '10 projects',
        'Basic task management',
        'Mobile app access'
      ],
      limits: {
        seats: 3,
        projects: 10,
        storage: 1 // GB
      }
    },
    {
      name: 'Starter',
      price: 19,
      annualPrice: 190,
      currency: 'USD',
      features: [
        'Up to 10 users',
        'Unlimited projects',
        'File attachments',
        'Time tracking',
        'Basic reporting'
      ],
      limits: {
        seats: 10,
        storage: 50 // GB
      },
      popular: true
    },
    {
      name: 'Pro',
      price: 49,
      annualPrice: 490,
      currency: 'USD',
      features: [
        'Unlimited users',
        'Advanced analytics',
        'API access',
        'Custom fields',
        'Automations',
        'Priority support'
      ],
      limits: {
        storage: 250 // GB
      }
    },
    {
      name: 'Enterprise',
      price: 199,
      currency: 'USD',
      features: [
        'Everything in Pro',
        'SSO / SAML',
        'Advanced security',
        'Audit logs',
        'Dedicated support',
        'SLA guarantee'
      ],
      enterprise: true
    }
  ],

  // Features
  features: [
    {
      name: 'Task Boards',
      description: 'Visual kanban boards for task management',
      category: 'Core'
    },
    {
      name: 'Time Tracking',
      description: 'Track time spent on tasks and projects',
      category: 'Productivity'
    },
    {
      name: 'Team Collaboration',
      description: 'Comments, mentions, and real-time updates',
      category: 'Collaboration'
    },
    {
      name: 'Custom Workflows',
      description: 'Create custom task workflows',
      category: 'Advanced',
      new: true
    }
  ],

  // API
  api: {
    enabled: true,
    type: 'rest',
    documentation: 'https://taskflow.com/docs/api',
    rateLimit: 1000,
    webhooks: true
  },

  // Security
  security: {
    sso: true,
    mfa: true,
    soc2: true,
    gdpr: true,
    encryption: 'both'
  },

  // Support
  support: {
    channels: ['email', 'chat'],
    onboarding: true
  }
}

Enterprise SaaS with Advanced Features

const enterpriseCRM: SaaSProductProps = {
  $type: 'SaaS',
  $id: 'https://salesforce.example.com',
  name: 'Enterprise CRM',
  domain: 'salesforce.example.com',
  description: 'AI-powered CRM for enterprise sales teams',
  category: 'Customer Relationship Management',

  deployment: 'hybrid',
  targetUser: 'enterprise',

  // No free tier for enterprise
  freeTier: false,
  trialDays: 30,

  pricingModel: 'per_seat',
  tiers: [
    {
      name: 'Professional',
      price: 75,
      currency: 'USD',
      features: [
        'Unlimited contacts',
        'Sales pipeline management',
        'Email integration',
        'Mobile app',
        'Basic reporting'
      ],
      limits: {
        apiRequests: 10000
      }
    },
    {
      name: 'Enterprise',
      price: 150,
      currency: 'USD',
      features: [
        'Everything in Professional',
        'Advanced AI features',
        'Custom objects',
        'Workflow automation',
        'Advanced analytics',
        'API access',
        'Priority support'
      ],
      limits: {
        apiRequests: 100000
      },
      popular: true
    },
    {
      name: 'Unlimited',
      price: 300,
      currency: 'USD',
      features: [
        'Everything in Enterprise',
        'Unlimited API calls',
        'SSO / SAML',
        'Advanced security',
        'Dedicated success manager',
        '99.99% SLA'
      ],
      enterprise: true
    }
  ],

  features: [
    {
      name: 'AI Lead Scoring',
      description: 'Machine learning-powered lead prioritization',
      category: 'AI',
      new: true
    },
    {
      name: 'Sales Forecasting',
      description: 'Predictive revenue forecasting',
      category: 'Analytics'
    },
    {
      name: 'Custom Objects',
      description: 'Extend the data model with custom objects',
      category: 'Customization'
    },
    {
      name: 'Territory Management',
      description: 'Manage sales territories and assignments',
      category: 'Enterprise'
    }
  ],

  api: {
    enabled: true,
    type: 'both',
    documentation: 'https://salesforce.example.com/api',
    rateLimit: 5000,
    webhooks: true
  },

  integrations: [
    {
      name: 'Salesforce',
      native: true,
      category: 'CRM'
    },
    {
      name: 'HubSpot',
      native: true,
      category: 'Marketing'
    },
    {
      name: 'Slack',
      native: true,
      category: 'Communication'
    },
    {
      name: 'Gmail',
      native: true,
      category: 'Email'
    },
    {
      name: 'Zapier',
      zapier: true,
      category: 'Automation'
    }
  ],

  security: {
    sso: true,
    mfa: true,
    soc2: true,
    gdpr: true,
    hipaa: true,
    encryption: 'e2e'
  },

  support: {
    channels: ['email', 'chat', 'phone'],
    sla: '4 hours for critical issues',
    dedicatedSuccess: true,
    onboarding: true
  }
}

Usage-Based SaaS

const analyticsService: SaaSProductProps = {
  $type: 'SaaS',
  $id: 'https://datalytics.com',
  name: 'DataLytics',
  domain: 'datalytics.com',
  description: 'Real-time analytics and business intelligence',
  category: 'Analytics',

  deployment: 'cloud',
  targetUser: 'business',

  freeTier: true,
  trialDays: 14,

  // Usage-based pricing
  pricingModel: 'usage',
  tiers: [
    {
      name: 'Free',
      price: 0,
      currency: 'USD',
      features: [
        '10,000 events/month',
        'Basic dashboards',
        '7-day data retention'
      ],
      limits: {
        events: 10000,
        retention: 7
      }
    },
    {
      name: 'Starter',
      price: 99,
      currency: 'USD',
      features: [
        '100,000 events/month included',
        'Custom dashboards',
        '90-day data retention',
        'Email reports',
        '$0.001 per additional event'
      ],
      limits: {
        events: 100000,
        retention: 90
      },
      popular: true
    },
    {
      name: 'Growth',
      price: 299,
      currency: 'USD',
      features: [
        '1M events/month included',
        'Advanced analytics',
        '1-year data retention',
        'API access',
        'Slack integration',
        '$0.0005 per additional event'
      ],
      limits: {
        events: 1000000,
        retention: 365
      }
    },
    {
      name: 'Enterprise',
      price: 999,
      currency: 'USD',
      features: [
        '10M events/month included',
        'Unlimited data retention',
        'White-label dashboards',
        'Custom integrations',
        'Dedicated infrastructure',
        '$0.0001 per additional event'
      ],
      enterprise: true
    }
  ],

  features: [
    {
      name: 'Event Tracking',
      description: 'Track custom events and user actions',
      category: 'Core'
    },
    {
      name: 'Funnel Analysis',
      description: 'Visualize conversion funnels',
      category: 'Analytics'
    },
    {
      name: 'Cohort Analysis',
      description: 'Analyze user cohorts over time',
      category: 'Analytics'
    },
    {
      name: 'Data Warehouse Export',
      description: 'Export data to your warehouse',
      category: 'Enterprise',
      beta: true
    }
  ],

  api: {
    enabled: true,
    type: 'both',
    documentation: 'https://datalytics.com/docs',
    rateLimit: 10000,
    webhooks: true
  },

  integrations: [
    {
      name: 'Segment',
      native: true,
      category: 'Data'
    },
    {
      name: 'Google Analytics',
      native: true,
      category: 'Analytics'
    },
    {
      name: 'Snowflake',
      native: true,
      category: 'Data Warehouse'
    }
  ],

  security: {
    sso: true,
    mfa: true,
    soc2: true,
    gdpr: true,
    encryption: 'both'
  },

  support: {
    channels: ['email', 'chat'],
    onboarding: true
  }
}

Multi-Workspace SaaS Configuration

// Workspace configuration for multi-tenant SaaS
interface WorkspaceConfig {
  workspace: Workspace
  subscription: Subscription
  features: FeatureFlags
  usage: UsageLimits
}

const workspaceConfig: WorkspaceConfig = {
  workspace: {
    id: 'ws_acme',
    name: 'Acme Corporation',
    slug: 'acme-corp',
    ownerId: 'user_123',
    plan: 'pro',
    settings: {
      logo: 'https://acme.com/logo.png',
      primaryColor: '#3B82F6',
      features: {
        apiAccess: true,
        sso: false,
        customDomain: true,
        auditLogs: true
      },
      limits: {
        seats: 50,
        storage: 250,
        apiRequests: 100000
      },
      usage: {
        seats: 32,
        storage: 127,
        apiRequests: 45230
      }
    },
    createdAt: new Date('2024-01-15'),
    updatedAt: new Date('2024-12-19')
  },

  subscription: {
    id: 'sub_123',
    stripeSubscriptionId: 'sub_1ABC...',
    plan: 'pro',
    status: 'active',
    currentPeriodStart: new Date('2024-12-01'),
    currentPeriodEnd: new Date('2025-01-01'),
    cancelAtPeriodEnd: false,
    trialEnd: null,
    items: [
      {
        priceId: 'price_pro_monthly',
        quantity: 32, // seats
        amount: 1568 // $49 * 32
      }
    ]
  },

  features: {
    api_access: true,
    sso: false,
    custom_domain: true,
    audit_logs: true,
    advanced_analytics: true,
    custom_roles: true,
    white_label: false
  },

  usage: {
    seats: {
      current: 32,
      limit: 50,
      percentage: 64
    },
    storage: {
      current: 127,
      limit: 250,
      unit: 'GB',
      percentage: 50.8
    },
    apiRequests: {
      current: 45230,
      limit: 100000,
      period: 'month',
      percentage: 45.2
    }
  }
}

Next Steps

On this page