1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-06-21 18:24:04 +00:00

Remove detailed tenancy references from boost resources for better clarity and maintainability

This commit is contained in:
eramitgupta 2026-06-02 12:38:17 +05:30
parent fde2bf0cf4
commit 882eaef8b4
20 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,214 @@
---
name: tenancy
description: "Activate when the user is building or debugging multi-tenant Laravel behavior with stancl/tenancy. Use for tenancy:install, tenant identification middleware, central and tenant routes, tenant model and domain model setup, multi-database or single-database tenancy, tenant-aware bootstrappers for database/cache/filesystem/queue/session/Redis, tenant context switching with tenancy()->initialize() or tenant()->run(), tenant migrations and seeders, tenant asset routes, pending tenants, resource syncing, user impersonation, RLS, Vite bundling, or testing tenant-aware behavior."
license: MIT
metadata:
author: Samuel Štancl
---
# Tenancy For Laravel
Use this skill when a Laravel task involves `stancl/tenancy`.
## Documentation
Use `search-docs` first when it is available for Laravel integration patterns. For package-specific behavior, inspect:
- `src/TenancyServiceProvider.php`
- `src/Tenancy.php`
- `assets/config.php`
- `assets/routes.php`
- `src/Middleware/*`
- `src/Bootstrappers/*`
- `src/Commands/*`
- `src/Database/Models/*`
- `src/Resolvers/*`
- `src/Features/*`
- `references/package.md`
Load `references/package.md` when the task needs package-specific detail beyond the core workflow in this file.
## Feature References
Load focused references when the task matches a specific package area:
- `references/installation.md` for install, publishing, and setup checks
- `references/configuration.md` for `config/tenancy.php` sections
- `references/identification.md` for middleware and resolvers
- `references/routing-assets.md` for tenant routes, route modes, cloned routes, and asset routes
- `references/context-api.md` for `tenancy()`, `tenant()`, `run()`, and `central()` behavior
- `references/bootstrappers.md` for tenant-aware Laravel service scoping
- `references/database-tenancy.md` for database isolation and tenant database managers
- `references/migrations-commands.md` for tenant Artisan commands
- `references/models-domains.md` for tenant/domain models and single-database traits
- `references/filesystem-cache-queue.md` for storage, cache, sessions, Redis, and queues
- `references/lifecycle-jobs.md` for events, provisioning, and cleanup pipelines
- `references/resource-syncing.md` for synced central and tenant resources
- `references/impersonation.md` for tenant user impersonation
- `references/pending-tenants.md` for pending tenant pools
- `references/rls.md` for PostgreSQL row-level security
- `references/features.md` for optional package features
- `references/integrations.md` for URL, mail, broadcasting, Fortify, Scout, Livewire, Telescope, and Vite
- `references/testing.md` for test coverage guidance
## Package Surface
The package auto-discovers:
- Service provider: `Stancl\Tenancy\TenancyServiceProvider`
- Facades: `Tenancy` and `GlobalCache`
The package also publishes:
- `config/tenancy.php`
- `routes/tenant.php`
- `app/Providers/TenancyServiceProvider.php`
- tenant, domain, impersonation, and resource-syncing migrations
## Installation And Setup
Install the package with Composer:
```bash
composer require stancl/tenancy
```
Prefer the package installer over manual publishing:
```bash
php artisan tenancy:install --no-interaction
```
That command publishes the config, routes, provider, core migrations, and creates `database/migrations/tenant`.
## Core Working Pattern
1. Install the package and inspect `config/tenancy.php`.
2. Decide the tenant identification strategy first: domain, subdomain, domain-or-subdomain, path, request data, or origin header.
3. Keep central and tenant routes explicit. Use the package middleware and route modes instead of ad hoc request checks.
4. Choose the minimum bootstrapper set that matches the app's infrastructure.
5. For data isolation, decide between multi-database tenancy, single-database tenancy, or PostgreSQL RLS before writing application models.
6. Test both central and tenant contexts.
## Tenant Identification
The default identification middleware is `InitializeTenancyByDomain`.
Available identification middleware:
- `InitializeTenancyByDomain`
- `InitializeTenancyBySubdomain`
- `InitializeTenancyByDomainOrSubdomain`
- `InitializeTenancyByPath`
- `InitializeTenancyByRequestData`
- `InitializeTenancyByOriginHeader`
Use `PreventAccessFromUnwantedDomains` only with the domain-oriented identification middleware recognized by the package config.
For path identification, the package uses `PathTenantResolver` and a route parameter name configured in `tenancy.identification.resolvers`.
## Tenant Context
Common patterns:
```php
tenancy()->initialize($tenant);
$tenant->run(function () {
// Code in tenant context.
});
tenancy()->central(function () {
// Code in central context.
});
```
Prefer the package context helpers instead of manually mutating connections, cache prefixes, filesystem roots, or config.
## Bootstrappers
Default bootstrappers cover:
- tenant database connection switching
- cache scoping
- filesystem scoping
- queue scoping
- database session support
Optional bootstrappers exist for:
- Redis scoping
- database-backed cache scoping
- tenant config injection
- URL, root URL, and asset generation
- mail config
- broadcasting config and channel prefixing
- Fortify and Scout integration
- PostgreSQL RLS
If tenant state appears partially applied, inspect the active bootstrappers in `config/tenancy.php` before changing application code.
## Routes And Assets
The package registers route middleware groups for `clone`, `universal`, `tenant`, and `central`.
When tenancy routes are enabled, it registers tenant asset routes from `assets/routes.php`. For path-based identification, asset routes can include the tenant parameter prefix.
Keep tenant routes in `routes/tenant.php` when the app uses the published route stub.
## Data Model Guidance
The default tenant model is `Stancl\Tenancy\Database\Models\Tenant`.
Related package models:
- `Stancl\Tenancy\Database\Models\Domain`
- `Stancl\Tenancy\Database\Models\ImpersonationToken`
Use package traits and helpers before inventing your own tenant key, domain, or tenant-run abstractions.
When changing tenant identity generation, use a class implementing `UniqueIdentifierGenerator` or set the generator to `null` only if the application intentionally uses auto-incrementing IDs.
## Commands
Common package commands:
- `tenancy:install`
- `tenants:migrate`
- `tenants:rollback`
- `tenants:seed`
- `tenants:run`
- `tenant:tinker`
- `tenants:list`
- `tenants:down`
- `tenants:up`
- `tenants:link`
Use the package commands for tenant-aware migration, seeding, maintenance, and per-tenant execution instead of custom loops.
## Features
Optional features include:
- `UserImpersonation`
- `TelescopeTags`
- `CrossDomainRedirect`
- `ViteBundler`
- `DisallowSqliteAttach`
- `TenantConfig`
Enable features through `tenancy.features` and check each feature's class before assuming it changes bootstrapping behavior.
## Testing
Test both successful identification and failure behavior.
For tenancy-aware tests, verify:
- the request resolves the correct tenant
- central routes stay central
- tenant routes reject central access when expected
- tenant context affects database, cache, filesystem, queue, and URL behavior as intended
- tenant artisan commands run against the expected tenants
If a behavior depends on package internals, inspect `tests/*` in the package or load `references/package.md` before adding application-level workarounds.

