Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Permissions Laravel Package

laravel-enso/permissions

Laravel Enso Permissions provides role and permission management for Enso-based Laravel applications, letting you assign permissions to roles and control user access through Laravel’s authorization layer. It integrates with Enso’s UI and core modules to simplify access-control administration.

View on GitHub
Deep Wiki
Context7

Getting Started

laravel-enso/permissions is not a standalone package — it is a thin CRUD and UI layer that sits on top of spatie/laravel-permission and only makes sense inside the broader Enso admin suite. Before touching it, make sure you actually have the surrounding pieces:

  1. Prerequisites

    • laravel-enso/core (provides Response, Forms, Tables, compositors, and the admin shell)
    • spatie/laravel-permission (the real permission engine — Enso only manages the records)
    • The paired Vue frontend enso-ui/permissions (the backend ships no meaningful Blade views; the UI lives in the npm package)
    • The Enso menu/route scaffolding so the "System → Permissions" entry appears
  2. Install

    composer require laravel-enso/permissions
    php artisan vendor:publish --tag=permissions   # if publishing config/migrations
    php artisan migrate
    

    The PermissionServiceProvider is auto-discovered and registers routes, migrations, the model binding, and the menu compositor.

  3. Where to look first

    • src/App/Http/Controllers/PermissionController.php — the four endpoints (index, store, update, destroy)
    • src/App/Http/Requests/ValidatePermissionRequest.php — the actual validation contract (name format, uniqueness, guard)
    • src/App/Tables/Builders/PermissionTable.php and src/App/Forms/Builders/PermissionForm.php — the shape of what the UI reads/writes
    • routes/api.php — the exact URLs (/api/system/permissions and friends)
    • src/database/migrations and src/database/seeders — how the table is created and the system.* permissions are seeded
    • config/permission.php (Spatie) — guard names, table names, cache TTL
  4. First use case Log in as an Admin, hit System → Permissions, create a permission named sales.invoices.view, assign it to a role, then verify enforcement in code with $user->can('sales.invoices.view') or @can('sales.invoices.view') in Blade. If the page 403s, the menu item/gate behind it is system.permissions.index — check that your admin role has it.

Implementation Patterns

Naming conventions drive everything. Enso permissions are just Spatie permissions, so the package does not enforce any structure. Adopt a dotted convention yourself (module.entity.action) so grouping, search, and UI filtering behave predictably. Never rename a permission casually — every @can/$user->can() string in your codebase is effectively a hard-coded foreign key.

Shipping permissions with features. Do not create permissions by hand in production. Write a feature seeder and run it as part of your deploy:

Permission::firstOrCreate(['name' => 'sales.invoices.approve', 'guard_name' => 'web']);

Role::where('name', 'manager')->first()
    ->givePermissionTo('sales.invoices.approve');

This is idempotent and safe to re-run — important because Enso's own seeders use the same firstOrCreate pattern.

Enforcement patterns. The admin panel manages the data; your application still uses standard Spatie guards:

  • Route::middleware('can:sales.invoices.approve')
  • Gate::define('approve-invoice', fn ($user, $invoice) => $user->can('sales.invoices.approve') && $invoice->user_id === $user->id)
  • FormRequest authorize(): bool { return $this->user()->can('sales.invoices.create'); }

Extending the UI. Because the table and form are Enso builder classes, the cleanest customization is subclassing:

  • Extend PermissionTable to add columns (e.g., a guard_name column, or roles_count via withCount('roles')), then re-bind in a service provider.
  • Extend PermissionForm to add a guard_name select or a description text field, then update ValidatePermissionRequest accordingly.

Do not edit the vendor files — Enso's model resolution is done through config (enso/config.php → models), so override the Permission class there rather than in composer.json.

Programmatic access. The API is unremarkable REST: GET /api/system/permissions (with Table query params like search, sort, page), POST, PUT /{id}, DELETE /{id}. Anything you can do in the UI — bulk assignment of roles to a permission, seeding a new tenant's permission set, scripting a migration of old permission names — you can do via these endpoints or (more commonly) directly against the Spatie models.

