Files
neo/backend/scripts

Tenant Migration & Admin Scripts

This directory contains scripts for managing database migrations across all tenants and creating admin users in the multi-tenant platform.

Admin User Management

Create Central Admin User

npm run create-central-admin

Creates an administrator user in the central database. Central admins can:

  • Manage tenants (create, update, delete)
  • Access platform-wide administration features
  • View all tenant information
  • Manage tenant provisioning

Interactive Mode:

npm run create-central-admin
# You will be prompted for:
# - Email
# - Password
# - First Name (optional)
# - Last Name (optional)
# - Role (admin or superadmin)

Non-Interactive Mode (using environment variables):

EMAIL=admin@example.com PASSWORD=securepass123 FIRST_NAME=John LAST_NAME=Doe ROLE=superadmin npm run create-central-admin

Logging In as Central Admin:

  1. Access the application using a central subdomain (e.g., central.yourdomain.com or admin.yourdomain.com)
  2. Enter your central admin credentials
  3. You'll be authenticated against the central database (not a tenant database)

Note: The system automatically detects if you're logging in from a central subdomain based on the CENTRAL_SUBDOMAINS environment variable (defaults to central,admin). No special UI or configuration is needed on the frontend.

Create Tenant User

For creating users within a specific tenant database, use:

npm run create-tenant-user <tenant-slug>
# (Note: This script may need to be created or already exists)

Migration Scripts

1. Create a New Migration

npm run migrate:make <migration_name>

Creates a new migration file in migrations/tenant/ directory.

Example:

npm run migrate:make add_status_field_to_contacts

2. Migrate a Single Tenant

npm run migrate:tenant <tenant-slug-or-id>

Runs all pending migrations for a specific tenant. You can identify the tenant by its slug or ID.

Example:

npm run migrate:tenant acme-corp
npm run migrate:tenant cm5a1b2c3d4e5f6g7h8i9j0k

3. Migrate All Tenants

npm run migrate:all-tenants

Runs all pending migrations for all active tenants in the system. This is useful when:

  • You've created a new migration that needs to be applied to all tenants
  • You're updating the schema across the entire platform
  • You need to ensure all tenants are up to date

Output:

  • Shows progress for each tenant
  • Lists which migrations were applied
  • Provides a summary at the end
  • Exits with error code if any tenant fails

4. Rollback Migration (Manual)

npm run migrate:rollback

⚠️ Warning: This runs a rollback on the default database configured in knexfile.js. For tenant-specific rollbacks, you'll need to manually configure the connection.

Migration Flow

During New Tenant Provisioning

When a new tenant is created via the API, migrations are automatically run as part of the provisioning process:

  1. Tenant database is created
  2. TenantProvisioningService.runTenantMigrations() is called
  3. All migrations in migrations/tenant/ are executed

For Existing Tenants

When you add a new migration file and need to apply it to existing tenants:

  1. Create the migration:

    npm run migrate:make add_new_feature
    
  2. Edit the generated migration file in migrations/tenant/

  3. Test on a single tenant first:

    npm run migrate:tenant test-tenant
    
  4. If successful, apply to all tenants:

    npm run migrate:all-tenants
    

Migration Directory Structure

backend/
├── migrations/
│   └── tenant/                    # Tenant-specific migrations
│       ├── 20250126000001_create_users_and_rbac.js
│       ├── 20250126000002_create_object_definitions.js
│       └── ...
├── scripts/
│   ├── migrate-tenant.ts         # Single tenant migration
│   └── migrate-all-tenants.ts    # All tenants migration
└── knexfile.js                   # Knex configuration

Security Notes

Database Password Encryption

Tenant database passwords are encrypted in the central database using AES-256-CBC encryption. The migration scripts automatically:

  1. Fetch tenant connection details from the central database
  2. Decrypt the database password using the DB_ENCRYPTION_KEY environment variable
  3. Connect to the tenant database
  4. Run migrations
  5. Close the connection

Required Environment Variable:

DB_ENCRYPTION_KEY=your-32-character-secret-key!!

This key must match the key used by TenantService for encryption.

Troubleshooting

Migration Fails for One Tenant

If migrate:all-tenants fails for a specific tenant:

  1. Check the error message in the output
  2. Investigate the tenant's database directly
  3. Fix the issue (manual SQL, data cleanup, etc.)
  4. Re-run migrations for that tenant: npm run migrate:tenant <slug>
  5. Once fixed, run migrate:all-tenants again to ensure others are updated

Migration Already Exists

Knex tracks which migrations have been run in the knex_migrations table in each tenant database. If a migration was already applied, it will be skipped automatically.

Connection Issues

If you see connection errors:

  1. Verify the central database is accessible
  2. Check that tenant database credentials are correct
  3. Ensure DB_ENCRYPTION_KEY matches the one used for encryption
  4. Verify the tenant's database server is running and accessible

Example Migration File

// migrations/tenant/20250126000006_add_custom_fields.js

exports.up = async function(knex) {
  await knex.schema.table('field_definitions', (table) => {
    table.boolean('is_custom').defaultTo(false);
    table.string('custom_type', 50).nullable();
  });
};

exports.down = async function(knex) {
  await knex.schema.table('field_definitions', (table) => {
    table.dropColumn('is_custom');
    table.dropColumn('custom_type');
  });
};

Best Practices

  1. Always test on a single tenant first before running migrations on all tenants
  2. Include rollback logic in your down() function
  3. Use transactions for complex multi-step migrations
  4. Backup production databases before running migrations
  5. Monitor the output when running migrate:all-tenants to catch any failures
  6. Version control your migration files
  7. Document breaking changes in migration comments
  8. Consider data migrations separately from schema migrations when dealing with large datasets

CI/CD Integration

In your deployment pipeline, you can automatically migrate all tenants:

# After deploying new code
npm run migrate:all-tenants

Or integrate it into your Docker deployment:

# In your Dockerfile or docker-compose.yml
CMD npm run migrate:all-tenants && npm run start:prod