PSA/ee/docs/tenant-onboarding.md
Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

9.9 KiB

Tenant Onboarding Process

Overview

The tenant onboarding process is a fully automated workflow that provisions new tenants in the Alga PSA system. This process uses Temporal workflows to ensure reliability, consistency, and proper error handling throughout the tenant creation process.

Architecture

Components

  • Temporal Workflows: Orchestrate the multi-step tenant creation process
  • Database Operations: Handle tenant, user, and company creation in PostgreSQL
  • Email Service: Send welcome emails to new admin users
  • Rollback System: Automatic cleanup in case of failures

Key Files

  • ee/temporal-workflows/src/workflows/tenant-creation-workflow.ts - Main workflow orchestration
  • ee/temporal-workflows/src/db/tenant-operations.ts - Database operations for tenant setup
  • ee/temporal-workflows/src/db/user-operations.ts - User creation and management
  • ee/temporal-workflows/src/services/email-service.ts - Email notification service

Workflow Steps

1. Tenant Creation (creating_tenant)

  • Creates tenant record in tenants table
  • Optionally creates company record in companies table
  • Establishes tenant-company relationship
  • Progress: 10% → 40%

2. Admin User Creation (creating_admin_user)

  • Creates admin user in users table
  • Assigns admin role via user_roles table
  • Generates temporary password
  • Progress: 40% → 60%

3. Tenant Data Setup (setting_up_data)

  • Configures tenant email settings in tenant_email_settings
  • Sets up tenant-company associations in tenant_companies
  • Initializes default configurations
  • Progress: 60% → 85%

4. Welcome Email (sending_welcome_email)

  • Sends welcome email to admin user
  • Includes login credentials and setup instructions
  • Progress: 85% → 100%

Database Schema

Core Tables

-- Tenant record
tenants (
  tenant VARCHAR PRIMARY KEY,
  company_name VARCHAR,
  email VARCHAR,
  created_at TIMESTAMP,
  updated_at TIMESTAMP
)

-- Company record
companies (
  company_id VARCHAR PRIMARY KEY,
  company_name VARCHAR,
  tenant VARCHAR REFERENCES tenants(tenant),
  created_at TIMESTAMP,
  updated_at TIMESTAMP
)

-- Admin user
users (
  user_id VARCHAR PRIMARY KEY,
  tenant VARCHAR REFERENCES tenants(tenant),
  first_name VARCHAR,
  last_name VARCHAR,
  email VARCHAR,
  password_hash VARCHAR,
  created_at TIMESTAMP,
  updated_at TIMESTAMP
)

-- User roles
user_roles (
  user_id VARCHAR REFERENCES users(user_id),
  role_id VARCHAR,
  tenant VARCHAR REFERENCES tenants(tenant),
  created_at TIMESTAMP,
  updated_at TIMESTAMP
)

-- Email settings
tenant_email_settings (
  tenant_id VARCHAR,
  email_provider VARCHAR DEFAULT 'resend',
  fallback_enabled BOOLEAN DEFAULT true,
  tracking_enabled BOOLEAN DEFAULT false,
  created_at TIMESTAMP,
  updated_at TIMESTAMP
)

-- Tenant-company associations
tenant_companies (
  tenant VARCHAR REFERENCES tenants(tenant),
  company_id VARCHAR REFERENCES companies(company_id),
  is_default BOOLEAN DEFAULT false,
  created_at TIMESTAMP,
  updated_at TIMESTAMP
)

API Usage

Starting a Tenant Creation Workflow

import { Client } from '@temporalio/client';

const client = new Client({ address: 'localhost:7233' });

const result = await client.workflow.start('tenantCreationWorkflow', {
  workflowId: `tenant-creation-${Date.now()}`,
  taskQueue: 'tenant-creation',
  args: [{
    tenantName: 'Acme Corp',
    adminUser: {
      firstName: 'John',
      lastName: 'Doe', 
      email: 'john.doe@acme.com'
    },
    companyName: 'Acme Corporation',
    contractLine: 'professional'
  }]
});

// Monitor progress
const handle = client.workflow.getHandle(result.workflowId);
const state = await handle.query('getState');
console.log('Current step:', state.step, 'Progress:', state.progress + '%');

Input Parameters

interface TenantCreationInput {
  tenantName: string;              // Display name for the tenant
  adminUser: {
    firstName: string;
    lastName: string;
    email: string;                 // Admin user email (also used for tenant)
  };
  companyName?: string;            // Optional company name
  contractLine?: string;            // Optional contract line (default: 'basic')
}

Output Results

interface TenantCreationResult {
  tenantId: string;                // Generated tenant ID
  adminUserId: string;             // Generated admin user ID
  companyId?: string;              // Generated company ID (if applicable)
  temporaryPassword: string;       // Temporary password for admin user
  emailSent: boolean;              // Whether welcome email was sent
  success: boolean;                // Overall success status
  createdAt: string;               // ISO timestamp of completion
}