View file

@ -0,0 +1,42 @@
# Bootstrappers Reference
Use this when tenant context should affect Laravel services.
## Source Files
- `src/Bootstrappers/*`
- `assets/config.php`
## Defaults
- `DatabaseTenancyBootstrapper`
- `CacheTenancyBootstrapper`
- `FilesystemTenancyBootstrapper`
- `QueueTenancyBootstrapper`
- `DatabaseSessionBootstrapper`
## Optional Bootstrappers
- `CacheTagsBootstrapper`
- `DatabaseCacheBootstrapper`
- `RedisTenancyBootstrapper`
- `TenantConfigBootstrapper`
- `RootUrlBootstrapper`
- `UrlGeneratorBootstrapper`
- `MailConfigBootstrapper`
- `BroadcastingConfigBootstrapper`
- `BroadcastChannelPrefixBootstrapper`
- `FortifyRouteBootstrapper`
- `ScoutPrefixBootstrapper`
- `PostgresRLSBootstrapper`
- `PersistentQueueTenancyBootstrapper`
## Rules
- Configure bootstrappers before writing app-level workarounds.
- `DatabaseCacheBootstrapper` must run after `DatabaseTenancyBootstrapper`.
- `RedisTenancyBootstrapper` needs phpredis and is for direct Redis calls.
- Prefer `TenantConfigBootstrapper` over deprecated `TenantConfig` feature.
- Use `RootUrlBootstrapper` for CLI URL root behavior.
- Use `UrlGeneratorBootstrapper` for tenant-aware route generation.
- Inspect `tenancy()->getBootstrappers()` when context looks partially applied.

View file

@ -0,0 +1,34 @@
# Configuration Reference
Use this when changing `config/tenancy.php`.
## Source Files
- `assets/config.php`
- `src/TenancyServiceProvider.php`
## Must-Review Sections
- `models`: tenant, domain, impersonation token, tenant key column, ID generator.
- `identification`: central domains, default middleware, resolver settings.
- `bootstrappers`: runtime Laravel feature scoping.
- `database`: central connection, template tenant connection, DB managers, prefixes.
- `rls`: PostgreSQL RLS manager, user, and session variable.
- `cache`: prefix, stores, session scoping, tag base.
- `filesystem`: disks, root overrides, URL overrides, storage suffixing, asset override.
- `redis`: direct Redis connection prefixing.
- `features`: optional package features.
- `routes`: package asset route registration toggle.
- `default_route_mode`: central, tenant, or universal default route behavior.
- `pending`: pending tenant query inclusion and pool count.
- `migration_parameters`: tenant migration defaults.
- `seeder_parameters`: tenant seeder defaults.
## Rules
- Decide identification, database isolation, and bootstrappers before writing app code.
- Never use `tenant` as the template tenant connection name; it is reserved by the package.
- Set `models.id_generator` to `null` only when using auto-increment tenant IDs intentionally.
- Keep resolver caching disabled until invalidation behavior is tested.
- Keep `database.drop_tenant_databases_on_migrate_fresh` false unless local/dev destructive behavior is intended.
- Enable `filesystem.asset_helper_override` only after checking third-party package asset calls.

View file

@ -0,0 +1,45 @@
# Context API Reference
Use this when switching between tenant and central contexts.
## Source Files
- `src/Tenancy.php`
- `src/helpers.php`
- `src/Database/Concerns/TenantRun.php`
- `src/Database/Concerns/InitializationHelpers.php`
## Core API
```php
tenancy()->initialize($tenant);
tenancy()->end();
tenancy()->reinitialize();
tenancy()->central(fn () => null);
$tenant->run(fn () => null);
```
## Behavior
- `initialize()` accepts a tenant model, ID, or string key.
- Switching tenants ends the previous context first.
- `run()` restores the previous tenant or central context in `finally`.
- `central()` temporarily ends tenancy and restores prior tenant context.
- `reinitialize()` re-runs bootstrappers for the current tenant.
- `bootstrapFeatures()` is idempotent per feature, but feature bootstrapping is irreversible.
- `find()` resolves tenants through the configured tenant model.
## Helpers
- `tenancy()` returns the tenancy singleton.
- `tenant()` returns current tenant or tenant attribute.
- `central()` executes a callback in central context.
- `globalCache()` resolves central cache.
- `tenant_asset()` returns tenant asset URLs.
- `global_asset()` returns global asset URLs.
## Rules
- Do not manually mutate DB connections, cache prefixes, filesystem roots, queue payloads, sessions, or URL roots.
- Use atomic `run()` and `central()` when context must be restored safely.
- Test context restoration after exceptions.

