Skip to content

Roles & Permissions

XetaSuite uses Spatie Laravel-Permission with teams mode enabled to manage permissions per site.

User ─┬─ Site 1 ─── Role: Admin ─── Permissions: [company.*, user.*, ...]
├─ Site 2 ─── Role: Manager ─── Permissions: [material.*, zone.*, ...]
└─ Site 3 ─── Role: User ─── Permissions: [material.view, zone.view]
'teams' => true,
'team_foreign_key' => 'site_id',
// ⚠️ ALWAYS set site context BEFORE assignment
setPermissionsTeamId($site->id);
// Assign the role
$user->assignRole('manager');
// The role is saved with site_id in the pivot table
class CompanyPolicy
{
public function view(User $user, Company $company): bool
{
// Checks permission for current site
return $user->can('company.view');
}
}
public function index(Request $request)
{
// Via Gate
$this->authorize('viewAny', Company::class);
// Or directly
if ($request->user()->can('company.viewAny')) {
// ...
}
}
const { hasPermission, hasRole, hasAnyPermission } = useAuth();
// Single permission
{hasPermission('company.create') && <CreateButton />}
// Multiple permissions (OR)
{hasAnyPermission(['company.update', 'company.delete']) && <EditMenu />}
// Role
{hasRole('admin') && <AdminPanel />}
{resource}.{action}
ActionDescription
viewAnyView list
viewView single
createCreate
updateUpdate
deleteDelete
ModulePermissions
Sitessite.viewAny, site.view, site.create, site.update, site.delete
Zoneszone.viewAny, zone.view, zone.create, zone.update, zone.delete
Materialsmaterial.viewAny, material.view, material.create, material.update, material.delete, material.generateQrCode, material.scanQrCode
Maintenancesmaintenance.viewAny, maintenance.view, maintenance.create, maintenance.update, maintenance.delete
Incidentsincident.viewAny, incident.view, incident.create, incident.update, incident.delete
Cleaningscleaning.viewAny, cleaning.view, cleaning.create, cleaning.update, cleaning.delete
Itemsitem.viewAny, item.view, item.create, item.update, item.delete, item.generateQrCode, item.scanQrCode
Movementsitem-movement.viewAny, item-movement.view, item-movement.create, item-movement.update, item-movement.delete
Companiescompany.viewAny, company.view, company.create, company.update, company.delete
Usersuser.viewAny, user.view, user.create, user.update, user.delete, user.restore, user.assignDirectPermission, user.assignSite
Rolesrole.viewAny, role.view, role.create, role.update, role.delete
Permissionspermission.viewAny, permission.view, permission.create, permission.update, permission.delete
Settingssetting.viewAny, setting.view, setting.update,

The permission middleware runs after site context is set:

SetCurrentSite → SetCurrentPermissionsAndRoles → Controller
  1. SetCurrentSite - Reads user.current_site_id, caches is_on_headquarters
  2. SetCurrentPermissionsAndRoles - Calls setPermissionsTeamId(siteId), refreshes cached relations

Some resources (Companies) are only accessible from the headquarters:

public function before(User $user, string $ability): ?bool
{
if (! isOnHeadquarters()) {
return false; // Blocks access from regular sites
}
return null; // Continue to specific check
}