Skip to content

feat: add team role management - #52

Merged
bjarn merged 1 commit into
feat/team-invitesfrom
feat/team-roles
Oct 21, 2026
Merged

bjarn merged 1 commit into
feat/team-invitesfrom
feat/team-roles

Conversation

@bjarn

@bjarn bjarn commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

What changed

Adds team role management to $lettermint->team. team->roles is already the role list, so these are methods on team, named like the existing ones (team token):

Method Request Returns
retrieveRole(string $roleId) GET /team/roles/{roleId} TeamRoleData
createRole(array $body) POST /team/roles with CreateTeamRoleData (name, description?, permissions) TeamRoleData (201)
updateRole(string $roleId, array $body) PUT /team/roles/{roleId} with UpdateTeamRoleData TeamRoleData
deleteRole(string $roleId, array $query = []) DELETE /team/roles/{roleId}, optional ['replacement_role_id' => …] (DeleteTeamRoleQuery) MessageResponse
duplicateRole(string $roleId, array $body) POST /team/roles/{roleId}/duplicate with DuplicateTeamRoleData (name, description?) TeamRoleData (201)
  • deleteRole takes the generated query shape, like team->retrieve(array $query = []). Without it, or with replacement_role_id set to null, no query parameter is sent. A replacement role is needed only while the role is still assigned to members, invites or SCIM groups.
  • Custom roles need a plan that includes them. Permissions must include everything they depend on, and role names are unique within the team. Built-in roles can't be changed or deleted, and the Owner role can't be duplicated. Without a description, a duplicate keeps the source role's description.
  • TeamRoleData->description (string|null) is tested set, null and absent.
  • A 409 throws the existing ConflictException, with the conflict code (for example built_in_role_immutable) in errorCode. A 422 throws ValidationException. Empty, . and .. role IDs are rejected before any request.
  • No Idempotency-Key on these operations.
  • The coverage test no longer lists the five role operations as pending. Only member removal is still pending; the next PR adds it.
  • README: the role methods are in the Team API table, with a short example.

Non-breaking.

Usage

use Lettermint\Types\RbacPermission;

$role = $lettermint->team->createRole([
    'name' => 'Support',
    'description' => 'Reads messages.',
    'permissions' => [RbacPermission::MESSAGES_READ],
]);

$lettermint->team->updateRole($role->id, [
    'name' => 'Support',
    'description' => null,
    'permissions' => [RbacPermission::MESSAGES_READ, RbacPermission::SUPPRESSIONS_READ],
]);

$copy = $lettermint->team->duplicateRole($role->id, ['name' => 'Support (EU)']);
echo $lettermint->team->retrieveRole($copy->id)->description;

// The replacement receives the members, invites and SCIM groups that still hold the role.
$lettermint->team->deleteRole($role->id, ['replacement_role_id' => $copy->id]);

Checks

On this branch (PHP 8.5, Composer 2.10):

  • vendor/bin/pest --ci: 344 passed (3799 assertions)
  • vendor/bin/phpstan: no errors
  • vendor/bin/pint --test: passed
  • composer generate:check (full regeneration check): 170 generated files up to date
  • composer generate:check in the header-only mode that CI runs: headers of 170 generated files OK

Not run locally

  • The Windows jobs of the test matrix. The full Linux/macOS matrix ran on the top of the stack.

🤖 Generated with Claude Code

Add `retrieveRole`, `createRole`, `updateRole`, `deleteRole` and
`duplicateRole` to `$lettermint->team`. `deleteRole` takes an optional
`replacement_role_id` query for a role that is still assigned.

Co-Authored-By: Claude <noreply@anthropic.com>
@bjarn
bjarn requested a review from a team as a code owner October 20, 2026 20:49
@bjarn
bjarn added this pull request to stack #54 October 20, 2026 20:49
@bjarn
bjarn merged commit 15c3ec2 into main Oct 21, 2026
17 checks passed
@bjarn
bjarn deleted the feat/team-roles branch October 21, 2026 14:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants