🧱 Roles & Permissions Schema Map¶
Last updated: 2025-10-09 (Europe/Paris)
This diagram shows how Spatie Laravel-Permission’s tables connect to the Accounts context (users, organizations, memberships) when team mode is enabled. Use it as the source of truth when adjusting migrations, seeding roles, or debugging authorization issues.
🔗 Schema Overview¶
%%{init: {'themeVariables': {'fontSize': '15px'}, 'class': {'useMaxWidth': true}}}%%
classDiagram
direction LR
class User {
UUID id
string email (unique)
string password
timestamps
}
class Organization {
UUID id
string name
string slug (unique)
UUID owner_id
timestamps
}
class Membership {
UUID id
UUID user_id
UUID organization_id
string role
string status
json permissions
timestamps
}
class Role {
bigint id
string name
string guard_name
bigint team_id (nullable)
timestamps
}
class Permission {
bigint id
string name
string guard_name
timestamps
}
class ModelHasRoles {
bigint role_id
bigint model_id
string model_type
bigint team_id (nullable)
}
class ModelHasPermissions {
bigint permission_id
bigint model_id
string model_type
bigint team_id (nullable)
}
class RoleHasPermissions {
bigint role_id
bigint permission_id
}
User "1" --> "many" Membership : enrolls
Organization "1" --> "many" Membership : contains
Membership ..> Role : "syncs Spatie role"
User "1" --> "many" ModelHasRoles : "model_has_roles"
ModelHasRoles --> Role : "role_id"
Organization "1" --> "many" ModelHasRoles : "team_id"
User "1" --> "many" ModelHasPermissions : "model_has_permissions"
ModelHasPermissions --> Permission : "permission_id"
Organization "1" --> "many" ModelHasPermissions : "team_id"
Role "1" --> "many" RoleHasPermissions : "role_has_permissions"
RoleHasPermissions --> Permission : "permission_id"
note for ModelHasRoles "team_id references organizations.id when team mode is enabled"
note for ModelHasPermissions "team_id references organizations.id when team mode is enabled"
🧱 Domain Models in Scope¶
| Model | Stored in | Description |
|---|---|---|
Spatie\Permission\Models\Role |
roles |
Team-scoped roles mapped from organization memberships. |
Spatie\Permission\Models\Permission |
permissions |
Atomic abilities (artist.manage, release.publish, etc.). |
ModelHasRoles (pivot) |
model_has_roles |
Links a user (or other model) to a role within a specific team. |
ModelHasPermissions (pivot) |
model_has_permissions |
Direct ability grants to a user/model with team scoping. |
RoleHasPermissions (pivot) |
role_has_permissions |
Associates roles with their bundled permissions. |
📝 Implementation Notes¶
model_has_rolesandmodel_has_permissionsboth includeteam_idwhenpermission.teamsistrue. We set this to the active organization so Spatie scopes checks correctly.Membership::rolemirrors the high-level role (owner/admin/manager/artist/viewer). When memberships change, sync the Spatie role for that organization viaassignRole($role, $organization).- Per-member overrides (stored in
memberships.permissions) become direct permission grants usinggivePermissionTo($ability, $organization), populatingmodel_has_permissions. role_has_permissionsdefines reusable bundles of abilities (e.g.,artist.manage,release.publish). Seed these alongside organization creation.
Related Docs¶
docs/contexts/accounts/models.md— Accounts entities (users, organizations, memberships, invitations).docs/contexts/auth/roles-permissions.md— Narrative overview of access domains and default mappings.docs/contexts/auth/entity-diagram.md— High-level relationships between Spatie tables and other contexts.docs/contexts/auth/index.md— Other auth documentation (flows, guides).