B2B SaaS Platform
Build a complete multi-tenant B2B SaaS platform with Business-as-Code
Build a complete, autonomous multi-tenant B2B SaaS platform using Business-as-Code principles.
Overview
This use case demonstrates building a B2B SaaS platform that:
- Manages multi-tenant organizations autonomously
- Handles team hierarchies and permissions
- Processes subscriptions and billing automatically
- Tracks usage and enforces limits
- Provides self-service provisioning
- Delivers analytics and insights
- Manages support workflows
- Handles enterprise integrations
Architecture
Core Entities
Organizations
Organizations represent customer companies in a multi-tenant B2B platform.
import $, { db, on, send, ai } from 'sdk.do'
// Create organization
const organization = await $.Organization.create({
$type: 'Organization',
name: 'Acme Corporation',
description: 'Enterprise software company',
url: 'https://acme.com',
email: '[email protected]',
telephone: '+1-555-0100',
// Organization details
numberOfEmployees: 500,
foundingDate: '2015-03-15',
industry: 'Software',
// Address
address: {
$type: 'PostalAddress',
streetAddress: '123 Enterprise Blvd',
addressLocality: 'San Francisco',
addressRegion: 'CA',
postalCode: '94105',
addressCountry: 'US',
},
// Settings
settings: {
timezone: 'America/Los_Angeles',
dateFormat: 'MM/DD/YYYY',
currency: 'USD',
language: 'en',
},
// Metadata
status: 'active',
createdAt: new Date(),
onboardedAt: null,
})Teams
Teams organize users within organizations with hierarchical structures.
// Create teams
const engineering = await $.Team.create({
$type: 'PerformingGroup',
name: 'Engineering',
description: 'Product engineering team',
parentOrganization: organization,
numberOfMembers: 50,
settings: {
allowedRoles: ['admin', 'developer', 'viewer'],
defaultRole: 'developer',
},
})
const backend = await $.Team.create({
$type: 'PerformingGroup',
name: 'Backend',
description: 'Backend engineering team',
parentOrganization: organization,
parentTeam: engineering,
numberOfMembers: 20,
})
await db.relate(organization, $.hasSubOrganization, engineering)
await db.relate(engineering, $.hasSubOrganization, backend)Users & Roles
// Create user
const user = await $.Person.create({
$type: 'Person',
givenName: 'Jane',
familyName: 'Smith',
email: '[email protected]',
jobTitle: 'Senior Engineer',
telephone: '+1-555-0123',
// Authentication
authProvider: 'email',
emailVerified: true,
// Metadata
status: 'active',
createdAt: new Date(),
lastLoginAt: null,
})
// Assign to organization
await db.relate(organization, $.member, user)
// Assign to team with role
await $.Role.assign({
user,
team: backend,
role: 'developer',
permissions: ['resources.read', 'resources.write', 'deployments.create'],
assignedBy: adminUser,
assignedAt: new Date(),
})Business Functions
1. Organization Onboarding
Complete self-service onboarding workflow with AI assistance.
// Onboarding workflow
on($.Organization.created, async (organization) => {
// Create onboarding checklist
const checklist = await $.ItemList.create({
$type: 'ItemList',
name: 'Onboarding Checklist',
itemListElement: [
{
$type: 'ListItem',
name: 'Verify email',
position: 1,
status: 'pending',
},
{
$type: 'ListItem',
name: 'Add team members',
position: 2,
status: 'pending',
},
{
$type: 'ListItem',
name: 'Configure settings',
position: 3,
status: 'pending',
},
{
$type: 'ListItem',
name: 'Create first project',
position: 4,
status: 'pending',
},
{
$type: 'ListItem',
name: 'Set up billing',
position: 5,
status: 'pending',
},
],
})
await db.relate(organization, $.has, checklist)
// Send welcome email
await send($.Email.send, {
to: organization.email,
template: 'organization-welcome',
data: {
organization,
checklist,
setupUrl: `https://app.platform.do/onboarding/${organization.$id}`,
},
})
// Create trial subscription
await send($.Subscription.createTrial, {
organization,
plan: 'professional',
trialDays: 14,
})
// Schedule check-in emails
await send($.Email.schedule, {
to: organization.email,
template: 'onboarding-checkin-day3',
sendAt: addDays(new Date(), 3),
data: { organization },
})
await send($.Email.schedule, {
to: organization.email,
template: 'onboarding-checkin-day7',
sendAt: addDays(new Date(), 7),
data: { organization },
})
// Assign customer success rep
const rep = await ai.decide('assign-success-rep', {
organization,
size: organization.numberOfEmployees,
industry: organization.industry,
plan: 'professional',
})
if (rep.shouldAssign) {
await db.relate(organization, $.assignedTo, rep.representative)
await send($.Notification.send, {
to: rep.representative,
message: `New organization assigned: ${organization.name}`,
action: { view: organization.$id },
})
}
})
// Track onboarding progress
on($.Checklist.itemCompleted, async ({ checklist, item }) => {
const organization = await db.related(checklist, $.belongsTo, $.Organization).then((orgs) => orgs[0])
// Calculate completion percentage
const items = checklist.itemListElement
const completed = items.filter((i) => i.status === 'completed').length
const progress = completed / items.length
await db.update($.Organization, organization.$id, {
onboardingProgress: progress,
})
// Mark as onboarded when complete
if (progress === 1.0 && !organization.onboardedAt) {
await db.update($.Organization, organization.$id, {
onboardedAt: new Date(),
status: 'onboarded',
})
await send($.Organization.onboarded, organization)
// Send congratulations email
await send($.Email.send, {
to: organization.email,
template: 'onboarding-complete',
data: { organization },
})
}
})2. Team Management
Hierarchical team structures with role-based access control.
// Add team member
async function addTeamMember(params: { team: Team; user: Person; role: string; permissions?: string[]; invitedBy: Person }) {
const { team, user, role, permissions, invitedBy } = params
// Check if user is already a member
const existing = await db.related(team, $.member, user)
if (existing.length > 0) {
throw new Error('User is already a team member')
}
// Get organization
const organization = await db.related(team, $.belongsTo, $.Organization).then((orgs) => orgs[0])
// Check organization limits
const subscription = await db.related(organization, $.has, $.Subscription).then((subs) => subs[0])
const currentMembers = await db.count(organization, $.member)
if (currentMembers >= subscription.plan.limits.users) {
throw new Error('Organization has reached user limit')
}
// Add to organization if not already a member
const orgMembers = await db.related(organization, $.member, user)
if (orgMembers.length === 0) {
await db.relate(organization, $.member, user)
}
// Add to team
await db.relate(team, $.member, user)
// Assign role
const roleAssignment = await $.Role.create({
$type: 'Role',
roleName: role,
member: user,
memberOf: team,
permissions: permissions || getDefaultPermissions(role),
assignedBy: invitedBy,
startDate: new Date(),
})
await db.relate(user, $.hasRole, roleAssignment)
// Send welcome email
await send($.Email.send, {
to: user.email,
template: 'team-invitation',
data: {
team,
organization,
role,
invitedBy,
},
})
await send($.Team.memberAdded, {
team,
user,
role: roleAssignment,
})
return roleAssignment
}
// Permission checking
async function checkPermission(user: Person, resource: string, action: string): Promise<boolean> {
// Get all roles for user
const roles = await db.related(user, $.hasRole, $.Role)
// Check if any role has the required permission
for (const role of roles) {
const permission = `${resource}.${action}`
if (role.permissions.includes(permission) || role.permissions.includes(`${resource}.*`)) {
return true
}
// Check wildcard permissions
if (role.permissions.includes('*')) {
return true
}
}
return false
}
// Permission middleware
async function requirePermission(resource: string, action: string) {
return async (context: Context) => {
const user = context.user
if (!user) {
throw new Error('Unauthorized')
}
const hasPermission = await checkPermission(user, resource, action)
if (!hasPermission) {
throw new Error('Forbidden: Insufficient permissions')
}
return context.next()
}
}3. Subscription Management
Complete subscription lifecycle with plans, trials, and upgrades.
// Subscription plans
const plans = {
starter: {
name: 'Starter',
price: 49,
interval: 'month',
limits: {
users: 5,
projects: 10,
storage: 10, // GB
apiCalls: 10000,
},
features: ['Basic support', 'Email notifications', 'API access'],
},
professional: {
name: 'Professional',
price: 199,
interval: 'month',
limits: {
users: 25,
projects: 50,
storage: 100,
apiCalls: 100000,
},
features: ['Priority support', 'Advanced analytics', 'Custom integrations', 'SSO/SAML'],
},
enterprise: {
name: 'Enterprise',
price: 999,
interval: 'month',
limits: {
users: -1, // unlimited
projects: -1,
storage: 1000,
apiCalls: 1000000,
},
features: ['Dedicated support', 'SLA guarantees', 'Custom contracts', 'On-premise deployment'],
},
}
// Create subscription
async function createSubscription(params: { organization: Organization; plan: string; paymentMethod?: string; trial?: boolean; trialDays?: number }) {
const { organization, plan, paymentMethod, trial, trialDays } = params
const planConfig = plans[plan]
if (!planConfig) {
throw new Error('Invalid plan')
}
const subscription = await $.Subscription.create({
$type: 'Subscription',
name: `${planConfig.name} Plan`,
provider: organization,
// Pricing
price: planConfig.price,
priceCurrency: 'USD',
billingPeriod: planConfig.interval,
// Dates
startDate: new Date(),
endDate: null,
// Trial
isTrial: trial || false,
trialEndDate: trial ? addDays(new Date(), trialDays || 14) : null,
// Plan details
plan: planConfig,
// Payment
paymentMethod: paymentMethod || null,
// Status
status: 'active',
autoRenew: true,
})
await db.relate(organization, $.has, subscription)
// Schedule trial end reminder
if (trial) {
await send($.Email.schedule, {
to: organization.email,
template: 'trial-ending-soon',
sendAt: subDays(subscription.trialEndDate, 3),
data: { organization, subscription },
})
}
await send($.Subscription.created, subscription)
return subscription
}
// Handle subscription changes
on($.Subscription.created, async (subscription) => {
const organization = await db.related(subscription, $.belongsTo, $.Organization).then((orgs) => orgs[0])
// Initialize usage tracking
await $.UsageRecord.create({
$type: 'UsageRecord',
subscription: subscription.$id,
organization: organization.$id,
period: {
start: subscription.startDate,
end: addMonths(subscription.startDate, 1),
},
metrics: {
users: 0,
projects: 0,
storage: 0,
apiCalls: 0,
},
})
// Log event
await db.create($.AuditLog, {
action: 'subscription.created',
actor: organization.$id,
target: subscription.$id,
timestamp: new Date(),
})
})
// Upgrade subscription
async function upgradeSubscription(params: { subscription: Subscription; newPlan: string; immediate?: boolean }) {
const { subscription, newPlan, immediate } = params
const planConfig = plans[newPlan]
if (!planConfig) {
throw new Error('Invalid plan')
}
// Calculate proration if immediate
let prorationAmount = 0
if (immediate) {
const daysRemaining = differenceInDays(subscription.endDate, new Date())
const daysInPeriod = differenceInDays(subscription.endDate, subscription.startDate)
const unusedAmount = (subscription.price * daysRemaining) / daysInPeriod
const newAmount = (planConfig.price * daysRemaining) / daysInPeriod
prorationAmount = newAmount - unusedAmount
}
// Update subscription
await db.update($.Subscription, subscription.$id, {
plan: planConfig,
price: planConfig.price,
upgradeScheduled: !immediate,
upgradeDate: immediate ? new Date() : subscription.endDate,
})
// Create invoice if immediate and prorated
if (immediate && prorationAmount > 0) {
await send($.Invoice.create, {
subscription,
amount: prorationAmount,
description: `Prorated upgrade to ${planConfig.name}`,
dueDate: new Date(),
})
}
await send($.Subscription.upgraded, {
subscription,
oldPlan: subscription.plan.name,
newPlan: planConfig.name,
immediate,
})
}4. Usage Tracking & Quota Enforcement
Real-time usage tracking with automatic quota enforcement.
// Track usage
async function trackUsage(params: { organization: Organization; metric: string; amount: number; metadata?: any }) {
const { organization, metric, amount, metadata } = params
// Get current subscription
const subscription = await db.related(organization, $.has, $.Subscription).then((subs) => subs[0])
if (!subscription) {
throw new Error('No active subscription')
}
// Get current usage record
const usageRecord = await db
.list($.UsageRecord, {
where: {
subscription: subscription.$id,
'period.start': { $lte: new Date() },
'period.end': { $gte: new Date() },
},
})
.then((records) => records[0])
if (!usageRecord) {
throw new Error('No usage record found')
}
// Update usage
const newUsage = (usageRecord.metrics[metric] || 0) + amount
await db.update($.UsageRecord, usageRecord.$id, {
[`metrics.${metric}`]: newUsage,
updatedAt: new Date(),
})
// Check if approaching limit
const limit = subscription.plan.limits[metric]
if (limit > 0) {
const percentage = newUsage / limit
// Alert at 80%
if (percentage >= 0.8 && percentage < 0.9) {
await send($.Usage.approaching, {
organization,
metric,
current: newUsage,
limit,
percentage,
})
}
// Alert at 90%
if (percentage >= 0.9 && percentage < 1.0) {
await send($.Usage.warning, {
organization,
metric,
current: newUsage,
limit,
percentage,
})
}
// Exceeded
if (percentage >= 1.0) {
await send($.Usage.exceeded, {
organization,
metric,
current: newUsage,
limit,
percentage,
})
}
}
// Create usage event
await db.create($.UsageEvent, {
organization: organization.$id,
subscription: subscription.$id,
metric,
amount,
timestamp: new Date(),
metadata,
})
return { current: newUsage, limit }
}
// Check quota before operation
async function checkQuota(organization: Organization, metric: string, required: number = 1): Promise<boolean> {
const subscription = await db.related(organization, $.has, $.Subscription).then((subs) => subs[0])
if (!subscription) {
return false
}
const limit = subscription.plan.limits[metric]
// Unlimited
if (limit === -1) {
return true
}
// Get current usage
const usageRecord = await db
.list($.UsageRecord, {
where: {
subscription: subscription.$id,
'period.start': { $lte: new Date() },
'period.end': { $gte: new Date() },
},
})
.then((records) => records[0])
if (!usageRecord) {
return false
}
const current = usageRecord.metrics[metric] || 0
return current + required <= limit
}
// Quota enforcement middleware
async function enforceQuota(metric: string, required: number = 1) {
return async (context: Context) => {
const organization = context.organization
if (!organization) {
throw new Error('No organization context')
}
const allowed = await checkQuota(organization, metric, required)
if (!allowed) {
const subscription = await db.related(organization, $.has, $.Subscription).then((subs) => subs[0])
const limit = subscription.plan.limits[metric]
throw new Error(`Quota exceeded: ${metric} limit is ${limit}`)
}
// Track usage after successful operation
context.onSuccess(async () => {
await trackUsage({
organization,
metric,
amount: required,
})
})
return context.next()
}
}
// Handle quota exceeded
on($.Usage.exceeded, async (event) => {
const { organization, metric, current, limit } = event
// Notify admins
const admins = await db.list($.Person, {
where: {
organization: organization.$id,
role: 'admin',
},
})
for (const admin of admins) {
await send($.Email.send, {
to: admin.email,
template: 'quota-exceeded',
priority: 'high',
data: {
organization,
metric,
current,
limit,
upgradeUrl: `https://app.platform.do/billing/upgrade`,
},
})
}
// AI suggests upgrade
const recommendation = await ai.decide('suggest-upgrade', {
organization,
subscription: await db.related(organization, $.has, $.Subscription).then((subs) => subs[0]),
usage: event,
})
if (recommendation.shouldSuggest) {
await send($.Notification.send, {
to: admins,
template: 'upgrade-suggestion',
data: {
recommendation,
organization,
},
})
}
})5. Billing & Invoicing
Automated billing with invoice generation and payment processing.
// Generate invoice
async function generateInvoice(subscription: Subscription) {
const organization = await db.related(subscription, $.belongsTo, $.Organization).then((orgs) => orgs[0])
// Get usage for billing period
const usageRecord = await db
.list($.UsageRecord, {
where: {
subscription: subscription.$id,
'period.end': { $lte: new Date() },
},
sort: { 'period.end': -1 },
limit: 1,
})
.then((records) => records[0])
// Calculate base amount
let totalAmount = subscription.price
// Add usage-based charges
const overages = calculateOverages(usageRecord, subscription.plan.limits)
totalAmount += overages.total
// Apply discounts
const discounts = await db.related(organization, $.has, $.Discount, {
where: {
validFrom: { $lte: new Date() },
validThrough: { $gte: new Date() },
status: 'active',
},
})
let discountAmount = 0
for (const discount of discounts) {
if (discount.type === 'percentage') {
discountAmount += totalAmount * (discount.value / 100)
} else {
discountAmount += discount.value
}
}
totalAmount -= discountAmount
// Create invoice
const invoice = await $.Invoice.create({
$type: 'Invoice',
identifier: `INV-${Date.now()}`,
// Parties
provider: organization,
customer: organization,
// Amounts
totalPaymentDue: {
$type: 'PriceSpecification',
price: totalAmount,
priceCurrency: 'USD',
},
// Line items
referencesOrder: [
{
$type: 'OrderItem',
orderItem: subscription,
orderQuantity: 1,
price: subscription.price,
description: `${subscription.plan.name} Plan`,
},
...overages.items.map((item) => ({
$type: 'OrderItem',
orderItem: item.metric,
orderQuantity: item.amount,
price: item.rate,
description: item.description,
})),
],
// Discounts
discount: discounts.map((d) => ({
name: d.name,
amount: d.type === 'percentage' ? `${d.value}%` : d.value,
})),
// Dates
dateIssued: new Date(),
paymentDueDate: addDays(new Date(), 30),
billingPeriod: {
startDate: usageRecord.period.start,
endDate: usageRecord.period.end,
},
// Status
paymentStatus: 'due',
})
await db.relate(organization, $.receivesInvoice, invoice)
await send($.Invoice.created, invoice)
return invoice
}
// Process invoice payment
on($.Invoice.created, async (invoice) => {
const organization = await db.related(invoice, $.belongsTo, $.Organization).then((orgs) => orgs[0])
const subscription = await db.related(organization, $.has, $.Subscription).then((subs) => subs[0])
// Get payment method
if (!subscription.paymentMethod) {
// Send payment request email
await send($.Email.send, {
to: organization.email,
template: 'invoice-payment-required',
data: {
invoice,
paymentUrl: `https://app.platform.do/billing/pay/${invoice.$id}`,
},
})
return
}
// Attempt automatic payment
try {
const payment = await send($.Payment.process, {
invoice,
amount: invoice.totalPaymentDue.price,
currency: invoice.totalPaymentDue.priceCurrency,
paymentMethod: subscription.paymentMethod,
customer: organization,
})
if (payment.status === 'succeeded') {
await db.update($.Invoice, invoice.$id, {
paymentStatus: 'paid',
paidAt: new Date(),
})
// Send receipt
await send($.Email.send, {
to: organization.email,
template: 'payment-receipt',
data: { invoice, payment },
})
await send($.Invoice.paid, { invoice, payment })
} else {
throw new Error(payment.error || 'Payment failed')
}
} catch (error) {
// Payment failed
await send($.Email.send, {
to: organization.email,
template: 'payment-failed',
priority: 'high',
data: {
invoice,
error: error.message,
updatePaymentUrl: `https://app.platform.do/billing/payment-method`,
},
})
await send($.Invoice.paymentFailed, { invoice, error })
}
})
// Handle failed payments
on($.Invoice.paymentFailed, async ({ invoice, error }) => {
const organization = await db.related(invoice, $.belongsTo, $.Organization).then((orgs) => orgs[0])
// Retry after 3 days
await send($.Invoice.retryPayment, {
invoice,
retryAt: addDays(new Date(), 3),
})
// If overdue by 7 days, suspend service
const daysSinceIssue = differenceInDays(new Date(), invoice.dateIssued)
if (daysSinceIssue >= 7) {
const subscription = await db.related(organization, $.has, $.Subscription).then((subs) => subs[0])
await db.update($.Subscription, subscription.$id, {
status: 'suspended',
suspendedAt: new Date(),
suspensionReason: 'payment-overdue',
})
await send($.Subscription.suspended, { subscription, reason: 'payment-overdue' })
}
})6. User Provisioning
Automated user provisioning with SSO and SCIM support.
// SCIM user provisioning
async function scimProvisionUser(params: {
organization: Organization
userName: string
name: { givenName: string; familyName: string }
emails: Array<{ value: string; primary: boolean }>
active: boolean
groups?: string[]
}) {
const { organization, userName, name, emails, active, groups } = params
// Check if user already exists
const primaryEmail = emails.find((e) => e.primary)?.value || emails[0].value
let user = await db
.list($.Person, {
where: { email: primaryEmail },
})
.then((users) => users[0])
if (!user) {
// Create new user
user = await $.Person.create({
$type: 'Person',
givenName: name.givenName,
familyName: name.familyName,
email: primaryEmail,
additionalName: userName,
// SCIM attributes
active,
authProvider: 'scim',
// Metadata
status: active ? 'active' : 'inactive',
createdAt: new Date(),
})
// Add to organization
await db.relate(organization, $.member, user)
await send($.User.provisioned, { user, organization, source: 'scim' })
} else {
// Update existing user
await db.update($.Person, user.$id, {
givenName: name.givenName,
familyName: name.familyName,
active,
status: active ? 'active' : 'inactive',
updatedAt: new Date(),
})
await send($.User.updated, { user, source: 'scim' })
}
// Assign to groups/teams
if (groups && groups.length > 0) {
for (const groupName of groups) {
const team = await db
.list($.Team, {
where: {
organization: organization.$id,
name: groupName,
},
})
.then((teams) => teams[0])
if (team) {
await db.relate(team, $.member, user)
}
}
}
return user
}
// SSO authentication
async function ssoAuthenticate(params: { samlResponse: string; organization: Organization }) {
const { samlResponse, organization } = params
// Validate SAML response
const samlData = await validateSAMLResponse(samlResponse, organization)
if (!samlData.valid) {
throw new Error('Invalid SAML response')
}
// Get or create user
let user = await db
.list($.Person, {
where: {
email: samlData.email,
organization: organization.$id,
},
})
.then((users) => users[0])
if (!user) {
// Auto-provision user from SAML attributes
user = await $.Person.create({
$type: 'Person',
givenName: samlData.firstName,
familyName: samlData.lastName,
email: samlData.email,
authProvider: 'saml',
// SAML attributes
externalId: samlData.nameId,
status: 'active',
createdAt: new Date(),
})
await db.relate(organization, $.member, user)
await send($.User.provisioned, { user, organization, source: 'saml' })
}
// Update last login
await db.update($.Person, user.$id, {
lastLoginAt: new Date(),
})
// Create session
const session = await $.Session.create({
user: user.$id,
organization: organization.$id,
authMethod: 'saml',
createdAt: new Date(),
expiresAt: addHours(new Date(), 24),
})
await send($.Session.created, session)
return { user, session }
}7. Analytics & Reporting
Real-time analytics with AI-powered insights.
// Organization analytics
async function getOrganizationAnalytics(organization: Organization, timeRange: string = '30d') {
const startDate = subtractTimeRange(new Date(), timeRange)
// User metrics
const userMetrics = await db.aggregate($.Person, {
where: {
organization: organization.$id,
createdAt: { $gte: startDate },
},
aggregations: {
total: { $count: '*' },
active: { $count: '*', where: { lastLoginAt: { $gte: subDays(new Date(), 7) } } },
newUsers: { $count: '*', where: { createdAt: { $gte: startDate } } },
},
})
// Usage metrics
const usageMetrics = await db.aggregate($.UsageEvent, {
where: {
organization: organization.$id,
timestamp: { $gte: startDate },
},
groupBy: ['metric'],
aggregations: {
total: { $sum: 'amount' },
average: { $avg: 'amount' },
peak: { $max: 'amount' },
},
})
// Financial metrics
const financialMetrics = await db.aggregate($.Invoice, {
where: {
customer: organization.$id,
dateIssued: { $gte: startDate },
},
aggregations: {
revenue: { $sum: 'totalPaymentDue.price' },
paid: { $sum: 'totalPaymentDue.price', where: { paymentStatus: 'paid' } },
outstanding: { $sum: 'totalPaymentDue.price', where: { paymentStatus: 'due' } },
},
})
// Support metrics
const supportMetrics = await db.aggregate($.Ticket, {
where: {
organization: organization.$id,
createdAt: { $gte: startDate },
},
aggregations: {
total: { $count: '*' },
open: { $count: '*', where: { status: 'open' } },
resolved: { $count: '*', where: { status: 'resolved' } },
avgResponseTime: { $avg: 'firstResponseTime' },
avgResolutionTime: { $avg: 'resolutionTime' },
},
})
return {
users: userMetrics,
usage: usageMetrics,
financial: financialMetrics,
support: supportMetrics,
timeRange,
generatedAt: new Date(),
}
}
// AI-powered insights
async function generateInsights(organization: Organization) {
const analytics = await getOrganizationAnalytics(organization, '90d')
// AI analyzes patterns
const insights = await ai.analyze('organization-health', {
organization,
analytics,
subscription: await db.related(organization, $.has, $.Subscription).then((subs) => subs[0]),
})
return {
health: insights.overallHealth, // 0-100
trends: insights.trends,
risks: insights.risks,
opportunities: insights.opportunities,
recommendations: insights.recommendations,
}
}
// Scheduled reporting
setInterval(
async () => {
// Get all organizations
const organizations = await db.list($.Organization, {
where: { status: 'active' },
})
for (const org of organizations) {
try {
// Generate weekly report
const analytics = await getOrganizationAnalytics(org, '7d')
const insights = await generateInsights(org)
// Get admins
const admins = await db.list($.Person, {
where: {
organization: org.$id,
role: 'admin',
},
})
// Send report
for (const admin of admins) {
await send($.Email.send, {
to: admin.email,
template: 'weekly-analytics-report',
data: {
organization: org,
analytics,
insights,
},
})
}
} catch (error) {
console.error(`Failed to generate report for ${org.name}:`, error)
}
}
},
7 * 24 * 60 * 60 * 1000
) // Weekly8. Support Workflows
AI-powered support with ticketing and automation.
// Create support ticket
async function createTicket(params: { organization: Organization; user: Person; subject: string; description: string; priority?: string; category?: string }) {
const { organization, user, subject, description, priority, category } = params
// AI analyzes ticket
const analysis = await ai.analyze('ticket-triage', {
subject,
description,
user,
organization,
})
// Create ticket
const ticket = await $.Ticket.create({
$type: 'Ticket',
identifier: `TICK-${Date.now()}`,
// Content
name: subject,
description,
// Parties
customer: user,
organization,
// Classification
category: category || analysis.suggestedCategory,
priority: priority || analysis.suggestedPriority,
// AI insights
sentiment: analysis.sentiment,
urgency: analysis.urgency,
suggestedResponse: analysis.suggestedResponse,
// Status
status: 'open',
createdAt: new Date(),
})
// Auto-assign based on category
const agent = await ai.decide('assign-support-agent', {
ticket,
category: ticket.category,
priority: ticket.priority,
availability: await getSupportAgentAvailability(),
})
if (agent.assignTo) {
await db.relate(ticket, $.assignedTo, agent.assignTo)
await send($.Notification.send, {
to: agent.assignTo,
message: `New ticket assigned: ${subject}`,
priority: ticket.priority,
action: { view: ticket.$id },
})
}
// Send acknowledgment
await send($.Email.send, {
to: user.email,
template: 'ticket-created',
data: {
ticket,
estimatedResponse: agent.estimatedResponseTime,
},
})
await send($.Ticket.created, ticket)
return ticket
}
// AI support agent
on($.Ticket.created, async (ticket) => {
// Check if AI can auto-resolve
const resolution = await ai.decide('auto-resolve-ticket', {
ticket,
knowledgeBase: await searchKnowledgeBase(ticket.description),
similarTickets: await findSimilarTickets(ticket),
})
if (resolution.canAutoResolve && resolution.confidence > 0.9) {
// Send resolution
await send($.Email.send, {
to: ticket.customer.email,
template: 'ticket-auto-resolution',
data: {
ticket,
resolution: resolution.solution,
helpfulArticles: resolution.articles,
feedbackUrl: `https://app.platform.do/support/feedback/${ticket.$id}`,
},
})
// Mark as resolved
await db.update($.Ticket, ticket.$id, {
status: 'resolved',
resolution: resolution.solution,
resolvedAt: new Date(),
resolvedBy: 'ai-agent',
autoResolved: true,
})
await send($.Ticket.resolved, { ticket, resolution })
} else if (resolution.suggestedResponse) {
// Suggest response to agent
const agent = await db.related(ticket, $.assignedTo, $.Person).then((agents) => agents[0])
if (agent) {
await send($.Notification.send, {
to: agent,
template: 'suggested-response',
data: {
ticket,
suggestion: resolution.suggestedResponse,
},
})
}
}
})
// SLA monitoring
on($.Ticket.created, async (ticket) => {
// Define SLA based on priority
const sla = {
critical: { firstResponse: 1, resolution: 4 }, // hours
high: { firstResponse: 4, resolution: 24 },
medium: { firstResponse: 8, resolution: 48 },
low: { firstResponse: 24, resolution: 120 },
}
const timeLimits = sla[ticket.priority] || sla.medium
// Schedule SLA breach alerts
await send($.Alert.schedule, {
alertAt: addHours(ticket.createdAt, timeLimits.firstResponse * 0.8),
type: 'sla-warning',
ticket: ticket.$id,
metric: 'firstResponse',
})
await send($.Alert.schedule, {
alertAt: addHours(ticket.createdAt, timeLimits.resolution * 0.8),
type: 'sla-warning',
ticket: ticket.$id,
metric: 'resolution',
})
})Workflows
Organization Lifecycle
// Complete organization lifecycle
const organizationWorkflow = {
// 1. Signup
signup: async (params: SignupParams) => {
const org = await $.Organization.create(params)
await send($.Organization.created, org)
return org
},
// 2. Onboarding
onboard: on($.Organization.created, async (org) => {
await createOnboardingChecklist(org)
await createTrialSubscription(org)
await assignSuccessRep(org)
await sendWelcomeEmail(org)
}),
// 3. Activation
activate: on($.Organization.onboarded, async (org) => {
await db.update($.Organization, org.$id, { status: 'active' })
await scheduleHealthChecks(org)
await enableFeatures(org)
}),
// 4. Growth
monitor: setInterval(async () => {
const orgs = await db.list($.Organization, { where: { status: 'active' } })
for (const org of orgs) {
const health = await calculateHealthScore(org)
if (health.score < 50) {
await send($.Organization.needsAttention, { org, health })
}
}
}, 86400000), // Daily
// 5. Renewal
renew: on($.Subscription.expiring, async ({ subscription }) => {
const org = await db.related(subscription, $.belongsTo, $.Organization).then((orgs) => orgs[0])
if (subscription.autoRenew) {
await renewSubscription(subscription)
} else {
await sendRenewalReminder(org, subscription)
}
}),
// 6. Churn Prevention
preventChurn: on($.Organization.needsAttention, async ({ org, health }) => {
const intervention = await ai.decide('churn-prevention', {
organization: org,
health,
})
if (intervention.shouldIntervene) {
await executeChurnPrevention(org, intervention)
}
}),
}Events
// Organization events
on($.Organization.created, async (org) => {
console.log('New organization:', org.name)
})
on($.Organization.onboarded, async (org) => {
console.log('Organization onboarded:', org.name)
})
on($.Organization.suspended, async ({ org, reason }) => {
console.log('Organization suspended:', org.name, reason)
})
// Subscription events
on($.Subscription.created, async (sub) => {
console.log('New subscription:', sub.plan.name)
})
on($.Subscription.upgraded, async ({ subscription, oldPlan, newPlan }) => {
console.log('Subscription upgraded:', oldPlan, '->', newPlan)
})
on($.Subscription.cancelled, async (sub) => {
console.log('Subscription cancelled:', sub.plan.name)
})
// Usage events
on($.Usage.exceeded, async (event) => {
console.log('Quota exceeded:', event.metric, event.organization.name)
})
// Invoice events
on($.Invoice.created, async (invoice) => {
console.log('Invoice created:', invoice.identifier)
})
on($.Invoice.paid, async ({ invoice }) => {
console.log('Invoice paid:', invoice.identifier)
})
// Support events
on($.Ticket.created, async (ticket) => {
console.log('Ticket created:', ticket.identifier)
})
on($.Ticket.resolved, async ({ ticket }) => {
console.log('Ticket resolved:', ticket.identifier)
})Metrics
Track key B2B SaaS metrics:
// Calculate MRR
async function calculateMRR() {
const subscriptions = await db.list($.Subscription, {
where: {
status: 'active',
isTrial: false,
},
})
const mrr = subscriptions.reduce((total, sub) => {
if (sub.billingPeriod === 'month') {
return total + sub.price
} else if (sub.billingPeriod === 'year') {
return total + sub.price / 12
}
return total
}, 0)
return mrr
}
// Calculate churn rate
async function calculateChurnRate(timeRange: string = '30d') {
const startDate = subtractTimeRange(new Date(), timeRange)
const activeAtStart = await db.count($.Subscription, {
where: {
createdAt: { $lt: startDate },
status: 'active',
},
})
const cancelled = await db.count($.Subscription, {
where: {
cancelledAt: { $gte: startDate },
},
})
return (cancelled / activeAtStart) * 100
}
// Calculate NPS
async function calculateNPS(timeRange: string = '90d') {
const startDate = subtractTimeRange(new Date(), timeRange)
const surveys = await db.list($.Survey, {
where: {
type: 'nps',
completedAt: { $gte: startDate },
},
})
const promoters = surveys.filter((s) => s.score >= 9).length
const detractors = surveys.filter((s) => s.score <= 6).length
const total = surveys.length
return ((promoters - detractors) / total) * 100
}
// Calculate LTV
async function calculateLTV(organization: Organization) {
const orders = await db.list($.Invoice, {
where: {
customer: organization.$id,
paymentStatus: 'paid',
},
})
const totalRevenue = orders.reduce((sum, inv) => sum + inv.totalPaymentDue.price, 0)
const months = differenceInMonths(new Date(), organization.createdAt)
const avgMonthlyRevenue = totalRevenue / months
// Estimate LTV based on churn
const churnRate = await calculateChurnRate()
const avgLifetimeMonths = 1 / (churnRate / 100)
return avgMonthlyRevenue * avgLifetimeMonths
}Best Practices
1. Multi-Tenancy
- Strict Isolation: Never query across organizations without explicit relationships
- Tenant Context: Always include organization/tenant context in queries
- Database Isolation: Use row-level security or tenant-scoped connections
- Resource Limits: Enforce per-tenant quotas to prevent abuse
2. Security
- Role-Based Access Control: Implement fine-grained permissions
- Audit Logging: Log all administrative actions
- Data Encryption: Encrypt sensitive data at rest and in transit
- SSO/SAML: Support enterprise authentication requirements
- API Security: Use API keys, OAuth2, or JWT for API access
3. Scalability
- Async Processing: Use event-driven architecture for heavy operations
- Caching: Cache frequently accessed data per tenant
- Rate Limiting: Implement per-tenant rate limits
- Database Optimization: Use proper indexes and query optimization
4. Billing
- Accurate Tracking: Track usage in real-time with idempotency
- Flexible Plans: Support multiple pricing models
- Prorations: Handle plan changes with fair prorations
- Failed Payments: Implement retry logic with grace periods
5. Customer Success
- Proactive Monitoring: Track health scores and intervene early
- Onboarding: Guide customers to activation with clear milestones
- Support: Provide self-service resources and AI assistance
- Feedback Loops: Regularly collect and act on customer feedback
6. Analytics
- Real-Time Metrics: Provide dashboards with live data
- Cohort Analysis: Track behavior by signup cohort
- Feature Usage: Monitor which features drive engagement
- Predictive Analytics: Use AI to predict churn and expansion
Complete Implementation
See the full working example at:
Key Takeaways
- Multi-Tenancy First: Design for tenant isolation from day one
- Subscription Lifecycle: Automate the entire subscription journey
- Usage-Based Billing: Track usage accurately and enforce quotas
- Enterprise Features: SSO, SCIM, audit logs are table stakes
- Customer Success: Proactive monitoring prevents churn
- AI Integration: Use AI for support, insights, and automation
Next Steps
- Fintech Platform → - Financial services applications
- Healthcare Platform → - Healthcare management systems
- Architecture Guide → - System design patterns