Error Handling & Rollback

Automatic Rollback

The workflow includes comprehensive rollback mechanisms:

  1. User Rollback: Removes user records and role assignments
  2. Tenant Rollback: Removes tenant, company, and associated data
  3. Cascade Cleanup: Handles foreign key relationships properly

Error Types

  • ValidationError: Invalid input data (non-retryable)
  • DuplicateError: Tenant/user already exists (non-retryable)
  • DatabaseError: Connection or query issues (retryable)
  • EmailError: Email service failures (retryable)

Retry Policy

retry: {
  maximumAttempts: 3,
  backoffCoefficient: 2.0,
  initialInterval: '1s',
  maximumInterval: '30s',
  nonRetryableErrorTypes: ['ValidationError', 'DuplicateError']
}

Monitoring & Observability

Workflow State Queries

// Get current workflow state
const state = await handle.query('getState');

// State includes:
// - step: Current workflow step
// - progress: Completion percentage (0-100)
// - tenantId: Created tenant ID
// - adminUserId: Created admin user ID
// - companyId: Created company ID
// - emailSent: Email delivery status
// - error: Error message (if failed)

Workflow Signals

// Cancel workflow
await handle.signal('cancel', {
  reason: 'User requested cancellation',
  cancelledBy: 'admin@example.com'
});

// Update workflow parameters
await handle.signal('update', {
  field: 'contractLine',
  value: 'enterprise'
});

Testing

E2E Tests

The system includes comprehensive end-to-end tests:

# Run all E2E tests
cd ee/temporal-workflows
npm run test:e2e

# Run specific tenant creation test
npm run test:e2e -- tenant-creation-workflow.e2e.test.ts

Test Coverage

  • Complete tenant creation workflow
  • Database rollback on failures
  • Email service integration
  • Workflow state management
  • Error handling and retries
  • Signal and query operations

Production Deployment

Prerequisites

  1. Temporal Server: Running and accessible
  2. PostgreSQL: Alga database with proper schema
  3. Email Service: Configured email provider (Resend, AWS SES, etc.)
  4. Worker Process: Temporal worker running with proper activities

Configuration

// Worker configuration
const worker = new Worker({
  taskQueue: 'tenant-creation',
  workflowsPath: require.resolve('./workflows'),
  activitiesPath: require.resolve('./activities'),
  
  // Database connection
  connection: {
    host: process.env.DB_HOST,
    port: parseInt(process.env.DB_PORT || '5432'),
    database: process.env.DB_NAME,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD
  },
  
  // Email service
  email: {
    provider: process.env.EMAIL_PROVIDER || 'resend',
    apiKey: process.env.EMAIL_API_KEY
  }
});

Health Checks

// Basic health check workflow
const health = await client.workflow.execute('healthCheckWorkflow', {
  workflowId: 'health-check',
  taskQueue: 'tenant-creation'
});

console.log('System status:', health.status); // 'healthy'

Security Considerations

Data Protection

  • All passwords are hashed using bcrypt
  • Temporary passwords are cryptographically secure
  • Database connections use SSL/TLS
  • Email content is sanitized

Access Control

  • Workflow execution requires proper Temporal permissions
  • Database operations use principle of least privilege
  • Email service API keys are encrypted at rest

Audit Trail

  • All workflow executions are logged
  • Database operations include audit timestamps
  • Email delivery is tracked and logged

Performance Metrics

Typical Execution Times

  • Total Workflow: 2-5 seconds
  • Database Operations: 1-2 seconds
  • Email Delivery: 1-3 seconds
  • Rollback Operations: 0.5-1 second

Resource Usage

  • Memory: ~50MB per workflow execution
  • CPU: Minimal (I/O bound operations)
  • Database: 5-10 queries per tenant creation

Troubleshooting

Common Issues

  1. Database Connection Failures

    • Check connection string and credentials
    • Verify network connectivity
    • Ensure database schema is up to date
  2. Email Delivery Failures

    • Verify email service API key
    • Check rate limiting and quotas
    • Validate email addresses
  3. Workflow Timeouts

    • Increase timeout values if needed
    • Check for deadlocks or slow queries
    • Monitor system resources

Debugging

// Enable debug logging
const client = new Client({
  address: 'localhost:7233',
  logger: new DefaultLogger('DEBUG')
});

// Query workflow history
const history = await handle.fetchHistory();
console.log('Workflow events:', history.events);

Future Enhancements

Planned Features

  • Bulk Tenant Creation: Support for creating multiple tenants
  • Custom Email Templates: Configurable welcome email content
  • Integration Webhooks: Notify external systems of tenant creation
  • Advanced Analytics: Tenant creation metrics and reporting
  • Self-Service Portal: Allow customers to create their own tenants

Scaling Considerations

  • Database Sharding: For high-volume tenant creation
  • Workflow Batching: Group operations for efficiency
  • Async Email: Decouple email sending from workflow
  • Caching: Cache frequently accessed data