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
| Role | Can do |
|---|---|
owner | Everything an admin can do, plus delete the org and reassign |
| ownership. There can be multiple owners. | |
admin | Manage members, billing plan, provider keys, integrations, and |
| every workspace. Cannot delete the org. | |
member | Read 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
⌘K → Settings → Members → Invite member. This panel is
OrgMembersPanel.jsx and it shows both active members and pending
invites in one view.
The flow end-to-end:
- Owner / admin enters an email address and picks a role.
api.invites.send({ orgId, email, role })creates an invite row and theorg-invitesEdge Function sends an email with a tokenised link.- Recipient clicks the link.
api.invites.validate(token)callsget_invite_public_infoto fetch the org name, role, and invitee email (without revealing anything sensitive about the org). - The signup / login form is prefilled with the invitee's email so the path from invite → account is one step shorter.
- 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/officelobby 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_membersRLS). - Role changes and member removal require
owneroradmin. - 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.