Multi-Tenancy
Filament Flow supports both global workflows (shared across all tenants) and tenant-specific workflows (each tenant manages their own).
Global Workflows (Default)
By default, workflows are global and not scoped to any tenant. This is ideal when workflows define application-wide business logic:
FilamentFlowPlugin::make()
->global() // Explicit, but this is the defaultTenant-Aware Workflows
Enable tenant-aware mode when each tenant should be able to customize or create their own workflows:
FilamentFlowPlugin::make()
->tenantAware()
->tenantModel(Company::class) // Optional: override config
->tenantColumn('company_id') // Optional: override configYou can also configure this in the config file:
// config/filament-flow.php
return [
'tenant_model' => App\Models\Company::class,
'tenant_foreign_key' => 'tenant_id',
];Workflow Resolution with Fallback
When tenant-aware mode is enabled, Filament Flow uses a fallback strategy to find workflows:
- First: Look for a tenant-specific workflow (matching the current tenant)
- Fallback: If not found, use the global workflow (
tenant_id = null)
This allows you to:
- Define global "base" workflows that apply to all tenants
- Let specific tenants override with their own customized workflows
Example: A global "Order Processing" workflow applies to all companies, but Company A can create their own version with additional states.
Configuration Reference
// config/filament-flow.php
/**
* The tenant model class for multi-tenancy support.
* Set to null to disable multi-tenancy.
*
* Example: App\Models\Company::class, App\Models\Tenant::class
*/
'tenant_model' => null,
/**
* The foreign key column name for tenant relationship.
* This will be used in the workflows table.
*/
'tenant_foreign_key' => 'tenant_id',Use Case: If your application has multiple tenants (e.g., companies, organizations), you can configure workflows per tenant. Each tenant can have their own workflow definitions in the database.
Custom Role Resolver for Tenant-Aware Roles
When using multi-tenancy with per-company roles (e.g., a collaborator role stored in the company_user pivot), extend DefaultRoleResolver to include the pivot role:
use RoBYCoNTe\FilamentFlow\Support\DefaultRoleResolver;
class TenantAwareRoleResolver extends DefaultRoleResolver
{
public function getRoles(Model $user): array
{
$roles = parent::getRoles($user);
$company = $user->currentCompany;
if ($company) {
$pivotRole = $user->employeeships()
->where('company_id', $company->id)
->value('role');
if ($pivotRole) {
$roles[] = $pivotRole;
}
}
return array_unique($roles);
}
}Register it in config:
// config/filament-flow.php
'state_access' => [
'role_resolver' => \App\Support\TenantAwareRoleResolver::class,
],This resolver is used by both AccessRuleEvaluator (for state access rules) and WorkflowFieldPermissionsService (for field permissions), ensuring consistent role resolution across the entire workflow system.