View file

@ -0,0 +1,36 @@
# Database Tenancy Reference
Use this when changing tenant database isolation or managers.
## Source Files
- `src/Database/DatabaseManager.php`
- `src/Database/DatabaseConfig.php`
- `src/Database/TenantDatabaseManagers/*`
- `src/Bootstrappers/DatabaseTenancyBootstrapper.php`
- `assets/config.php`
## Supported Isolation
- Separate tenant databases.
- PostgreSQL schema isolation.
- Permission-controlled tenant database users.
- PostgreSQL RLS for single-database tenancy.
## Managers
- SQLite: `SQLiteDatabaseManager`
- MySQL/MariaDB: `MySQLDatabaseManager`
- PostgreSQL: `PostgreSQLDatabaseManager`
- SQL Server: `MicrosoftSQLDatabaseManager`
- Permission-controlled variants for MySQL, PostgreSQL, SQL Server.
- PostgreSQL schema managers for schema isolation.
## Rules
- `tenant` is a reserved dynamic connection name.
- Use `database.template_tenant_connection` for the tenant connection template.
- Use `database.tenant_host_connection_name` for database creation/deletion host connection.
- Tenant DB names are `prefix + tenant_id + suffix`.
- Use schema managers only when PostgreSQL schema isolation is intended.
- Test creation, migration, rollback, deletion, and connection restoration.

View file

@ -0,0 +1,30 @@
# Optional Features Reference
Use this when enabling or debugging classes in `tenancy.features`.
## Source Files
- `src/Features/*`
- `src/Tenancy.php`
## Features
- `UserImpersonation`
- `TelescopeTags`
- `CrossDomainRedirect`
- `ViteBundler`
- `DisallowSqliteAttach`
- `TenantConfig`
## Behavior
- Features are bootstrapped independently from tenant initialization.
- `tenancy()->bootstrapFeatures()` is idempotent per feature.
- Feature bootstrapping is irreversible during the request lifecycle.
- `TenantConfig` is deprecated in favor of `TenantConfigBootstrapper`.
## Rules
- Inspect the feature class before assuming behavior.
- Enable only the needed features.
- Test each enabled feature in central and tenant contexts where relevant.

View file

@ -0,0 +1,41 @@
# Filesystem Cache Queue Reference
Use this when tenant context affects storage, cache, sessions, Redis, or queues.
## Source Files
- `src/Bootstrappers/FilesystemTenancyBootstrapper.php`
- `src/Bootstrappers/CacheTenancyBootstrapper.php`
- `src/Bootstrappers/CacheTagsBootstrapper.php`
- `src/Bootstrappers/DatabaseCacheBootstrapper.php`
- `src/Bootstrappers/RedisTenancyBootstrapper.php`
- `src/Bootstrappers/QueueTenancyBootstrapper.php`
- `src/Bootstrappers/PersistentQueueTenancyBootstrapper.php`
- `src/Bootstrappers/DatabaseSessionBootstrapper.php`
- `src/Middleware/ScopeSessions.php`
## Filesystem
- `filesystem.disks` controls scoped disks.
- `filesystem.root_override` rewrites local disk roots.
- `filesystem.url_override` enables tenant-aware local public URLs.
- `filesystem.suffix_storage_path` controls `storage_path()` suffixing.
- `filesystem.asset_helper_override` makes `asset()` tenant-aware.
## Cache And Redis
- Cache tenancy prefixes configured stores through `cache.prefix`.
- Global central cache is available through `GlobalCache`/`globalCache()`.
- Redis tenancy is for direct Redis usage and requires phpredis.
## Queue
- Queue bootstrapper carries tenant context into queued jobs.
- Persistent queue bootstrapper is for workers intentionally staying tenant-aware.
## Rules
- Run `php artisan tenants:link` when tenant public local storage URLs are enabled.
- Be careful with `asset_helper_override`; third-party package assets may become tenant-aware.
- Scope sessions through config and `ScopeSessions` middleware where required.
- Test queued jobs in central and tenant contexts.

View file

@ -0,0 +1,43 @@
# Tenant Identification Reference
Use this when resolving tenants from requests.
## Source Files
- `src/Middleware/IdentificationMiddleware.php`
- `src/Middleware/InitializeTenancyByDomain.php`
- `src/Middleware/InitializeTenancyBySubdomain.php`
- `src/Middleware/InitializeTenancyByDomainOrSubdomain.php`
- `src/Middleware/InitializeTenancyByPath.php`
- `src/Middleware/InitializeTenancyByRequestData.php`
- `src/Middleware/InitializeTenancyByOriginHeader.php`
- `src/Middleware/PreventAccessFromUnwantedDomains.php`
- `src/Middleware/ScopeSessions.php`
- `src/Resolvers/*`
## Middleware
- `InitializeTenancyByDomain`
- `InitializeTenancyBySubdomain`
- `InitializeTenancyByDomainOrSubdomain`
- `InitializeTenancyByPath`
- `InitializeTenancyByRequestData`
- `InitializeTenancyByOriginHeader`
- `PreventAccessFromUnwantedDomains`
- `CheckTenantForMaintenanceMode`
- `ScopeSessions`
## Resolver Config
- `DomainTenantResolver`: cache, TTL, cache store.
- `PathTenantResolver`: tenant route parameter, route name prefix, tenant model column, allowed extra columns, cache.
- `RequestDataTenantResolver`: header, cookie, query parameter, tenant model column, cache.
## Rules
- Configure `identification.central_domains` for domain/subdomain strategies.
- Use `PreventAccessFromUnwantedDomains` only with configured domain identification middleware.
- For path identification, confirm the tenant parameter name before defining URLs.
- For request-data identification, set unused channels to `null`.
- If custom middleware is introduced, add it to the appropriate config category.
- Test success and failure identification paths.

