Release 3.0
π 3.0 β Release Highlights
Introduces a major refactor of the teams, roles, and permissions system.
This release simplifies the API, unifies permissions management, and makes it easier to build multi-tenant apps with fine-grained access control.
β¨ Whatβs New
- Unified Permissions Model
ReplacedCapabilitieswith a newPermissions+Abilitiessystem for cleaner, more flexible access rules. - Improved Groups & Roles
Roles and groups now share a consistent permission model. Groups can attach/detach users dynamically. - Entity-Specific Abilities
Abilities are polymorphic: assign them to users, groups, or roles with fullallow/forbidcontrol. - Invitation System
Built-in team invitations with configurable routes (/invitation/{id}/accept). - Cleaner Middleware
Middleware syntax now supports{team_id},{entity_id}placeholders and improved OR/AND checks. - New API Methods
Helpers likeTeam::inviteUser(),Team::getRole(),User::hasTeamPermission($scope)simplify common tasks.
β‘ Why Upgrade?
- More powerful and predictable access control logic.
- Cleaner database schema with fewer pivots and clearer naming.
- Easier to extend teams with custom roles, groups, and entity-specific permissions.
- Middleware and API now match modern Laravel conventions.
Breaking Changes
- Removed
Capabilitymodel β replaced withPermission+ new polymorphic tables:entity_permissionentity_ability
- All role/group capability relations now resolved through permissions.
- Pivot table renamed:
group_user(previouslyuser_group)
Ownermoved to:Jurager\Teams\Models\Owner(wasJurager\Teams\Owner)
hasTeamAbility()fully refactored:- introduces priority of sources (
roleβgroupβglobalβuser) - adds support for
forbiddenflag - adds wildcard permission resolution (
a.b.cβa.*,a.b.*)
- introduces priority of sources (
- Legacy relation methods (
users(),roles(),groups()) moved into theHasMemberstrait. - Old
Teamrelation methods (users(),roles(),groups(),abilities()) removed (migrated toHasMembers). - Support for
support_field(is_support) in config removed β replaced byinvitations.
Added
- Polymorphic ability system:
Abilityβentity_abilityforusers,groups,roles- Pivot includes
forbiddenflag + timestamps
- Permission polymorphic relations:
Permissionβentity_permission(roles, groups)
- Trait
HasMembers:- Common team-related helpers:
owner,users,abilities
- Common team-related helpers:
- New team methods:
Team::purge()β cleanup helperTeam::getPermissionIds()β resolves permission codes to IDs (auto-creates missing)
- Invitations improvements:
- New config section
invitations(enabled,routes.url,routes.middleware) Team::inviteUser($email, $role)Team::inviteAccept($invitationId)
- New config section
Changed
- Permission model:
$fillable = ['name', 'code', 'team_id']timestamps = falseroles()/groups()βmorphedByManyviaentity_permission
- Role:
- Eager-loads
permissions(protected $with = ['permissions']) - Detaches permissions & abilities on delete
- Eager-loads
- Group:
- Eager-loads
permissions - Detaches permissions & abilities on delete
- Uses
group_userpivot with timestamps
- Eager-loads
- Team:
- Eager-loads
roles.permissions+groups.permissions - Most relation methods moved into
HasMembers
- Eager-loads
- HasTeams trait:
- New
ownsTeam(),abilities()relations teamPermissions()/hasTeamPermission()accept$scope = 'role'|'group'hasTeamAbility()β reworked with new logic (priority, forbidden, wildcard)
- New
- Membership:
- Table name resolved from
teams.tables.team_user
- Table name resolved from
- Service Provider:
- Routes registered with configurable
teams.routes.prefix|middleware - Conditional publishing of
invitationsmigration (teams.invitations.enabled)
- Routes registered with configurable
- Middleware:
- Ability middleware now checks via:
$user->hasTeamAbility($team, $ability, $entity)
- Updated route parameter style:
{team_id},{article_id}
- Ability middleware now checks via:
Database & Migrations
- New / Renamed migrations:
abilitiesentity_ability(waspermissions)entity_permission(wasrole_capability)group_user(wasuser_group)groups(updated schema)
- Optional migration:
invitations(enabled viateams.invitations.enabled) - Migration publishing now uses fixed filenames