| Install | |
|---|---|
composer require angelitosystems/filament-tenancy |
|
| Latest Version: | v1.0.4 |
| PHP: | ^8.1|^8.2|^8.3 |
A comprehensive multi-tenancy package for Filament with support for multiple databases, central management, advanced logging, and performance monitoring.
The easiest way to install Filament Tenancy is using the interactive installer:
composer require angelitosystems/filament-tenancy
php artisan filament-tenancy:install
The installer will:
bootstrap/app.php (Laravel 11) or via ServiceProvider (Laravel 10)If you prefer manual installation:
# Install the package
composer require angelitosystems/filament-tenancy
# Publish the configuration file
php artisan vendor:publish --tag="filament-tenancy-config"
# Publish seeders (now includes central and tenant seeders)
php artisan vendor:publish --tag="filament-tenancy-seeders"
php artisan vendor:publish --tag="filament-tenancy-tenant-seeders"
# Publish custom 404 page components and views (optional)
php artisan vendor:publish --tag="filament-tenancy-views"
php artisan vendor:publish --tag="filament-tenancy-components"
# Run the migrations
php artisan migrate
# Seed default plans (or they will be seeded automatically during installation)
php artisan db:seed --class=Database\Seeders\PlanSeeder
# Setup central database (required for landlord administration)
php artisan filament-tenancy:setup-central --create-admin
After installation, you need to set up the central database with roles and permissions for the landlord/central administration:
# Complete central database setup (recommended)
php artisan filament-tenancy:setup-central --create-admin
# Or step by step:
php artisan migrate --path="packages/filament-tenancy/database/migrations"
php artisan filament-tenancy:seed-central
php artisan filament-tenancy:create-central-admin
The central database setup includes:
Central Permissions Available:
manage tenants - Create, edit, delete tenantsmanage plans - Manage subscription plansmanage subscriptions - Handle tenant subscriptionsmanage central users - Manage central admin usersmanage central roles - Manage central roles and permissionsview central dashboard - Access central dashboardmanage system settings - Configure system-wide settingsaccess landlord panel - Access landlord administration panelmanage tenant databases - Manage tenant database operationsThe package configuration is located at config/filament-tenancy.php. Key configuration options include:
// How tenants are resolved from requests
'resolver' => env('TENANCY_RESOLVER', 'domain'), // 'domain', 'subdomain', 'path'
// Central domains that won't be resolved as tenants
'central_domains' => [
'app.dental.test',
'localhost',
env('APP_DOMAIN', 'localhost'),
],
Note: The package now supports APP_DOMAIN environment variable for subdomain-based tenancy. When creating tenants with subdomains, the package will automatically detect and suggest configuring APP_DOMAIN from your APP_URL if it's not already set.
'database' => [
'default_connection' => env('DB_CONNECTION', 'mysql'),
'tenants_connection_template' => [
'driver' => env('TENANT_DB_DRIVER', 'mysql'),
'host' => env('TENANT_DB_HOST', '127.0.0.1'),
'port' => env('TENANT_DB_PORT', '3306'),
'username' => env('TENANT_DB_USERNAME', 'root'),
'password' => env('TENANT_DB_PASSWORD', ''),
// ... other database options
],
'auto_create_tenant_database' => env('TENANCY_AUTO_CREATE_DB', true),
'auto_delete_tenant_database' => env('TENANCY_AUTO_DELETE_DB', false),
],
The package uses the following environment variables:
# Base domain for subdomain-based tenancy (auto-detected from APP_URL)
APP_DOMAIN=hola.test
# Tenant resolution strategy
TENANCY_RESOLVER=domain
# Database configuration (optional, uses DB_* by default)
TENANT_DB_DRIVER=mysql
TENANT_DB_HOST=127.0.0.1
TENANT_DB_PORT=3306
TENANT_DB_USERNAME=root
TENANT_DB_PASSWORD=
# Tenancy settings
TENANCY_AUTO_CREATE_DB=true
TENANCY_AUTO_DELETE_DB=false
APP_DOMAIN: This variable is automatically detected and configured when creating tenants. If your APP_URL contains a valid domain (e.g., http://hola.test), the package will ask if you want to use it as APP_DOMAIN. This is essential for subdomain-based tenancy.
Central Domains: APP_DOMAIN is automatically considered a central domain and will not resolve tenants. Additional domains can be configured in central_domains config array. Central domains typically host the admin panel for managing tenants. The middleware automatically allows access to these domains without tenant resolution.
Security: The middleware automatically:
is_active = true and not expired)'filament' => [
'auto_register_plugins' => true,
'landlord_panel_id' => 'admin',
'tenant_panel_id' => 'tenant',
'tenant_panel_path' => '/admin',
],
The easiest way to create tenants is using the interactive command:
# Interactive tenant creation
php artisan tenancy:create
The command will guide you through:
APP_DOMAIN from APP_URL if neededAPP_DOMAIN automatically)APP_DOMAIN Auto-Configuration:
APP_URL contains a valid domain (e.g., http://hola.test), the command will detect it and ask if you want to use it as APP_DOMAINAPP_URL is localhost or has a port (e.g., http://localhost:8000), you'll be prompted to configure APP_DOMAIN manuallyAPP_DOMAIN variable is automatically added or updated in your .env fileAPP_DOMAIN (e.g., tenant.APP_DOMAIN)Create users for specific tenants with roles and permissions:
# Interactive mode
php artisan tenant:user-create
# Non-interactive mode
php artisan tenant:user-create \
--tenant="my-tenant" \
--name="John Doe" \
--email="john@example.com" \
--role="admin" \
--permissions="manage users,view dashboard"
# List available options
php artisan tenant:user-create --list-tenants
php artisan tenant:user-create --tenant="my-tenant" --list-roles
php artisan tenant:user-create --tenant="my-tenant" --list-permissions
Features:
# Create a new tenant with all options (plan slug must exist in database)
php artisan tenancy:create "Acme Corp" \
--subdomain="acme" \
--database="acme_db" \
--plan="premium" \
--active \
--expires="2025-12-31"
# Create with domain
php artisan tenancy:create "Acme Corp" --domain="acme.com"
# Create with subdomain
php artisan tenancy:create "Acme Corp" --subdomain="acme"
Note: When using --plan, the plan slug must exist in the tenancy_plans table. If a plan is provided, a subscription will be automatically created for the tenant.
use AngelitoSystems\FilamentTenancy\Facades\Tenancy;
// Create a new tenant
$tenant = Tenancy::createTenant([
'name' => 'Acme Corporation',
'slug' => 'acme-corp',
'domain' => 'acme.com',
'is_active' => true,
]);
// Switch to tenant context
Tenancy::switchToTenant($tenant);
// Run code in tenant context
Tenancy::runForTenant($tenant, function () {
// This code runs in the tenant's database context
User::create(['name' => 'John Doe', 'email' => 'john@acme.com']);
});
// Switch back to central context
Tenancy::switchToCentral();
Add the HasRoles trait to your User model to enable role-based access control:
<?php
namespace App\Models;
use AngelitoSystems\FilamentTenancy\Concerns\HasRoles;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use HasRoles;
// Your model code...
}
// Assign roles
$user->assignRole('admin');
$user->syncRoles(['admin', 'editor']);
// Check roles
$user->hasRole('admin');
$user->hasAnyRole(['admin', 'editor']);
// Assign permissions
$user->givePermissionTo('manage users');
$user->syncPermissions(['manage users', 'view dashboard']);
// Check permissions
$user->hasPermissionTo('manage users');
$user->hasAnyPermission(['manage users', 'edit posts']);
Use the tenant_asset() helper to access shared assets:
<!-- In Blade templates -->
<link href="{{ tenant_asset('css/app.css') }}" rel="stylesheet">
<script src="{{ tenant_asset('livewire/livewire.js') }}" defer></script>
<link href="{{ tenant_asset('filament/assets/app.css') }}" rel="stylesheet">
The helper automatically:
asset() helper as final fallbackFor models that belong to tenants, use the BelongsToTenant trait:
use AngelitoSystems\FilamentTenancy\Concerns\BelongsToTenant;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
use BelongsToTenant;
// Your model code...
}
For models that should always use the central database, use the UsesLandlordConnection trait:
use AngelitoSystems\FilamentTenancy\Concerns\UsesLandlordConnection;
use Illuminate\Database\Eloquent\Model;
class Plan extends Model
{
use UsesLandlordConnection;
// Your model code...
}
Create a landlord panel for managing tenants:
// app/Providers/Filament/AdminPanelProvider.php
use AngelitoSystems\FilamentTenancy\FilamentPlugins\TenancyLandlordPlugin;
public function panel(Panel $panel): Panel
{
return $panel
->id('admin')
->path('/admin')
->plugin(TenancyLandlordPlugin::make())
// ... other panel configuration
}
Create a tenant panel:
// app/Providers/Filament/TenantPanelProvider.php
use AngelitoSystems\FilamentTenancy\FilamentPlugins\TenancyTenantPlugin;
public function panel(Panel $panel): Panel
{
return $panel
->id('tenant')
->path('/admin')
->plugin(TenancyTenantPlugin::make())
// ... other panel configuration
}
The package provides several middleware for tenant management:
InitializeTenancy:
EnsureTenantAccess:
PreventAccessFromCentralDomains: Prevents tenant access from central domains
The package includes a beautiful, personalized 404 page for tenant not found errors. During installation, you'll be asked if you want to publish the components and views for customization.
# Publish views (Blade templates)
php artisan vendor:publish --tag="filament-tenancy-views"
# Publish Livewire component (optional, requires Livewire)
php artisan vendor:publish --tag="filament-tenancy-components"
If you choose to publish during installation:
resources/views/vendor/filament-tenancy/errors/tenant-not-found.blade.phpapp/Livewire/TenantNotFound.php (if Livewire is available)Once published, you can fully customize:
resources/views/vendor/filament-tenancy/errors/tenant-not-found.blade.php to change the design, colors, layout, or contentapp/Livewire/TenantNotFound.php to add dynamic functionality or interactivityThe installer automatically registers the custom 404 page in bootstrap/app.php (Laravel 11) for handling tenant not found errors. The page will:
If you choose not to publish, the package will use its internal views and components. The 404 page will still work, but you won't be able to customize it.
# Run migrations for all tenants
php artisan tenant:migrate
# Run migrations for a specific tenant
php artisan tenant:migrate --tenant=1
# Run fresh migrations with seeding
php artisan tenant:migrate --fresh --seed
Place tenant-specific migrations in database/migrations/tenant/:
php artisan make:migration create_tenant_users_table --path=database/migrations/tenant
The package dispatches several events:
TenantCreated: When a new tenant is createdTenantDeleted: When a tenant is deletedTenantSwitched: When switching between tenantsuse AngelitoSystems\FilamentTenancy\Events\TenantCreated;
Event::listen(TenantCreated::class, function (TenantCreated $event) {
// Handle tenant creation
$tenant = $event->tenant;
});
You can extend the tenant resolver for custom logic:
use AngelitoSystems\FilamentTenancy\Support\TenantResolver;
class CustomTenantResolver extends TenantResolver
{
public function resolve(Request $request): ?Tenant
{
// Your custom resolution logic
return parent::resolve($request);
}
}
// Register in a service provider
$this->app->bind(TenantResolver::class, CustomTenantResolver::class);
Override database configuration per tenant:
$tenant = Tenant::find(1);
$tenant->update([
'database_host' => 'custom-host.com',
'database_name' => 'custom_database',
'database_username' => 'custom_user',
'database_password' => 'custom_password',
]);
Store additional tenant data using the JSON data column:
$tenant->data = [
'settings' => [
'theme' => 'dark',
'timezone' => 'UTC',
],
'features' => ['feature1', 'feature2'],
];
$tenant->save();
// Access data
$theme = $tenant->data['settings']['theme'] ?? 'light';
The APP_DOMAIN environment variable is used for subdomain-based tenancy. It's automatically detected and configured during tenant creation:
Automatic Detection:
php artisan tenancy:create, the package checks your APP_URLAPP_URL contains a valid domain (e.g., http://hola.test), it suggests using it as APP_DOMAINAPP_URL is localhost or has a port, you'll be prompted to configure APP_DOMAIN manuallyManual Configuration:
APP_DOMAIN=hola.test
Usage:
{subdomain}.{APP_DOMAIN}APP_DOMAIN=hola.test and subdomain is acme, the full domain becomes acme.hola.testTenant::getFullDomain() method uses APP_DOMAIN when available, falling back to central_domains configurationExample:
// With APP_DOMAIN=hola.test configured
$tenant = Tenant::create([
'name' => 'Acme Corp',
'subdomain' => 'acme',
]);
echo $tenant->getFullDomain(); // Output: acme.hola.test
echo $tenant->getUrl(); // Output: http://acme.hola.test
Run the package tests:
composer test
The package includes enhanced debug logging that is environment-aware:
The DebugHelper class provides environment-aware logging:
use AngelitoSystems\FilamentTenancy\Support\DebugHelper;
// Only logs when APP_ENV=local AND APP_DEBUG=true
DebugHelper::info('Tenant created', ['tenant_id' => $tenant->id]);
DebugHelper::debug('Connection details', $connectionData);
DebugHelper::warning('Potential issue detected', $context);
// Always logs regardless of environment
DebugHelper::error('Critical error occurred', $errorData);
DebugHelper::critical('System failure', $criticalData);
# Enable debug logging
APP_ENV=local
APP_DEBUG=true
# Production settings (logs only errors/criticals)
APP_ENV=production
APP_DEBUG=false
This package includes several security features:
is_active and expires_at)Please see CONTRIBUTING.md for details.
This package is currently available for public use, but will transition to a license-based distribution model in the future.
Current Status: Public Access (Temporary)
Important: This package will transition to a paid license model in the future. Users who adopt the package now will receive preferential treatment when licensing becomes available.
Legal Consequences:
Technical Consequences:
To ensure compliance:
Current License: MIT License (subject to above restrictions)
For complete license terms, please read the LICENSE file.
# Complete central database setup with admin creation
php artisan filament-tenancy:setup-central --create-admin
# Seed central database with roles and permissions
php artisan filament-tenancy:seed-central
# Create central admin user with Super Admin role
php artisan filament-tenancy:create-central-admin
# Interactive tenant creation
php artisan tenancy:create
# List all tenants
php artisan tenancy:list
# Delete a tenant
php artisan tenancy:delete
# Create tenant user with roles
php artisan tenant:user-create
# Run migrations for specific tenant
php artisan tenant:migrate
# Rollback tenant migrations
php artisan tenant:rollback
# Fresh tenant database
php artisan tenant:fresh
# Monitor tenant connections
php artisan filament-tenancy:monitor-connections
For support, please open an issue on GitHub or contact us at angelitosystems@gmail.com.