View file

@ -0,0 +1,36 @@
# User Impersonation Reference
Use this when implementing tenant user impersonation.
## Source Files
- `src/Features/UserImpersonation.php`
- `src/Database/Models/ImpersonationToken.php`
- `assets/impersonation-migrations/*`
## Setup
```bash
php artisan vendor:publish --provider="Stancl\Tenancy\TenancyServiceProvider" --tag=impersonation-migrations
php artisan migrate
```
Enable feature:
```php
'features' => [
Stancl\Tenancy\Features\UserImpersonation::class,
],
```
## Command
```bash
php artisan tenants:purge-impersonation-tokens
```
## Rules
- Verify tenant match before logging in impersonated users.
- Test guard, redirect URL, remember flag, token TTL, and invalid token behavior.
- Purge expired tokens routinely.

View file

@ -0,0 +1,73 @@
# Installation Reference
Use this when installing or auditing `stancl/tenancy` setup.
## Source Files
- `src/Commands/Install.php`
- `src/TenancyServiceProvider.php`
- `assets/config.php`
- `assets/tenant_routes.stub.php`
- `assets/TenancyServiceProvider.stub.php`
- `assets/migrations/*`
## Required Steps
1. Install the package.
```bash
composer require stancl/tenancy
```
2. Run the installer non-interactively.
```bash
php artisan tenancy:install --no-interaction
```
3. Confirm these files exist:
- `config/tenancy.php`
- `routes/tenant.php`
- `app/Providers/TenancyServiceProvider.php`
- `database/migrations/2019_09_15_000010_create_tenants_table.php`
- `database/migrations/2019_09_15_000020_create_domains_table.php`
- `database/migrations/tenant`
4. Review `config/tenancy.php` before running migrations.
5. Run central migrations.
```bash
php artisan migrate
```
6. Add tenant migrations to `database/migrations/tenant`.
7. Create tenants and domains according to the identification strategy.
8. Run tenant migrations.
```bash
php artisan tenants:migrate
```
## Manual Publish Commands
Prefer `tenancy:install`. Use these only for targeted publishing:
```bash
php artisan vendor:publish --provider="Stancl\Tenancy\TenancyServiceProvider" --tag=config
php artisan vendor:publish --provider="Stancl\Tenancy\TenancyServiceProvider" --tag=routes
php artisan vendor:publish --provider="Stancl\Tenancy\TenancyServiceProvider" --tag=providers
php artisan vendor:publish --provider="Stancl\Tenancy\TenancyServiceProvider" --tag=migrations
php artisan vendor:publish --provider="Stancl\Tenancy\TenancyServiceProvider" --tag=impersonation-migrations
php artisan vendor:publish --provider="Stancl\Tenancy\TenancyServiceProvider" --tag=resource-syncing-migrations
```
## Installer Behavior
- Publishes config, routes, provider, and base migrations.
- Creates `database/migrations/tenant`.
- Skips files that already exist and warns instead of overwriting.
- Shows an interactive support prompt unless `--no-interaction` is used.

View file

@ -0,0 +1,44 @@
# Integrations Reference
Use this when tenancy integrates with URL generation, mail, broadcasting, Fortify, Scout, Livewire, Telescope, or Vite.
## Source Files
- `src/Bootstrappers/RootUrlBootstrapper.php`
- `src/Bootstrappers/UrlGeneratorBootstrapper.php`
- `src/Bootstrappers/MailConfigBootstrapper.php`
- `src/Bootstrappers/BroadcastingConfigBootstrapper.php`
- `src/Bootstrappers/BroadcastChannelPrefixBootstrapper.php`
- `src/Bootstrappers/Integrations/FortifyRouteBootstrapper.php`
- `src/Bootstrappers/Integrations/ScoutPrefixBootstrapper.php`
- `src/Features/TelescopeTags.php`
- `src/Features/ViteBundler.php`
- `assets/TenancyServiceProvider.stub.php`
## Bootstrappers
- `RootUrlBootstrapper`: tenant root URL for CLI/context URL generation.
- `UrlGeneratorBootstrapper`: tenant-aware route names and tenant parameters.
- `MailConfigBootstrapper`: tenant-specific mail config.
- `BroadcastingConfigBootstrapper`: tenant broadcaster config and manager.
- `BroadcastChannelPrefixBootstrapper`: tenant-prefixed broadcast channel names.
- `FortifyRouteBootstrapper`: tenant auth route/redirect integration.
- `ScoutPrefixBootstrapper`: tenant-specific Scout prefix.
## Features
- `TelescopeTags`: adds tenant tags when tenancy is initialized.
- `ViteBundler`: tenant-aware bundling behavior.
## Stub Hooks
- `overrideUrlInTenantContext()` shows how to set `RootUrlBootstrapper::$rootUrlOverride`.
- The Livewire v3 comment shows how to make the Livewire update route universal.
- `cloneRoutes()` shows the package route-cloning integration point.
## Rules
- Prefer bootstrappers over ad hoc service-provider config mutation.
- Test generated URLs in HTTP and CLI contexts.
- Test broadcast channel names and tenant-specific broadcaster credentials.
- Make third-party package routes universal or cloned only when intentionally accessible in tenant context.

View file

