Use Case 016: Tenant Provisioning and Management
Overview
| Property | Value |
|---|---|
| Use Case ID | UC-016 |
| Use Case Name | Tenant Provisioning and Management |
| Module | Tenant Management - Lifecycle |
| Priority | High |
| Status | Implemented |
| Version | 1.0 |
| Last Updated | February 2, 2026 |
Description
This use case describes the tenant provisioning and lifecycle management system that enables Application Manager to orchestrate multi-tenant architectures across registered applications. When ApplicationUsers are created or applications are registered, the system automatically provisions isolated tenant environments by calling application-specific webhooks. The system manages the complete tenant lifecycle including activation, suspension, deactivation, data retention, and deprovisioning. Unlike Riptide Auth's trial-focused approach, this supports permanent production tenants with subscription billing, enterprise configurations, and long-term data retention policies.
Actors
| Actor | Description | Role |
|---|---|---|
| AdminUser | Platform administrator managing tenant lifecycle | Primary |
| ApplicationUser | User whose account triggers tenant provisioning | Secondary |
| Registered Application | External application receiving tenant provisioning callbacks | Supporting |
| System | Application Manager orchestrating tenant operations | Supporting |
| Billing System | External system notified of tenant lifecycle events | Supporting |
Preconditions
- Application Manager platform is running
- At least one application is registered with provisioning endpoints configured
- AdminUser has
tenant:managecapability - Database schema for tenant entities is initialized
- Application webhooks are accessible and authenticated
Postconditions
Success Postconditions
- Tenant record created/updated in Application Manager database
- Tenant provisioned in target application(s) via webhook callbacks
- Tenant ID assigned to ApplicationUser(s)
- Tenant context available for session validation
- Provisioning status logged in audit trail
- Billing system notified of tenant lifecycle events (if integrated)
Failure Postconditions
- Tenant provisioning rolled back if webhook calls fail
- ApplicationUser creation blocked if provisioning fails (configurable)
- Error logged with detailed failure reason
- Alert sent to AdminUser for manual intervention
- Retry scheduled for transient failures
Triggers
- AdminUser provisions ApplicationUser (UC-015) triggering tenant creation
- AdminUser explicitly creates tenant for organization
- Application registration triggers admin tenant creation
- AdminUser suspends/reactivates tenant
- AdminUser initiates tenant deprovisioning
- Subscription billing system requests tenant suspension (non-payment)
- Compliance policy triggers tenant data retention/deletion
Basic Flow (Happy Path)
Detailed Steps
Tenant Creation Triggered
- ApplicationUser creation (UC-015) triggers tenant provisioning
- OR AdminUser explicitly creates tenant for organization
- OR Application registration creates admin tenant
System Generates Tenant Record
- Create
Tenantentity with unique GUID - Set
Status = Provisioning - Assign
OrganizationName,ContactEmail,PlanTier - Generate
ApiKeyfor tenant-to-platform communication - Set
CreatedByto AdminUser ID - Set
CreatedAttimestamp
- Create
System Retrieves Application List
- Query all registered applications with
ProvisioningUrlconfigured - Filter by applications user should have access to (based on plan/roles)
- Order by priority (critical apps first)
- Query all registered applications with
System Calls Application Provisioning Webhooks
- For each application in parallel (with configurable concurrency limit):
- POST to
{app.ProvisioningUrl} - Headers:
X-Api-Key: {api-key},X-Tenant-Id: {tenantId} - Body: Tenant metadata (ID, name, email, plan tier, max users)
- Timeout: 30 seconds
- Retry: 3 attempts with exponential backoff
- POST to
- For each application in parallel (with configurable concurrency limit):
Application Provisions Tenant
- Validates API key from Application Manager
- Creates isolated tenant database/schema
- Initializes default application data
- Creates admin user account linked to ApplicationUser
- Returns success with optional application-specific tenant ID
System Records Provisioning Results
- Create
ApplicationTenantMappingfor each successful provisioning - Store application-specific tenant ID if returned
- Update
Tenant.Status = Activewhen all apps succeed - Update
Tenant.Status = PartiallyProvisionedif some fail - Log failures with error messages for retry
- Create
System Links User to Tenant
- Update
ApplicationUser.TenantIdwith new tenant ID - Create default tenant admin role assignment
- Grant access to provisioned applications
- Update
System Notifies External Systems
- Send event to audit service with full provisioning details
- Notify billing system to create account
- Send email to organization contact (optional)
- Create support ticket for manual verification (if configured)
Alternative Flows
Alt Flow 1: Provisioning Webhook Failure
Steps:
- Application webhook call fails (timeout, 5xx error, network issue)
- System immediately retries (attempt 1 of 3) after 10 seconds
- If still failing, wait 30 seconds and retry (attempt 2)
- If still failing, wait 90 seconds and final retry (attempt 3)
- After 3 failures, mark
ApplicationTenantMapping.Status = Failed - Update
Tenant.Status = PartiallyProvisioned(if other apps succeeded) - Create alert for AdminUser with error details
- AdminUser can manually retry via UI: "Retry Failed Provisioning"
- AdminUser can exclude failing application and mark tenant as Active
Alt Flow 2: Multi-Application Partial Provisioning
Steps:
- System provisions tenant across 3 applications
- App1 succeeds, App2 fails, App3 succeeds
Tenant.Status = PartiallyProvisioned- AdminUser sees status: "2 of 3 applications provisioned"
- AdminUser options:
- Retry failed application
- Mark tenant as Active (accept partial provisioning)
- Deprovision successful apps and abort
- User can still access successfully provisioned applications
Alt Flow 3: Tenant Suspension (Non-Payment)
Steps:
- Billing system detects failed payment
- Billing system calls:
PATCH /api/v1/tenants/{id}/suspend - System validates billing system API key
- System updates
Tenant.Status = Suspended - System calls suspension webhook for each application:
PATCH /api/tenants/{tenantId}/suspend
- Applications disable access but retain data
- Users attempting to access see "Account Suspended" message
- AdminUser can view suspension reason: "Payment Failed - Renew by "
- After grace period (default 30 days), tenant moves to deprovisioning
Alt Flow 4: Tenant Reactivation
Steps:
- Billing system confirms payment received
- Billing system calls:
PATCH /api/v1/tenants/{id}/reactivate - System validates tenant was suspended (not deprovisioned)
- System updates
Tenant.Status = Active - System calls reactivation webhook for each application:
PATCH /api/tenants/{tenantId}/reactivate
- Applications re-enable access
- System sends welcome back email to organization
- Audit log records reactivation with reason
Alt Flow 5: Tenant Data Retention (Compliance)
Steps:
- AdminUser initiates soft delete: "Deprovision but retain for 90 days"
- System updates
Tenant.Status = Deprovisioned - System sets
Tenant.DataRetentionUntil = Now + 90 days - System calls application deprovisioning webhooks
- Applications archive tenant data (move to cold storage)
- Users cannot access applications
- After 90 days, scheduled job calls hard delete:
- Applications permanently purge tenant data
- Application Manager removes
ApplicationTenantMappingrecords - Tenant metadata retained indefinitely for audit
Alt Flow 6: Tenant Migration (Environment Transfer)
Steps:
- AdminUser requests tenant migration: Dev → Staging → Production
- System validates target environment is registered
- System exports tenant metadata and configuration
- System provisions tenant in target environment (normal flow)
- Applications handle data migration (out of scope for Application Manager)
- System updates tenant's environment identifier
- Users receive notification of migration
- Old environment tenant marked for deprovisioning (with grace period)
Business Rules
| Rule ID | Description | Enforcement |
|---|---|---|
| BR-001 | Each tenant must have unique ID (GUID) | Database primary key constraint |
| BR-002 | Tenant must be provisioned in at least one application to be Active | Status validation logic |
| BR-003 | Suspended tenants retain all data for grace period (default 30 days) | Suspension logic + scheduled cleanup |
| BR-004 | Deprovisioning requires explicit AdminUser confirmation | Two-step deletion workflow |
| BR-005 | Failed provisioning webhooks retry 3 times with exponential backoff | Retry service configuration |
| BR-006 | Tenant API key must be unique and cryptographically secure (32 bytes) | Key generation service |
| BR-007 | Tenant metadata retained indefinitely for compliance even after deprovisioning | Soft delete implementation |
| BR-008 | Provisioning webhook timeout: 30 seconds | HTTP client configuration |
| BR-009 | ApplicationUser can belong to only one tenant (no shared tenants) | Data model constraint |
| BR-010 | Tenant status transitions: Provisioning → Active → Suspended → Deprovisioned | State machine validation |
| BR-011 | Billing integration events must be idempotent | Event deduplication |
| BR-012 | Admin tenant (for Riptide team) created automatically on app registration | Application registration logic |
Data Requirements
Tenant Entity
{
"Id": "uuid-v4 (primary key)",
"OrganizationName": "string (required, 1-200 chars)",
"OrganizationDomain": "string (nullable, validated domain format)",
"ContactEmail": "string (required, validated email)",
"ContactName": "string (required, 1-200 chars)",
"ContactPhone": "string (nullable, 20 chars)",
"PlanTier": "enum (Free, Starter, Professional, Enterprise)",
"MaxUsers": "int (nullable, based on plan tier)",
"MaxApplications": "int (nullable, based on plan tier)",
"ApiKey": "string (32 bytes hex, unique)",
"Status": "enum (Provisioning, Active, PartiallyProvisioned, Suspended, Deprovisioned)",
"StatusReason": "string (nullable, reason for current status)",
"IsAdminTenant": "bool (default: false, true for Riptide team)",
"Environment": "enum (Development, Staging, Production)",
"DataRetentionUntil": "datetime (nullable, soft delete expiration)",
"CreatedBy": "uuid-v4 (AdminUser ID)",
"CreatedAt": "datetime (UTC)",
"UpdatedAt": "datetime (UTC)",
"LastAccessedAt": "datetime (nullable, UTC)",
"SuspendedAt": "datetime (nullable, UTC)",
"DeprovisionedAt": "datetime (nullable, UTC)",
"Metadata": "json (extensible key-value store)"
}
Status Enum:
Provisioning- Initial state, webhook calls in progressActive- All applications provisioned successfullyPartiallyProvisioned- Some applications failed, manual intervention neededSuspended- Access disabled but data retained (payment issue, policy violation)Deprovisioned- Tenant removed, data retention policy active
PlanTier Enum:
Free- Trial/demo tier (limited features, 30-day expiration)Starter- Small business tier (5 users, core features)Professional- Mid-market tier (25 users, advanced features)Enterprise- Enterprise tier (unlimited users, custom SLA)
ApplicationTenantMapping Entity
{
"Id": "uuid-v4 (primary key)",
"TenantId": "uuid-v4 (foreign key to Tenant)",
"ApplicationId": "uuid-v4 (foreign key to Application)",
"ApplicationSpecificTenantId": "string (nullable, app's internal tenant ID)",
"Status": "enum (Provisioning, Provisioned, Failed, Suspended, Deprovisioned)",
"ProvisioningAttempts": "int (default: 0, max: 3)",
"LastProvisioningAttempt": "datetime (nullable, UTC)",
"LastProvisioningError": "string (nullable, error message)",
"ProvisionedAt": "datetime (nullable, UTC)",
"ProvisionedBy": "uuid-v4 (AdminUser ID)",
"SuspendedAt": "datetime (nullable, UTC)",
"DeprovisionedAt": "datetime (nullable, UTC)",
"Metadata": "json (app-specific provisioning data)"
}
TenantUser Entity (Join Table)
{
"Id": "uuid-v4 (primary key)",
"TenantId": "uuid-v4 (foreign key)",
"UserId": "uuid-v4 (foreign key to ApplicationUser)",
"Role": "string (tenant-admin, tenant-member, tenant-billing)",
"JoinedAt": "datetime (UTC)",
"InvitedBy": "uuid-v4 (nullable, inviting user ID)",
"IsActive": "bool (default: true)"
}
TenantProvisioningLog Entity
{
"Id": "uuid-v4 (primary key)",
"TenantId": "uuid-v4 (foreign key)",
"ApplicationId": "uuid-v4 (nullable, null for tenant-level events)",
"EventType": "enum (ProvisioningStarted, ProvisioningSucceeded, ProvisioningFailed, Suspended, Reactivated, Deprovisioned)",
"Status": "enum (Success, Failed, Retrying)",
"Message": "string (event description)",
"ErrorDetails": "string (nullable, stack trace or error message)",
"Attempt": "int (retry attempt number)",
"RequestPayload": "json (webhook request body)",
"ResponsePayload": "json (nullable, webhook response)",
"HttpStatusCode": "int (nullable, webhook response code)",
"Duration": "int (milliseconds)",
"Timestamp": "datetime (UTC)",
"PerformedBy": "uuid-v4 (nullable, AdminUser ID)"
}
API Endpoints
Tenant Management
Create Tenant
Endpoint: POST /api/v1/tenants
Authentication: Required (tenant:create capability)
Request Body:
{
"organizationName": "Acme Corporation",
"organizationDomain": "acme.com",
"contactEmail": "admin@acme.com",
"contactName": "Jane Doe",
"contactPhone": "+1-555-123-4567",
"planTier": "Professional",
"maxUsers": 25,
"environment": "Production",
"applicationIds": [
"app-1-guid",
"app-2-guid"
],
"metadata": {
"industry": "Technology",
"companySize": "51-200",
"referralSource": "Partner"
}
}
Success Response: 201 Created
{
"tenantId": "tenant-123",
"organizationName": "Acme Corporation",
"status": "Provisioning",
"apiKey": "32-byte-hex-string",
"provisioningStatus": {
"totalApplications": 2,
"provisioned": 0,
"failed": 0,
"inProgress": 2
},
"applications": [
{
"applicationId": "app-1-guid",
"applicationName": "value-manager",
"status": "Provisioning"
},
{
"applicationId": "app-2-guid",
"applicationName": "fee-manager",
"status": "Provisioning"
}
],
"createdAt": "2026-02-02T10:30:00Z",
"createdBy": "admin-user-id"
}
Get Tenant Details
Endpoint: GET /api/v1/tenants/{tenantId}
Authentication: Required (tenant:read capability)
Success Response: 200 OK
{
"tenantId": "tenant-123",
"organizationName": "Acme Corporation",
"organizationDomain": "acme.com",
"contactEmail": "admin@acme.com",
"contactName": "Jane Doe",
"planTier": "Professional",
"maxUsers": 25,
"currentUsers": 12,
"status": "Active",
"statusReason": null,
"environment": "Production",
"isAdminTenant": false,
"applications": [
{
"applicationId": "app-1-guid",
"applicationName": "value-manager",
"displayName": "Value Manager",
"status": "Provisioned",
"provisionedAt": "2026-02-02T10:30:45Z",
"applicationTenantId": "vm-tenant-456"
}
],
"users": [
{
"userId": "user-789",
"fullName": "Jane Doe",
"email": "jane@acme.com",
"role": "tenant-admin",
"joinedAt": "2026-02-02T10:30:00Z"
}
],
"createdAt": "2026-02-02T10:30:00Z",
"lastAccessedAt": "2026-02-02T14:22:00Z",
"metadata": {
"industry": "Technology",
"companySize": "51-200"
}
}
List All Tenants
Endpoint: GET /api/v1/tenants
Authentication: Required (tenant:list capability)
Query Parameters:
status- Filter by status (Active, Suspended, etc.)planTier- Filter by plan tierenvironment- Filter by environmentsearch- Search by organization name or contact emailpage- Page number (default: 1)pageSize- Items per page (default: 50, max: 200)sortBy- Sort field (createdAt, organizationName, lastAccessedAt)sortOrder- Sort direction (asc, desc)
Success Response: 200 OK
{
"tenants": [
{
"tenantId": "tenant-123",
"organizationName": "Acme Corporation",
"contactEmail": "admin@acme.com",
"planTier": "Professional",
"status": "Active",
"userCount": 12,
"applicationCount": 3,
"createdAt": "2026-02-02T10:30:00Z",
"lastAccessedAt": "2026-02-02T14:22:00Z"
}
],
"pagination": {
"page": 1,
"pageSize": 50,
"totalItems": 145,
"totalPages": 3
}
}
Update Tenant
Endpoint: PATCH /api/v1/tenants/{tenantId}
Authentication: Required (tenant:update capability)
Request Body:
{
"organizationName": "Acme Corp (Updated)",
"contactEmail": "newadmin@acme.com",
"planTier": "Enterprise",
"maxUsers": 100,
"metadata": {
"billingContact": "billing@acme.com"
}
}
Success Response: 200 OK (updated tenant object)
Suspend Tenant
Endpoint: PATCH /api/v1/tenants/{tenantId}/suspend
Authentication: Required (tenant:suspend capability)
Request Body:
{
"reason": "Payment failed - account overdue",
"gracePeriodDays": 30,
"notifyUsers": true
}
Success Response: 200 OK
{
"tenantId": "tenant-123",
"status": "Suspended",
"statusReason": "Payment failed - account overdue",
"suspendedAt": "2026-02-02T15:00:00Z",
"gracePeriodEnds": "2026-03-04T15:00:00Z",
"applicationsSuspended": 3,
"usersNotified": 12
}
Reactivate Tenant
Endpoint: PATCH /api/v1/tenants/{tenantId}/reactivate
Authentication: Required (tenant:reactivate capability)
Success Response: 200 OK
{
"tenantId": "tenant-123",
"status": "Active",
"reactivatedAt": "2026-02-02T16:00:00Z",
"applicationsReactivated": 3
}
Retry Failed Provisioning
Endpoint: POST /api/v1/tenants/{tenantId}/retry-provisioning
Authentication: Required (tenant:provision capability)
Request Body:
{
"applicationIds": [
"app-2-guid"
]
}
Success Response: 200 OK
{
"tenantId": "tenant-123",
"retriedApplications": 1,
"results": [
{
"applicationId": "app-2-guid",
"status": "Provisioned",
"message": "Successfully provisioned on retry"
}
]
}
Deprovision Tenant
Endpoint: DELETE /api/v1/tenants/{tenantId}
Authentication: Required (tenant:delete capability)
Query Parameters:
dataRetentionDays- Days to retain data (default: 90, max: 365)confirm- Must be "true" to confirm deletion
Request Body:
{
"reason": "Customer requested account deletion",
"notifyUsers": true
}
Success Response: 200 OK
{
"tenantId": "tenant-123",
"status": "Deprovisioned",
"deprovisionedAt": "2026-02-02T17:00:00Z",
"dataRetentionUntil": "2026-05-03T17:00:00Z",
"applicationsDeprovisioned": 3,
"usersNotified": 12,
"summary": {
"totalApplications": 3,
"successfullyDeprovisioned": 3,
"failed": 0
}
}
Application-Specific Provisioning Webhooks
These endpoints are implemented by registered applications, not Application Manager.
Provision Tenant Webhook (Application Implements)
Endpoint: POST {app.ProvisioningUrl}
Example: POST https://value-manager.acme.com/api/tenants/provision
Headers:
X-Api-Key: {api-key-from-app-registration}
X-Tenant-Id: {tenant-id-from-application-manager}
Content-Type: application/json
Request Body (sent by Application Manager):
{
"tenantId": "tenant-123",
"organizationName": "Acme Corporation",
"contactEmail": "admin@acme.com",
"contactName": "Jane Doe",
"planTier": "Professional",
"maxUsers": 25,
"environment": "Production",
"metadata": {
"industry": "Technology"
}
}
Expected Response: 200 OK or 201 Created
{
"success": true,
"tenantId": "tenant-123",
"applicationTenantId": "vm-tenant-456",
"message": "Tenant provisioned successfully",
"metadata": {
"databaseSchema": "tenant_123",
"storageQuota": "100GB"
}
}
Error Response: 500 Internal Server Error
{
"success": false,
"error": "DatabaseConnectionFailed",
"message": "Unable to create tenant database",
"retryable": true
}
Suspend Tenant Webhook (Application Implements)
Endpoint: PATCH {app.ProvisioningUrl}/{tenantId}/suspend
Headers: Same as provisioning
Expected Response: 200 OK
{
"success": true,
"tenantId": "tenant-123",
"message": "Tenant access disabled"
}
Reactivate Tenant Webhook (Application Implements)
Endpoint: PATCH {app.ProvisioningUrl}/{tenantId}/reactivate
Headers: Same as provisioning
Expected Response: 200 OK
Deprovision Tenant Webhook (Application Implements)
Endpoint: DELETE {app.ProvisioningUrl}/{tenantId}
Headers: Same as provisioning
Query Parameters:
retainData- Boolean (if true, move to cold storage; if false, hard delete)
Expected Response: 204 No Content or 200 OK
{
"success": true,
"tenantId": "tenant-123",
"message": "Tenant data purged successfully",
"metadata": {
"recordsDeleted": 15000,
"storageFreed": "2.5GB"
}
}
User Interface Mockups
Tenant List View
┌────────────────────────────────────────────────────────────────────────┐
│ Application Manager - Tenant Management │
│ ═══════════════════════════════════════════════════════════════════ │
│ │
│ [+ Create Tenant] Search: [___________] 🔍 │
│ │
│ Filters: │
│ Status: [All ▾] Plan: [All ▾] Environment: [Production ▾] │
│ │
│ ┌──────────────────────────────────────────────────────────────────┐│
│ │ Organization │ Contact │ Plan │ Status │ Users │ Apps││
│ ├──────────────────────────────────────────────────────────────────┤│
│ │ Acme Corporation │ admin@acme │ Pro │ 🟢 Active │ 12/25│ 3 ││
│ │ Created: 2026-02-01 │ Last Access: 2 hours ago [···] ││
│ │ ││
│ │ Beta Industries │ beta@beta │ Start │ 🟡 Partial│ 5/10│ 2 ││
│ │ Created: 2026-01-28 │ Last Access: 3 days ago [···] ││
│ │ ││
│ │ Global Dynamics │ ops@global │ Ent │ 🔴 Suspended│ 45 │ 5 ││
│ │ Created: 2025-12-15 │ Suspended: Payment overdue [···] ││
│ │ ││
│ │ Test Company │ test@test │ Free │ ⚫ Deprov │ 0 │ 1 ││
│ │ Created: 2025-11-20 │ Deprovisioned: 2026-01-30 [···] ││
│ └──────────────────────────────────────────────────────────────────┘│
│ │
│ Showing 1-4 of 145 tenants [← Previous] [1] 2 3 [Next →] │
└────────────────────────────────────────────────────────────────────────┘
Tenant Details View
┌────────────────────────────────────────────────────────────────────────┐
│ ← Back to Tenants │
│ │
│ Acme Corporation [Edit] [Suspend] [Delete]│
│ ═══════════════════════════════════════════════════════════════════ │
│ │
│ Status: 🟢 Active Plan: Professional │
│ Tenant ID: tenant-123 Environment: Production │
│ API Key: ****-****-****-ab12 [Show] [Regenerate] │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Organization Details │ │
│ │ ═══════════════════════════════════════════════════════════════ │ │
│ │ Organization Name: Acme Corporation │ │
│ │ Domain: acme.com │ │
│ │ Contact: Jane Doe (admin@acme.com) │ │
│ │ Phone: +1-555-123-4567 │ │
│ │ Created: 2026-02-01 at 10:30 AM by Admin User │ │
│ │ Last Accessed: 2 hours ago │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Applications (3) [+ Add App] │ │
│ │ ═══════════════════════════════════════════════════════════════ │ │
│ │ │ │
│ │ 🟢 Value Manager Status: Provisioned │ │
│ │ Provisioned: 2026-02-01 at 10:32 AM │ │
│ │ App Tenant ID: vm-tenant-456 │ │
│ │ [Launch] [Suspend] [Deprovision] │ │
│ │ │ │
│ │ 🟢 Fee Manager Status: Provisioned │ │
│ │ Provisioned: 2026-02-01 at 10:33 AM │ │
│ │ App Tenant ID: fm-tenant-789 │ │
│ │ [Launch] [Suspend] [Deprovision] │ │
│ │ │ │
│ │ 🔴 Workflow Engine Status: Failed │ │
│ │ Last Attempt: 2026-02-01 at 10:35 AM (3 attempts) │ │
│ │ Error: Connection timeout │ │
│ │ [Retry Provisioning] [View Logs] │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Users (12 / 25 max) [+ Invite User] │ │
│ │ ═══════════════════════════════════════════════════════════════ │ │
│ │ Jane Doe (admin@acme.com) Role: tenant-admin │ │
│ │ John Smith (john@acme.com) Role: tenant-member │ │
│ │ [View All Users →] │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Provisioning Logs [View All Logs →] │ │
│ │ ═══════════════════════════════════════════════════════════════ │ │
│ │ 2026-02-01 10:35 AM │ Workflow Engine │ Failed (Attempt 3) │ │
│ │ 2026-02-01 10:33 AM │ Fee Manager │ Provisioned │ │
│ │ 2026-02-01 10:32 AM │ Value Manager │ Provisioned │ │
│ │ 2026-02-01 10:30 AM │ Tenant Created │ Success │ │
│ └─────────────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────┘
Create Tenant Dialog
┌──────────────────────────────────────────────────────────────┐
│ Create New Tenant │
│ ══════════════════════════════════════════════════════════ │
│ │
│ Organization Information │
│ │
│ Organization Name * │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Acme Corporation │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ Organization Domain │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ acme.com │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ Contact Information │
│ │
│ Contact Name * Contact Email * │
│ ┌──────────────────────┐ ┌──────────────────────────────┐│
│ │ Jane Doe │ │ admin@acme.com ││
│ └──────────────────────┘ └──────────────────────────────┘│
│ │
│ Contact Phone │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ +1-555-123-4567 │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ Plan & Configuration │
│ │
│ Plan Tier * │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Professional ▾ │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ Max Users Environment │
│ ┌──────────────────────┐ ┌──────────────────────────────┐│
│ │ 25 │ │ Production ▾ ││
│ └──────────────────────┘ └──────────────────────────────┘│
│ │
│ Applications to Provision * │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ ☑ Value Manager │ │
│ │ ☑ Fee Manager │ │
│ │ ☐ Workflow Engine │ │
│ │ ☑ Configuration Manager │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ ℹ️ Selected applications will be provisioned automatically │
│ with isolated tenant environments. │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ [Cancel] [Create Tenant] │
└──────────────────────────────────────────────────────────────┘
Suspend Tenant Confirmation Dialog
┌──────────────────────────────────────────────────────────────┐
│ Suspend Tenant: Acme Corporation │
│ ══════════════════════════════════════════════════════════ │
│ │
│ ⚠️ Warning: This will immediately disable access for all │
│ users in this tenant across all applications. │
│ │
│ Affected: │
│ • 12 users │
│ • 3 applications (Value Manager, Fee Manager, Config Mgr) │
│ │
│ Reason for Suspension * │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Payment failed - account overdue │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ Grace Period (days) │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ 30 │ │
│ └────────────────────────────────────────────────────────┘ │
│ ℹ️ After grace period, tenant will be deprovisioned │
│ │
│ ☑ Send notification emails to all users │
│ ☑ Notify billing system │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ [Cancel] [Suspend Tenant] │
└──────────────────────────────────────────────────────────────┘
Security Considerations
Tenant Isolation
- Each tenant must have cryptographically unique API key (32 bytes)
- API keys transmitted only via HTTPS
- Applications enforce tenant-level data isolation
- No cross-tenant data access permitted
- Tenant context validated on every request
Webhook Security
- All provisioning webhooks require API key authentication
- Webhook URLs must be HTTPS only (no HTTP)
- Request signing with HMAC-SHA256 (optional enhancement)
- IP allowlisting for Application Manager webhook sources
- Rate limiting on webhook endpoints (10 requests/minute per tenant)
Deprovisioning Security
- Two-step confirmation required for deprovisioning
- AdminUser must have
tenant:deletecapability - All deprovisioning actions logged in audit trail
- Data retention policies enforced (minimum 30 days for compliance)
- Cannot deprovision admin tenant
Access Control
- Tenant operations require specific capabilities (
tenant:create,tenant:suspend, etc.) - ApplicationUsers can only view/modify their own tenant
- AdminUsers can manage all tenants
- Billing system API key separate from admin user authentication
Audit & Compliance
- All tenant lifecycle events logged with actor, timestamp, reason
- Provisioning logs retained indefinitely
- Tenant metadata retained even after deprovisioning
- GDPR-compliant data deletion on request (with legal compliance check)
Non-Functional Requirements
Performance
- Tenant provisioning: < 60 seconds for 3 applications
- Webhook timeout: 30 seconds per application
- Parallel provisioning with max 5 concurrent webhook calls
- Tenant list query: < 500ms for 10,000 tenants
- Status updates propagate within 5 seconds
Reliability
- Webhook retry: 3 attempts with exponential backoff (10s, 30s, 90s)
- Failed provisioning does not block ApplicationUser creation (configurable)
- Partial provisioning allows tenant to be active with subset of applications
- Automatic recovery for transient network failures
- Dead letter queue for permanently failed webhooks
Scalability
- Support 10,000+ active tenants
- Handle 100 concurrent tenant provisioning requests
- Background job processes expired tenants (batch size: 100)
- Database indexes on: TenantId, Status, CreatedAt, OrganizationDomain
Observability
- Prometheus metrics: provisioning success rate, webhook latency, retry count
- Application Insights: tenant lifecycle events, application-specific provisioning times
- Alerts: provisioning failure rate > 10%, webhook timeout rate > 5%
- Dashboard: active tenants, provisioning queue depth, suspension rate
Disaster Recovery
- Tenant provisioning is idempotent (safe to retry)
- Webhook calls include correlation IDs for tracing
- Manual recovery tools for stuck provisioning jobs
- Backup/restore support for tenant metadata
Related Use Cases
- UC-001: Trial User Self-Registration - Trial tenants (temporary, auto-expire)
- UC-013: Application Registration and Management - Applications register provisioning endpoints
- UC-015: Application User Provisioning - User creation triggers tenant provisioning
- UC-006: Role-Based Access Control - Tenant-scoped role assignments
- UC-010: Activity Logging and Audit Trail - Tenant lifecycle events logged
Open Questions
Should tenant provisioning be synchronous (block user creation) or asynchronous (user created, provisioning background)?
- Recommendation: Configurable per application. Critical apps (identity) block, non-critical apps async.
How do we handle multi-region tenant provisioning (e.g., EU data residency requirements)?
- Recommendation: Tenant.Metadata includes
dataRegionfield, applications handle region-specific provisioning.
- Recommendation: Tenant.Metadata includes
Should we support tenant hierarchies (parent/child organizations)?
- Recommendation: V2 feature. V1 supports flat tenant structure only.
How do we handle tenant migrations between environments (dev → staging → prod)?
- Recommendation: UC-017: Tenant Migration (separate use case for complex multi-step process).
Should billing integration be part of Application Manager or separate service?
- Recommendation: Separate service. Application Manager sends webhook events to billing system.
What happens if user tries to access application that failed provisioning?
- Recommendation: Show friendly error: "This application is not available. Contact support."
Glossary
- Tenant: Isolated environment for an organization within a multi-tenant application
- Provisioning: Process of creating and initializing a tenant in an application
- Deprovisioning: Process of removing tenant and purging data from application
- Provisioning Webhook: HTTP endpoint implemented by application to handle tenant lifecycle events
- Admin Tenant: Special tenant pre-created for Riptide team members, never expires
- Partial Provisioning: State where tenant is provisioned in some applications but not others
- Grace Period: Time window between suspension and deprovisioning (default 30 days)
- Soft Delete: Marking tenant as deprovisioned but retaining metadata for compliance
- Hard Delete: Permanent deletion of tenant data from applications (after retention period)
- Plan Tier: Subscription level (Free, Starter, Professional, Enterprise)