Role↔permission sync. The package exposes the roles relation on Permission. When you need bulk reconciliation (e.g., "manager role should always have these 12 permissions"), use Spatie's syncPermissions() on the Role model — do not go through the UI endpoints, which are per-record.

Integration with the Enso menu. The PermissionComposer (bound in the service provider) injects the permissions menu entry when the logged-in user passes the system.permissions.* gates. If you build a custom admin shell, replicate that composer pattern rather than hard-coding sidebar links.

Gotchas and Tips

  • This package is not useful standalone. It has no Blade views, no working UI without enso-ui/permissions, and no authorization engine of its own. If you're not already on Enso, install spatie/laravel-permission directly and build a simple CRUD screen — you'll save a dependency tree.

  • Spatie's cache is the #1 source of "I changed the permission but nothing happened." After direct DB writes or seeding, run php artisan permission:cache-reset (or cache:clear). In CI/CD pipelines, put this in your deploy script, not in the permission seeder — the seeder runs before the cache matters.

  • Guards bite silently. Spatie keys permissions by (name, guard_name). If your app uses a non-web guard (e.g., api for a token-based client), a permission created by the default Enso form (which writes web) will never match can('...') under the api guard. Either expose guard_name in the form (subclass it) or pin config('auth.defaults.guard') consistently.

  • Migration ordering. Enso ships its own create_permissions_table migration. If you also have Spatie's create_permission_tables, order matters — the pivot tables (role_has_permissions, model_has_permissions) must exist before Enso's seeders run. On a fresh install this is usually handled by laravel-enso/core; if you're assembling by hand, migrate Spatie first.

  • Do not delete the seeded system.* permissions. They gate the admin UI itself, including this very page. Deleting system.permissions.index will make the page 403 for everyone who isn't a super-admin. Same for system.roles.index, system.users.index, etc. If you need to test deletion, use a throwaway permission.

  • Update validation ignores the current id — verify it. ValidatePermissionRequest typically uses Rule::unique('permissions','name')->ignore($this->route('permission')). If you customize the name field, remember to keep that ignore() clause, or editing a permission (e.g., fixing a typo in its name) will fail with "already taken" against itself.

  • roles column needs eager loading. If you add roles to the table, make sure the query in PermissionTable::query() includes ->with('roles') (or ->withCount('roles')). Without it you get N+1 queries and, in Enso's table pagination, a slow page that's easy to miss until you have 200+ permissions.

  • Deleting a permission cascades role assignments through the pivot (role_has_permissions), but leaves your code intact. This is the most dangerous operation in the UI — a developer can delete a permission that a dozen @can calls still reference, silently turning all those checks into false. Consider a policy/process around deleting permissions in production, or mark them deprecated rather than deleting.

  • The super-admin / owner role bypass is not this package. Enso doesn't automatically grant a role every permission. If your admin sees the permissions page without an explicit system.permissions.index assignment, that's a Gate::before callback registered elsewhere (usually laravel-enso/core's AuthServiceProvider). Know which mechanism is in play before you assume a permission is "working."

  • Version pairing. enso-ui/permissions (Vue) and laravel-enso/permissions (PHP) must be on matching major versions. A mismatch typically manifests as the table rendering nothing, or the form fields not matching what the backend validates — an error that's unhelpful in the browser console.

  • Debugging tip: if a form submission fails with a 422 that doesn't match your ValidatePermissionRequest, check whether a FormRequest in a parent Enso package is intercepting it, or whether the Vue side is sending fields your builder doesn't declare. Enso silently drops unknown form fields on the way in — so a "missing field" bug is usually "field wasn't registered in the Form builder."

  • Extension, not modification. The intended customization surface is: subclass PermissionTable/PermissionForm/Permission and re-bind via config or a service provider. Anything else (editing routes, patching the controller) will break on the next composer update and the package maintainers assume you'll extend.

  • Route caching is fine, model caching is not. php artisan route:cache works because the routes use controller array syntax. But do not wrap Permission::all() or role lookups in Cache::remember yourself — Spatie already manages permission caching, and duplicating it will resurrect a stale set after permission:cache-reset.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core