@ -0,0 +1,46 @@
# Lifecycle Jobs Reference
Use this when provisioning or deleting tenant resources through events and job pipelines.
## Source Files
- `assets/TenancyServiceProvider.stub.php`
- `src/Events/*`
- `src/Jobs/*`
- `src/Listeners/*`
- `src/Database/Models/Tenant.php`
- `src/Database/Models/Domain.php`
## Tenant Created Pipeline
The published application provider wires `TenantCreated` to a `JobPipeline` containing:
- `CreateDatabase`
- `MigrateDatabase`
- optional `SeedDatabase`
- optional `CreateStorageSymlinks`
- custom provisioning jobs
## Tenant Deletion Pipelines
The stub wires:
- `DeletingTenant` to `DeleteDomains`, optional `DeleteTenantStorage`, optional `RemoveStorageSymlinks`.
- `TenantDeleted` to `DeleteDatabase`, optional resource-syncing cleanup.
## Event Groups
- Tenant lifecycle events.
- Domain lifecycle events.
- Database lifecycle events.
- Tenancy initialization/end/bootstrap events.
- Pending tenant events.
- Resource syncing events.
- Storage symlink events.
## Rules
- Put provisioning and cleanup in event pipelines rather than controllers.
- Keep database, migration, seeding, storage, domain, and sync cleanup order explicit.
- Decide whether pipelines should be queued using `shouldBeQueued()`.
- Test tenant creation and deletion side effects.

View file

@ -0,0 +1,56 @@
# Migrations And Commands Reference
Use this for tenant-aware Artisan operations.
## Source Files
- `src/Commands/*`
- `src/Concerns/HasTenantOptions.php`
- `src/Concerns/ExtendsLaravelCommand.php`
- `src/Concerns/DealsWithMigrations.php`
- `assets/config.php`
## Tenant Migrations
Defaults from `tenancy.migration_parameters`:
- `--force` true
- `--path` `database/migrations/tenant`
- `--schema-path` `database/schema/tenant-schema.dump`
- `--realpath` true
Commands:
```bash
php artisan tenants:migrate
php artisan tenants:migrate --tenants=tenant-id
php artisan tenants:migrate --skip-failing
php artisan tenants:rollback
php artisan tenants:migrate-fresh
php artisan tenants:seed
```
## Tenant Operations
```bash
php artisan tenants:run cache:clear
php artisan tenant:tinker
php artisan tenants:list
php artisan tenant:dump
```
## Maintenance And Storage
```bash
php artisan tenants:down
php artisan tenants:up
php artisan tenants:link
php artisan tenants:link --remove
```
## Rules
- Use tenant commands for tenant DBs; normal `migrate` is central.
- Use `--tenants=*` to scope commands to selected tenants.
- Use `--skip-failing` only when failures should not stop execution.
- Use concurrent process options only after verifying tenant operations are safe in parallel.

View file

@ -0,0 +1,42 @@
# Models And Domains Reference
Use this when changing tenant/domain models or tenant-owned models.
## Source Files
- `src/Database/Models/Tenant.php`
- `src/Database/Models/Domain.php`
- `src/Contracts/Tenant.php`
- `src/Contracts/Domain.php`
- `src/Database/Concerns/*`
- `assets/migrations/*`
## Default Tenant Model
- Table: `tenants`
- Primary key: `id`
- Uses `VirtualColumn`, `CentralConnection`, `GeneratesIds`, `HasInternalKeys`, `TenantRun`, `InitializationHelpers`, `InvalidatesResolverCache`.
- Dispatches tenant lifecycle events.
## Default Domain Model
- Unique `domain` column.
- Belongs to configured tenant model using `Tenancy::tenantKeyColumn()`.
- Uses `CentralConnection`, `EnsuresDomainIsNotOccupied`, `ConvertsDomainsToLowercase`, `InvalidatesTenantsResolverCache`.
## Single-Database Traits
- `BelongsToTenant`
- `FillsCurrentTenant`
- `TenantConnection`
- `CentralConnection`
- `HasScopedValidationRules`
- `RLSModel`
## Rules
- Custom tenant models must implement `Stancl\Tenancy\Contracts\Tenant`.
- Custom domain models must implement `Stancl\Tenancy\Contracts\Domain`.
- Preserve resolver cache invalidation behavior when replacing models.
- Use tenant scoping traits consistently for single-database tenancy.
- If auto-increment tenant IDs are used, update config and migrations together.

View file

@ -0,0 +1,363 @@
# Tenancy Package Reference
This reference is for package-specific details that do not need to live in `SKILL.md`.
## Focused References
Load these smaller references for topic-specific work:
- `installation.md` for install, publishing, and setup checks
- `configuration.md` for `config/tenancy.php` sections
- `identification.md` for middleware and resolvers
- `routing-assets.md` for tenant routes, route modes, cloned routes, and asset routes
- `context-api.md` for `tenancy()`, `tenant()`, `run()`, and `central()` behavior
- `bootstrappers.md` for tenant-aware Laravel service scoping
- `database-tenancy.md` for database isolation and tenant database managers
- `migrations-commands.md` for tenant Artisan commands
- `models-domains.md` for tenant/domain models and single-database traits
- `filesystem-cache-queue.md` for storage, cache, sessions, Redis, and queues
- `lifecycle-jobs.md` for events, provisioning, and cleanup pipelines
- `resource-syncing.md` for synced central and tenant resources
- `impersonation.md` for tenant user impersonation
- `pending-tenants.md` for pending tenant pools
- `rls.md` for PostgreSQL row-level security
- `features.md` for optional package features
- `integrations.md` for URL, mail, broadcasting, Fortify, Scout, Livewire, Telescope, and Vite
- `testing.md` for test coverage guidance
## Main Entry Points
- `src/TenancyServiceProvider.php`
- `src/Tenancy.php`
- `assets/config.php`
- `assets/routes.php`
- `src/helpers.php`
## Published Files
The package publishes:
- `config/tenancy.php`
- `routes/tenant.php`
- `app/Providers/TenancyServiceProvider.php`
- `database/migrations/2019_09_15_000010_create_tenants_table.php`
- `database/migrations/2019_09_15_000020_create_domains_table.php`
- impersonation migrations
- resource syncing migrations
`tenancy:install` also creates `database/migrations/tenant`.
## Service Provider Behavior
`TenancyServiceProvider`:
- merges `assets/config.php` into `tenancy`
- binds `Stancl\Tenancy\Database\DatabaseManager` as a singleton
- binds `Stancl\Tenancy\Tenancy` as a singleton
- binds the current tenant to the `Stancl\Tenancy\Contracts\Tenant` contract
- binds the current domain to the `Stancl\Tenancy\Contracts\Domain` contract
- registers configured bootstrappers as singletons
- binds the configured unique ID generator to `UniqueIdentifierGenerator`
- registers package commands
- publishes config, routes, provider, and migrations
- loads package asset routes when `tenancy.routes` is enabled
- boots configured features through `tenancy()->bootstrapFeatures()`
- registers middleware groups: `clone`, `universal`, `tenant`, `central`
## Core Runtime API
`Stancl\Tenancy\Tenancy` exposes:
- `initialize(Tenant|int|string $tenant): void`
- `run(Tenant $tenant, Closure $callback): mixed`
- `central(Closure $callback): mixed`
- `end(): void`
- `reinitialize(): void`
- `bootstrapFeatures(): void`
- `getBootstrappers(): array`
- `find(int|string $id, ?string $column = null, bool $withRelations = false)`
Use these runtime methods instead of rolling your own context switch logic.
## Default Models
From `assets/config.php`:
- `tenancy.models.tenant` => `Stancl\Tenancy\Database\Models\Tenant`
- `tenancy.models.domain` => `Stancl\Tenancy\Database\Models\Domain`
- `tenancy.models.impersonation_token` => `Stancl\Tenancy\Database\Models\ImpersonationToken`
The default tenant key relation column is `tenant_id`.
## Tenant ID Generators
Supported generators exposed in config:
- `UUIDGenerator`
- `ULIDGenerator`
- `UUIDv7Generator`
- `RandomHexGenerator`
- `RandomIntGenerator`
- `RandomStringGenerator`
Set `tenancy.models.id_generator` to `null` only when the app intentionally uses auto-incrementing tenant IDs.
## Identification Middleware
Available middleware:
- `InitializeTenancyByDomain`
- `InitializeTenancyBySubdomain`
- `InitializeTenancyByDomainOrSubdomain`
- `InitializeTenancyByPath`
- `InitializeTenancyByRequestData`
- `InitializeTenancyByOriginHeader`
- `PreventAccessFromUnwantedDomains`
- `CheckTenantForMaintenanceMode`
- `ScopeSessions`
All package identification middleware inherit package failure handling through `IdentificationMiddleware::initializeTenancy()`. Failed identification throws a package exception unless an `onFail` callback is registered.
## Resolvers
Resolvers configured in `tenancy.identification.resolvers`:
- `DomainTenantResolver`
- `PathTenantResolver`
- `RequestDataTenantResolver`
Resolver config includes:
- cache enablement
- cache TTL
- cache store
- path tenant parameter name
- route name prefix
- request header, cookie, and query parameter names
- custom tenant model lookup column
## Default Bootstrappers
Enabled by default:
- `DatabaseTenancyBootstrapper`
- `CacheTenancyBootstrapper`
- `FilesystemTenancyBootstrapper`
- `QueueTenancyBootstrapper`
- `DatabaseSessionBootstrapper`
Optional bootstrappers:
- `CacheTagsBootstrapper`
- `DatabaseCacheBootstrapper`
- `RedisTenancyBootstrapper`
- `TenantConfigBootstrapper`
- `RootUrlBootstrapper`
- `UrlGeneratorBootstrapper`
- `MailConfigBootstrapper`
- `BroadcastingConfigBootstrapper`
- `BroadcastChannelPrefixBootstrapper`
- `Bootstrappers\Integrations\FortifyRouteBootstrapper`
- `Bootstrappers\Integrations\ScoutPrefixBootstrapper`
- `PostgresRLSBootstrapper`
- `PersistentQueueTenancyBootstrapper`
## Bootstrapper Semantics
- `DatabaseTenancyBootstrapper`
switches the active database connection into tenant context and reverts back to the central connection.
- `CacheTenancyBootstrapper`
scopes supported cache stores by prefix and can also scope cache-backed sessions.
- `CacheTagsBootstrapper`
is the older tag-based cache isolation approach and is less complete than prefix-based cache scoping.
- `DatabaseCacheBootstrapper`
scopes cache by moving database-backed cache stores onto the tenant connection instead of using prefixes.
- `FilesystemTenancyBootstrapper`
suffixes `storage_path()`, rewrites configured local disk roots, can scope file cache and file sessions, and can enable tenant-aware asset URLs.
- `QueueTenancyBootstrapper`
injects `tenant_id` into queued job payloads and re-initializes tenancy around queue job execution.
- `PersistentQueueTenancyBootstrapper`
is the queue bootstrapper variant for cases where worker processes should stay tenant-aware across jobs.
- `DatabaseSessionBootstrapper`
makes the database session driver use the tenant connection.
- `RedisTenancyBootstrapper`
sets Redis connection prefixes for configured direct Redis connections.
- `TenantConfigBootstrapper`
maps tenant attributes into arbitrary config keys during tenancy.
- `RootUrlBootstrapper`
overrides `app.url` and the URL generator root URL, primarily for CLI URL generation in tenant context.
- `UrlGeneratorBootstrapper`
swaps in `TenancyUrlGenerator` so route names and tenant parameters are generated correctly for path or query-string identification.
- `MailConfigBootstrapper`
maps tenant attributes into mail configuration at runtime.
- `BroadcastingConfigBootstrapper`
maps tenant-specific broadcaster credentials into broadcasting config and swaps in a tenancy-aware broadcast manager.
- `BroadcastChannelPrefixBootstrapper`
prefixes actual broadcast channel names with the tenant key for supported broadcasters.
- `Bootstrappers\Integrations\FortifyRouteBootstrapper`
rewrites Fortify redirect targets so tenant auth flows can land on tenant routes.
- `Bootstrappers\Integrations\ScoutPrefixBootstrapper`
sets `scout.prefix` to the tenant key.
- `PostgresRLSBootstrapper`
swaps the tenant connection to the configured PostgreSQL RLS user and session variable model.
## Database Isolation Options
The config supports:
- separate tenant databases
- PostgreSQL schema isolation
- optional permission-controlled database managers
- PostgreSQL RLS
Database manager mappings exist for:
- `sqlite`
- `mysql`
- `mariadb`
- `pgsql`
- `sqlsrv`
`tenancy.database.drop_tenant_databases_on_migrate_fresh` controls whether `migrate:fresh` also drops tenant databases through the package override.
## Cache, Filesystem, Queue, And Session Scoping
Important config sections:
- `tenancy.cache`
- `tenancy.filesystem`
- `tenancy.redis`
- `tenancy.migration_parameters`
- `tenancy.seeder_parameters`
Notable filesystem behavior:
- local disks can have tenant-specific root overrides
- `Storage::disk()->url()` can be overridden with tenant-aware public names
- `storage_path()` can be suffixed per tenant
- file cache and file sessions can be scoped
- `asset()` tenancy can be enabled, but may affect packages that assume global assets
## Routes
`assets/routes.php` registers:
- `/tenancy/assets/{path?}` named `stancl.tenancy.asset`
- `/{tenant}/tenancy/assets/{path?}` named `tenant.stancl.tenancy.asset` for path identification, behind the `tenant` middleware
The package route mode enum is `Stancl\Tenancy\Enums\RouteMode`, with central as the default route mode in config.
The service provider also registers empty middleware groups named:
- `clone`
- `universal`
- `tenant`
- `central`
These route modes and middleware groups are part of the package routing model and should be preferred over ad hoc tenant-versus-central route branching.
## Optional Features
Feature classes shipped in `src/Features`:
- `CrossDomainRedirect`
- `DisallowSqliteAttach`
- `TelescopeTags`
- `TenantConfig`
- `UserImpersonation`
- `ViteBundler`
Features bootstrap independently from tenant initialization and are intended to be enabled through `tenancy.features`.
Feature behavior:
- `CrossDomainRedirect`
adds a `RedirectResponse::domain(string $domain)` macro that swaps the redirect host without rebuilding the whole URL.
- `DisallowSqliteAttach`
blocks SQLite `ATTACH` usage by registering an authorizer on SQLite PDO connections, using a native authorizer on PHP 8.5+ and a loadable extension fallback on older runtimes.
- `TelescopeTags`
adds a `tenant:{tenantKey}` Telescope tag when tenancy is initialized.
- `TenantConfig`
maps tenant attributes into config values using event listeners. This feature is deprecated in favor of `TenantConfigBootstrapper`.
- `UserImpersonation`
adds a `tenancy()->impersonate()` macro, stores impersonation tokens in the configured impersonation token model, validates token TTL and tenant match, logs the user in with the configured guard, and exposes `isImpersonating()` plus `stopImpersonating()`.
- `ViteBundler`
configures Vite asset path generation to use `global_asset()` so asset URLs stay central rather than tenant-scoped.
## Pending Tenants
Pending tenant support is configured under `tenancy.pending`.
Important behavior:
- `include_in_queries` controls whether pending tenants are included in normal tenant queries.
- `count` controls the maintained size of the pending-tenant pool.
- the package ships dedicated commands for creating and clearing pending tenants.
If a task touches pre-provisioned tenant pools, inspect the pending-tenant commands and model scopes before implementing custom provisioning logic.
## Commands
Commands registered by `TenancyServiceProvider`:
- `tenancy:install`
- `tenants:up`
- `tenants:run`
- `tenants:down`
- `tenants:link`
- `tenants:seed`
- `tenant:tinker`
- `tenants:migrate`
- `tenants:rollback`
- `tenants:list`
- `tenants:dump`
- `tenants:migrate-fresh`
- `tenants:pending-clear`
- `tenants:pending-create`
- `tenants:purge-impersonation-tokens`
- `tenants:rls`
Prefer these commands over hand-written loops for tenant maintenance tasks.
Command notes:
- `tenancy:install`
publishes config, routes, service provider, and core migrations, then creates `database/migrations/tenant`.
- `tenants:migrate`
applies `tenancy.migration_parameters`, supports concurrent execution, and can continue with `--skip-failing`.
- `tenants:rollback`
rolls back tenant migrations.
- `tenants:migrate-fresh`
rebuilds tenant schema from scratch.
- `tenants:dump`
dumps a tenant schema and defaults the dump path from `tenancy.migration_parameters.--schema-path`.
- `tenants:seed`
uses `tenancy.seeder_parameters`.
- `tenants:run`
runs arbitrary artisan commands against tenant context.
- `tenant:tinker`
opens Tinker in a selected tenant context and supports searching by tenant key or domain.
- `tenants:link`
manages tenant storage symlinks used by tenant-aware public disk URLs.
- `tenants:down` / `tenants:up`
toggle tenant maintenance mode.
- `tenants:pending-create` / `tenants:pending-clear`
manage the pending-tenant pool.
- `tenants:purge-impersonation-tokens`
removes expired impersonation tokens.
- `tenants:rls`
creates the shared RLS user and row-level-security policies for tenant-related tables.
## Related Subsystems
The package also includes:
- `src/Events/*` for tenancy lifecycle, tenant, domain, database, storage, and pending-tenant events
- `src/Listeners/*` for bootstrapping and reverting context
- `src/Jobs/*` for database and storage lifecycle jobs
- `src/ResourceSyncing/*` for central-to-tenant resource syncing
- `src/RLS/*` for PostgreSQL row-level security support
- `src/Actions/*` for route cloning and storage symlink helpers
When a task touches one of these areas, inspect the relevant namespace before inventing a parallel abstraction in app code.

