Module Development — Production Guide
Licensing
- Active license =
workspace_module_subscriptionsintrial/active(and not ended). EnsureModule(module:{slug}) returns 403/402-style denial when the workspace lacks the module.- Default-included modules (
is_default_included) install on workspace provision; platform admins may deactivate. - Entitlements cache:
workspace:{id}:entitlements(1 hour); invalidated on install/cancel/deactivate.
Workspace bootstrap (explicit provisioning)
On workspace create (TenantProvisioningService):
- Billing profile
- Default modules installed
- Authorization defaults via
TenantAuthorizationProvisioningService(roles + permission maps) - Module-specific seed data (e.g. default lead stages)
- Owner user created (
TenantAuthBootstrapService::createOwner) — no RBAC side effects on login afterward
Authentication, dashboard, and role/user listing never repair permissions.
Shipping a new default-included module
Use data migrations, not production seeders:
- Schema migration(s)
- Catalog data migration →
App\Support\Catalog\DefaultModuleRegistrar - Permission data migration →
App\Support\Permissions\TenantPermissionSynchronizer::grantMissingDefaultRolePermissions([...]) - Deploy with:
bash
php artisan migrate --force
php artisan optimizeKeep CatalogSeeder updated for local/CI fresh databases only. Do not run db:seed / CatalogSeeder in production to register modules.
Never syncPermissions() against existing customized roles during deploy. Grants must be additive and idempotent.
What DefaultModuleRegistrar guarantees
firstOrCreateby module slug — never overwrites commercial flags, prices, or renamed fields- Installs subscriptions only when a workspace has never had a row for that module (checks soft-deleted)
- Does not reactivate cancelled / suspended / soft-deleted subscriptions
What TenantPermissionSynchronizer guarantees
- Creates missing permission vocabulary from
config/tenant-permissions.php - Grants only the listed new permission names to default roles that should have them
- Leaves customized role edits intact
Monitoring
- Platform audit log (
activitylog nameplatform) for install, assign, destructive actions - Spatie activity on domain models for attribute changes
- Nightwatch / Telescope for exceptions on module routes
- Stripe / gateway logs remain under Billing — modules must not bypass them
Deploy checklist
- Run migrations (
php artisan migrate --force) — include data migrations for catalog rows and additive permission grants - Do not rely on
CatalogSeeder/db:seedin production for new default modules - Confirm
tenant-permissions+tenant-default-role-permissionsconfig are deployed with the release (migrations read them) - Entitlement cache is cleared per workspace by the module registrar when a subscription is newly installed
- If the module contributes dashboard widgets or notifications, confirm scheduler (
crm:send-due-notifications) and SPA polling/widget ids - Smoke: login → module nav visible → list API 200 with
module:+can:
Rollback
- Soft-delete / deactivate module subscription to revoke licensing without dropping data
- Keep domain tables; do not drop migrations in production without a data plan
- Permission grant migrations are intentionally irreversible (do not revoke production role grants in
down())