Workspace & Team

Members and roles

Invite teammates, assign roles, and understand what each role can do.

Project88 has org-level membership: when you invite someone, they get access to every workspace in the org.

Roles

RoleCan do
ownerEverything an admin can do, plus delete the org and reassign
ownership. There can be multiple owners.
adminManage members, billing plan, provider keys, integrations, and
every workspace. Cannot delete the org.
memberRead and create their own resources (agents, pages, data,
conversations). Cannot change org-level config.

On signup, your personal org is created with you as the sole owner.

Inviting people

⌘KSettings → MembersInvite member. This panel is OrgMembersPanel.jsx and it shows both active members and pending invites in one view.

The flow end-to-end:

  1. Owner / admin enters an email address and picks a role.
  2. api.invites.send({ orgId, email, role }) creates an invite row and the org-invites Edge Function sends an email with a tokenised link.
  3. Recipient clicks the link. api.invites.validate(token) calls get_invite_public_info to fetch the org name, role, and invitee email (without revealing anything sensitive about the org).
  4. The signup / login form is prefilled with the invitee's email so the path from invite → account is one step shorter.
  5. As soon as the user signs in (or signs up and the trigger fires), accept_org_invite(token) runs and they're added to the org. This bypasses the /office lobby routing race that used to land users in their personal org before the invite was accepted.

If the invitee already has a Project88 account, they accept and are in. If not, signup → auto-sign-in → auto-accept happens in one continuous flow.

Pending invites

Pending invites appear in the Members panel with Resend and Revoke buttons. They also surface on the invitee's verify-email page once they've signed up but not yet joined — so a half-completed signup picks up exactly where it left off.

Removing members

Members tab → on a row → Remove. Confirms with a destructive modal (the shared ConfirmDialog primitive). Removal soft-deletes the member's org_seats row and revokes access immediately. The user's personal account is untouched.

Changing roles

Members tab → Change role, backed by the update_org_member_role RPC. Pick owner / admin / member.

Transferring ownership

Owners can transfer ownership to another member via api.orgs.transferOwnership({ orgId, newOwnerId }) — backed by the transfer_org_ownership RPC. The previous owner is demoted to admin.

Leaving an org

Members (and admins, and non-last owners) can leave via api.orgs.leave(orgId) — backed by the leave_org RPC. Owners cannot leave their last own org; you have to transfer ownership first.

Removing or demoting the last owner of an org is not enforced by the UI today. If you're transferring ownership, promote the new owner first, then transfer / demote — otherwise you risk leaving the org ownerless.

Security

  • Members can only see other members in their own orgs (org_members RLS).
  • Role changes and member removal require owner or admin.
  • The handle_new_user_org() trigger ensures every new user always has at least one personal org they own — so no user can ever be orphaned.

Where to next

On this page