View file

@ -0,0 +1,33 @@
# Pending Tenants Reference
Use this when maintaining a pool of prepared tenants.
## Source Files
- `src/Commands/CreatePendingTenants.php`
- `src/Commands/ClearPendingTenants.php`
- `src/Database/Concerns/HasPending.php`
- `src/Database/Concerns/PendingScope.php`
- `src/Jobs/CreatePendingTenants.php`
- `src/Jobs/ClearPendingTenants.php`
## Config
- `pending.include_in_queries`
- `pending.count`, defaulting to `TENANCY_PENDING_COUNT` or 5
## Commands
```bash
php artisan tenants:pending-create
php artisan tenants:pending-create --count=10
php artisan tenants:pending-clear
php artisan tenants:pending-clear --older-than-days=7
php artisan tenants:pending-clear --older-than-hours=12
```
## Rules
- When `include_in_queries` is false, pending tenants are excluded from tenant queries and tenant commands.
- Use `withPending()`, `withoutPending()`, and `onlyPending()` intentionally.
- Test command behavior with and without pending tenants included in queries.

View file

@ -0,0 +1,32 @@
# Resource Syncing Reference
Use this when syncing central resources into tenant contexts.
## Source Files
- `src/ResourceSyncing/*`
- `assets/resource-syncing-migrations/*`
- `assets/TenancyServiceProvider.stub.php`
## Setup
Publish resource syncing migration:
```bash
php artisan vendor:publish --provider="Stancl\Tenancy\TenancyServiceProvider" --tag=resource-syncing-migrations
php artisan migrate
```
## Main Pieces
- `tenant_resources` table.
- `ResourceSyncing` classes and listeners.
- `SyncMaster`, `Syncable`, `TenantPivot`, `TenantMorphPivot`.
- Events such as `SyncedResourceSaved`, `SyncedResourceDeleted`, `CentralResourceAttachedToTenant`.
## Rules
- Use package events/listeners instead of custom tenant loops.
- Keep central and tenant resource lifecycles explicit.
- Configure soft-delete query behavior in the application `TenancyServiceProvider` when needed.
- Test create, update, delete, restore, attach, and detach behavior.

View file

@ -0,0 +1,33 @@
# PostgreSQL RLS Reference
Use this when implementing single-database PostgreSQL row-level security.
## Source Files
- `src/Bootstrappers/PostgresRLSBootstrapper.php`
- `src/RLS/*`
- `src/Database/Concerns/RLSModel.php`
- `src/Commands/CreateUserWithRLSPolicies.php`
- `tests/RLS/*`
## Config
- `rls.manager`
- `rls.user.username`
- `rls.user.password`
- `rls.session_variable_name`
- `PostgresRLSBootstrapper` in `bootstrappers`
## Command
```bash
php artisan tenants:rls
php artisan tenants:rls --force
```
## Rules
- Use PostgreSQL and single-database tenancy.
- Session variable name must be namespaced, for example `my.current_tenant`.
- RLS user is one tenant database user for all tenants, not one user per tenant.
- Test policies on every tenant-owned table.

View file

@ -0,0 +1,49 @@
# Routing And Assets Reference
Use this when working with tenant routes, route modes, cloned routes, or tenant assets.
## Source Files
- `assets/tenant_routes.stub.php`
- `assets/TenancyServiceProvider.stub.php`
- `assets/routes.php`
- `src/Actions/CloneRoutesAsTenant.php`
- `src/Enums/RouteMode.php`
- `src/Controllers/TenantAssetController.php`
## Published Tenant Routes
The stub groups tenant routes with:
- `web`
- `InitializeTenancyByDomain`
- `PreventAccessFromUnwantedDomains`
- `ScopeSessions`
The application `TenancyServiceProvider` loads `routes/tenant.php` under the `tenant` middleware group.
## Route Modes
The package registers these middleware groups:
- `clone`
- `universal`
- `tenant`
- `central`
`tenancy.default_route_mode` defaults to central. Override per route using route mode middleware.
## Asset Routes
When `tenancy.routes` is true, the package registers:
- `/tenancy/assets/{path?}` named `stancl.tenancy.asset`
- `/{tenant}/tenancy/assets/{path?}` named `tenant.stancl.tenancy.asset` for path identification
## Rules
- Keep central and tenant routes explicit.
- Use `routes/tenant.php` for tenant application routes when using the stub.
- Use `universal` only for routes intended to work in both contexts.
- Use `CloneRoutesAsTenant` for package route integration instead of manually duplicating route definitions.
- Disable package routes only if using external storage or a custom asset controller.

View file

@ -0,0 +1,43 @@
# Testing Reference
Use this when adding or reviewing tenancy behavior tests.
## Source Files
- `tests/TestCase.php`
- `tests/Pest.php`
- `tests/*`
## High-Value Test Areas
- Installation and published files.
- Central route access.
- Tenant route access.
- Domain, subdomain, path, request data, and origin header identification.
- Identification failures.
- Tenant context API restoration after success and exceptions.
- Database connection switching and reverting.
- Cache, Redis, filesystem, session, queue, URL, mail, and broadcasting scoping.
- Tenant migrations, rollbacks, seeds, and tenant command options.
- Tenant lifecycle jobs and event pipelines.
- Resource syncing.
- User impersonation.
- Pending tenants.
- RLS policies.
- Optional features.
## Useful Existing Tests
- `tests/AutomaticModeTest.php`
- `tests/ManualModeTest.php`
- `tests/RouteMiddlewareTest.php`
- `tests/PathIdentificationTest.php`
- `tests/RequestDataIdentificationTest.php`
- `tests/OriginHeaderIdentificationTest.php`
- `tests/TenantAssetTest.php`
- `tests/CommandsTest.php`
- `tests/QueueTest.php`
- `tests/SingleDatabaseTenancyTest.php`
- `tests/RLS/*`
- `tests/ResourceSyncingTest.php`
- `tests/TenantUserImpersonationTest.php`