BaasixBaasix

Multi-tenant Guide

← Back to Documentation Home

Table of Contents

  1. Overview
  2. Configuration
  3. Data Isolation
  4. Tenant Management
  5. Authentication with Tenants
  6. Tenant-Specific vs Non-Tenant-Specific Roles
  7. Invitation System
  8. Tenant-Specific Permissions
  9. Schema Considerations
  10. Best Practices

Overview

Multi-tenancy in BAASIX allows you to host multiple separate client organizations (tenants) within a single instance of the application. Each tenant has their own isolated data, users, and permissions, while sharing the same underlying infrastructure and codebase.

Configuration

Enable multi-tenant mode by setting the appropriate environment variable:

# Enable multi-tenant functionality
MULTI_TENANT=true

# Define roles that are allowed for multi-tenant registration
# These are the roles that can be assigned when a user registers with a new tenant
ALLOWED_ROLES_MULTI_TENANT=user,customer,member

# Optional: Define the system field name for tenant identification
# Default is tenant_Id
TENANT_FIELD=tenant_Id

Data Isolation

When multi-tenant mode is enabled, BAASIX automatically:

  1. Adds a tenant_Id field to all non-system collections (tables that don't start with baasix_)
  2. Creates a relationship between each collection and the baasix_Tenant table
  3. Modifies all unique constraints to be tenant-aware (unique per tenant rather than globally)
  4. Automatically filters all queries to only return data from the current tenant

Database Schema Changes

For each non-system collection, the following field is added:

"tenant_Id": {
  "type": "UUID",
  "allowNull": false,
  "SystemGenerated": "true",
  "description": "Tenant identifier for multi-tenant isolation"
},
"tenant": {
  "relType": "BelongsTo",
  "target": "baasix_Tenant",
  "foreignKey": "tenant_Id",
  "as": "tenant",
  "SystemGenerated": "true",
  "description": "M2O relationship to tenant"
}

Tenant Management

Creating Tenants

Tenants can be created via the API:

POST /items/baasix_Tenant
Authorization: Bearer <admin_token>
Content-Type: application/json

{
  "name": "Organization Name",
  "code": "org-code",
  "settings": {
    "brandColor": "#ff0000",
    "maxUsers": 100
    // Any tenant-specific settings
  }
}

Listing Tenants

GET /items/baasix_Tenant
Authorization: Bearer <admin_token>

Updating Tenants

PATCH /items/baasix_Tenant/:id
Authorization: Bearer <admin_token>
Content-Type: application/json

{
  "name": "Updated Organization Name",
  "settings": {
    "brandColor": "#00ff00"
  }
}

Deleting Tenants

DELETE /items/baasix_Tenant/:id
Authorization: Bearer <admin_token>

Authentication with Tenants

User Registration with Tenant

In multi-tenant mode, when registering a user, you must provide tenant information:

POST /auth/register
Content-Type: application/json

{
  "firstName": "John",
  "lastName": "Doe",
  "email": "john@example.com",
  "password": "securePassword123",
  "tenant": {
    "name": "New Tenant Organization"
  }
}

You can also specify an optional role if allowed by your configuration:

POST /auth/register
Content-Type: application/json

{
  "firstName": "John",
  "lastName": "Doe", 
  "email": "john@example.com",
  "password": "securePassword123",
  "tenant": {
    "name": "New Tenant Organization"
  },
  "roleName": "user"
}

Login with Tenant Selection

When logging in, you can optionally specify a tenant ID if the user has access to multiple tenants:

POST /auth/login
Content-Type: application/json

{
  "email": "john@example.com",
  "password": "securePassword123",
  "tenant_Id": "550e8400-e29b-41d4-a716-446655440000"
}

Switching Tenants

If a user has access to multiple tenants, they can switch between them:

POST /auth/switch-tenant
Authorization: Bearer <token>
Content-Type: application/json

{
  "tenant_Id": "8a7d1ed4-8d7f-44b3-8f5e-7e5f2d8a7d3c"
}

Getting Available Tenants

GET /auth/tenants
Authorization: Bearer <token>

Tenant-Specific vs Non-Tenant-Specific Roles

BAASIX supports both tenant-specific and non-tenant-specific roles, which behave differently in a multi-tenant environment:

Tenant-Specific Roles

  • Marked with isTenantSpecific: true
  • Always associated with a specific tenant
  • Can only access data within their assigned tenant
  • Users with tenant-specific roles must specify or default to a tenant when logging in
POST /items/baasix_Role
Authorization: Bearer <admin_token>
Content-Type: application/json

{
  "name": "tenant_admin",
  "description": "Administrator for a specific tenant",
  "isTenantSpecific": true
}

Non-Tenant-Specific Roles

  • Marked with isTenantSpecific: false
  • Not bound to any specific tenant
  • Can potentially access data across tenants (subject to permissions)
  • Users with non-tenant-specific roles can login without specifying a tenant
POST /items/baasix_Role
Authorization: Bearer <admin_token>
Content-Type: application/json

{
  "name": "global_admin",
  "description": "Administrator with cross-tenant access",
  "isTenantSpecific": false
}

Handling Users with Multiple Roles

A user can have both tenant-specific and non-tenant-specific roles. In this case:

  • If the user logs in without a specified tenant, the system will use their non-tenant-specific role
  • If the user logs in with a specific tenant ID, the system will use their tenant-specific role for that tenant

Invitation System

BAASIX provides a comprehensive invitation system designed specifically for multi-tenant environments, allowing tenant administrators to invite users to their tenant with appropriate roles.

Role-Based Invitation Permissions

Roles can be configured with permissions to invite users with specific roles:

PATCH /items/baasix_Role/:id
Authorization: Bearer <admin_token>
Content-Type: application/json

{
  "canInviteRoleIds": ["550e8400-e29b-41d4-a716-446655440000", "8a7d1ed4-8d7f-44b3-8f5e-7e5f2d8a7d3c"]
}

The canInviteRoleIds array contains the IDs of roles that users with this role are allowed to invite.

Creating Invitations

Tenant administrators can create invitations for users to join their tenant:

POST /auth/invite
Authorization: Bearer <admin_token>
Content-Type: application/json

{
  "email": "newuser@example.com",
  "role_Id": "4a7d1ed4-8d7f-44b3-8f5e-7e5f2d8a7d3c",
  "tenant_Id": "8a7d1ed4-8d7f-44b3-8f5e-7e5f2d8a7d3c",
  "link": "https://yourapp.com"
}

Invitation Workflow

The invitation system supports both new and existing users:

  1. For new users:

    • Admin sends an invitation
    • User receives email with a registration link
    • User follows the link and registers with the provided invitation token
    • User is automatically assigned to the specified tenant and role
  2. For existing users:

    • Admin sends an invitation
    • User receives email with a link to accept the invitation
    • User logs in and accepts the invitation
    • User gains access to the new tenant with the specified role
    • User can switch between tenants they have access to

Cross-Tenant User Management

Through the invitation system, a user can have access to multiple tenants with different roles in each tenant, allowing for flexible cross-tenant user management while maintaining strict data isolation.

Tenant-Specific Permissions

Permissions in BAASIX are tenant-specific when multi-tenant mode is enabled. A user can have different roles and permissions across different tenants.

Assigning Role to User for Specific Tenant

POST /items/baasix_UserRole
Authorization: Bearer <admin_token>
Content-Type: application/json

{
  "user_Id": "550e8400-e29b-41d4-a716-446655440000",
  "role_Id": "4a7d1ed4-8d7f-44b3-8f5e-7e5f2d8a7d3c",
  "tenant_Id": "8a7d1ed4-8d7f-44b3-8f5e-7e5f2d8a7d3c"
}

Creating Tenant-Specific Permissions

POST /permissions
Authorization: Bearer <admin_token>
Content-Type: application/json

{
  "role_Id": "4a7d1ed4-8d7f-44b3-8f5e-7e5f2d8a7d3c",
  "collection": "products",
  "action": "read",
  "fields": "*",
  "tenant_Id": "8a7d1ed4-8d7f-44b3-8f5e-7e5f2d8a7d3c"
}

Schema Considerations

When creating schemas in multi-tenant mode, you don't need to manually define tenant fields - they are added automatically by BAASIX.

POST /schemas
Authorization: Bearer <admin_token>
Content-Type: application/json

{
  "collectionName": "products",
  "schema": {
    "name": "Product",
    "timestamps": true,
    "fields": {
      "id": { 
        "type": "UUID", 
        "primaryKey": true, 
        "defaultValue": { "type": "UUIDV4" } 
      },
      "name": { 
        "type": "String", 
        "allowNull": false 
      },
      "price": { 
        "type": "Double", 
        "allowNull": false 
      }
      // No need to define tenant_Id - it's added automatically
    }
  }
}

Tenant-Aware Unique Constraints

When defining unique constraints in multi-tenant mode, the tenant_Id field is automatically included in the constraint, making values unique per tenant rather than globally:

POST /schemas/products/indexes
Authorization: Bearer <admin_token>
Content-Type: application/json

{
  "fields": ["sku"],
  "unique": true,
  "name": "sku_unique"
}

In the database, this will actually create a constraint on ["sku", "tenant_Id"], allowing the same SKU to be used across different tenants but maintaining uniqueness within each tenant.

Best Practices

  1. User Assignment: Always assign new users to at least one tenant. Users without tenant assignments won't be able to access most functionality.

  2. Admin Users: Create super-admin users that have access across all tenants for system administration.

  3. Cross-Tenant Access: For specific scenarios where cross-tenant access is needed, implement it through a system user with specific permissions.

  4. Tenant Identification: Use descriptive names for tenants to make administration easier.

  5. Tenant-specific Settings: Store tenant-specific settings in the settings JSON field of the tenant model.

  6. Tenant URL Patterns: Consider implementing tenant-specific subdomains or URL paths in your frontend application (e.g., tenant-name.yourdomain.com or yourdomain.com/tenant-name).

  7. Data Migration: When migrating data between tenants, ensure you update all tenant foreign keys correctly.

  8. Hooks and Extensions: For hooks and extensions, check the tenant context to ensure operations are tenant-specific.

  9. Performance: Be aware that queries in multi-tenant mode have an additional tenant filter which may affect performance on very large data sets.

  10. Backup Strategy: Consider tenant-specific backup strategies for critical tenant data.

  11. Role Management: Clearly distinguish between tenant-specific and non-tenant-specific roles in your application's UI.

  12. Invitation Management: Implement proper UI flows for users to manage their tenant affiliations and accept invitations.

By leveraging BAASIX's multi-tenant capabilities, you can efficiently serve multiple client organizations from a single deployment, reducing infrastructure costs while maintaining strict data isolation between tenants.

← Back to Documentation Home

On this page