convex-teams

Workspaces and roles

Ownership, membership, personal teams, preferences, and deletion.

One owner per workspace

Each team has one owner. An owner can transfer ownership to an existing member. The transfer changes the owner record and both membership roles in one transaction. The former owner becomes an admin.

OperationOwnerAdminMember
Read team and membersYesYesYes
Change team profileYesYesNo
Invite and manage non-owner membersYesYesNo
Read invitation recipientsYesYesNo
Transfer ownershipYesNoNo
Delete teamYesNoNo
Leave teamTransfer firstYesYes

Invitations and direct grants preserve existing roles. Use updateMemberRole for an explicit change. Generic role changes cannot change the owner.

Slug allocation

Creation checks at most five candidates. Shared workspaces first try the name. A collision adds a random suffix. Personal workspaces always include a random suffix. Generated slugs stay within 60 characters.

If all candidates collide, the mutation fails without creating a workspace. Retry creation. Do not depend on sequential suffixes such as -2.

Personal teams

ensurePersonalTeam creates a personal workspace explicitly. A separate personal-owner field identifies it. A default-team preference does not define personal ownership.

Personal ownership cannot be transferred. Invitation acceptance does not create a personal workspace.

Preferences and access

Active and default preferences select a workspace. They do not authorize access to host content. Check current membership before each protected operation.

After removal or deletion, preference repair checks saved preferences and scans memberships in batches of 25. A continuation rechecks current preferences, so a later explicit selection wins. The result can be temporarily null during repair.

Paginated lists

listTeams, listMembers, and listPendingInvites accept pagination options. Request 1 to 100 rows:

const result = await teams.listTeams(ctx, userId, {
  numItems: 25,
  cursor: null,
});

Read result.page. For the next request, pass result.continueCursor as the cursor. Continue until result.isDone is true, including after an empty page. Deletion cleanup can leave an empty intermediate team page.

Team pages use membership order. Sort the returned results in the host UI if needed.

Deletion

deleteTeam requires the owner. It immediately denies access and invalidates invitation grants. Cleanup removes memberships and repairs preferences in batches of 50. The final batch removes the team record. Cleanup supports retries.

The host owns content and billing cleanup. Store a durable host cleanup job in the same mutation that requests deletion. Use the immutable teamPublicId as its reference.

On this page