WorkflowMedium

SaaS Customer Onboarding

Orchestrate account setup, welcome emails, and billing provisioning.

The Challenge

When a user signs up, multiple systems need to be provisioned:

  1. Identity: Create user in Auth0.
  2. Billing: Create customer in Stripe.
  3. CRM: Create contact in HubSpot.
  4. Email: Send welcome sequence.

If step 3 fails, we shouldn't leave a "zombie" user in Auth0 and Stripe.

The Solution

A workflow implementing the Saga Pattern to ensure data consistency across microservices.

Workflow Definition

import { defineWorkflow } from '@dataflows/core'
import { auth0 } from '@dataflows/auth0'
import { stripe } from '@dataflows/stripe'
import { sendgrid } from '@dataflows/sendgrid'

export const onboarding = defineWorkflow({
  id: 'customer-onboarding',
  trigger: { type: 'webhook', path: '/signup' },
  
  async run({ event, step }) {
    const { email, password } = event.body
    const compensation = []

    try {
      // 1. Create Auth0 User
      const user = await step.run('create-auth0', async () => {
        return auth0.createUser({ email, password })
      })
      compensation.push(() => auth0.deleteUser(user.id))

      // 2. Create Stripe Customer
      const customer = await step.run('create-stripe', async () => {
        return stripe.customers.create({ email })
      })
      compensation.push(() => stripe.customers.del(customer.id))

      // 3. Send Welcome Email
      await step.run('send-email', async () => {
        await sendgrid.send({
          to: email,
          templateId: 'd-welcome-123'
        })
      })

    } catch (error) {
      // Rollback on failure
      await step.run('rollback', async () => {
        for (const undo of compensation.reverse()) {
          await undo()
        }
      })
      throw error
    }
  }
})

Features

Parallel Execution

Provisions services in parallel to speed up onboarding.

Compensation Logic

Rolls back changes if any step fails (Saga Pattern).

Tech Stack

StripeAuth0SendGrid