Overview

Every workspace has a team. The first member is the owner — you. Anyone you add becomes a member with one of four roles: owner, admin, staff, or read_only. Roles are coarse on purpose; per-module and per-store hiding fills in the gaps.

Every team change — an invite, an accepted invite, a role bump, a removal — lands in the tamper-evident audit log. Removals revoke active sessions immediately so an ex-teammate can’t finish whatever tab they had open.

What working correctly looks like

  • Inviting a new email lands a sign-up link in the recipient’s inbox in <30 seconds.
  • An accepted invite shows up in Settings → Team with role, last sign-in, and store access.
  • Changing a role takes effect on the member’s next request — no re-login needed.
  • Removing a teammate revokes their session within a second; their next click drops to the sign-in screen.
  • The audit log shows team.invited, team.role_changed, team.removed rows for each team event.
  • If org-wide MFA is on, members who haven’t enrolled a factor are bounced to Settings → Security on first sign-in.

Invite a teammate

  1. Go to Settings → Team.
  2. Click Invite.
  3. Fill in:
    • Email — the address the invite goes to. Becomes the sign-in email.
    • Roleadmin, staff, or read_only. Owners can promote a member to owner later.
    • Stores — for staff and read_only, pick which stores they can see. Default is all.
    • Modules — optionally hide specific modules (e.g. Vendors, Reports) from this member.
  4. Click Send invite. We email a tokenized link that expires in 7 days.
Resending or revoking an invite

Pending invites show a Pending chip in the team list. Click the row to Resend (re-issues the email) or Revoke (invalidates the token immediately).

Roles

Four roles, simple ladder. Pick the lowest one that lets the person do their job.

  • owner — everything admin can do, plus delete the workspace, transfer billing, and demote / remove other owners. There is always at least one. Limit to founders.
  • admin — full operational access: invite team, mint API keys, change billing, edit settings, refund payments, export audit log. Cannot delete the workspace.
  • staff — the day-to-day operator role: read+write on orders, clients, vendors, payments, fulfillment, communications. No access to billing, security, integration keys, or audit-log export.
  • read_only — can view everything in their granted stores; cannot create, edit, or delete anything. Useful for accountants, auditors, advisors.

Permission matrix

The headline differences between roles. Per-module hiding (see below) overrides this for finer cases.

Capability owner admin staff read_only
View orders, clients, vendorsyesyesyesyes
Create / edit orders, clients, vendorsyesyesyesno
Record payments, refundsyesyesyesno
Send email / SMS to clientsyesyesyesno
Mint / rotate / revoke integration keysyesyesnono
Edit webhook endpointsyesyesnono
Invite / remove teammatesyesyesnono
Change another member’s roleyesyes (not owner)nono
Edit billing / change planyesyesnono
Export audit logyesyesnono
Add / archive a storeyesyesnono
Promote / demote ownersyesnonono
Delete the workspaceyesnonono

Per-store and per-module scoping

Two levers narrow the role.

Per-store access

For staff and read_only, you can grant access to a subset of stores. Owners and admins always see all stores. Set this at Settings → Team → member → Store access.

Cross-store reads are blocked at the database via Row-Level Security — a staff member granted only to retail cannot read a single row from wholesale even if they craft a query against the API directly.

Per-module hiding

Some operators want “our shipping coordinator should only see Orders + Fulfillment, nothing else”. Toggle individual modules off for that member at Settings → Team → member → Modules. Hidden modules disappear from the nav and return 403 if the member visits the URL directly.

Module hiding is UI sugar, not a security boundary

Module hiding is for keeping nav uncluttered. The hard security boundary is the role + store-access pair, which is enforced in Postgres. Don’t rely on module hiding to keep secrets from a determined member — demote them to read_only or remove them.

Remove a teammate

  1. Go to Settings → Team.
  2. Click the row for the member you want to remove.
  3. Click Remove at the bottom of the panel and confirm.
  4. We:
    • revoke every active session for that user (their next click drops to the sign-in screen);
    • strip their workspace membership row;
    • retain their authored history (orders, notes, messages stay attributed to them as “former teammate”);
    • write a team.removed entry to the audit log.
Removing the last owner is blocked

The workspace must always have at least one owner. Promote another member first, then remove the previous owner. To transfer ownership entirely, promote, then have the new owner remove you.

Org-wide MFA

By default, MFA is per-member opt-in. To require it for everyone, owners and admins toggle Settings → Workspace → Security → Require MFA.

Once enabled:

  • Members without an enrolled factor are redirected to Settings → Security on next sign-in and can’t reach any other screen until they enroll.
  • New invitees enroll a factor before finishing onboarding.
  • You can also restrict which factors are accepted (e.g. require TOTP, disallow SMS).

See Auth & MFA for the enrollment walk-through.

Audit log

Every team change is recorded in the workspace audit log with the actor, the target, and a before/after diff:

  • team.invited — who invited whom, with what role and store grants.
  • team.invite_accepted — the recipient finished sign-up.
  • team.role_changed — who changed whom, from role X to role Y.
  • team.store_access_changed — granted / revoked store access.
  • team.module_visibility_changed — hid / unhid a module.
  • team.removed — who removed whom; sessions revoked.
  • team.invite_revoked — pending invite cancelled.

Filter the log by entity_type = team at Settings → Audit log. See the full Audit log guide for export, retention, and the hash chain.

Settings & permissions

  • Settings → Team — invite / remove / change roles. Visible to owners and admins.
  • Settings → Workspace → Security — org-wide MFA, allowed factors, session lifetime.
  • Settings → Audit log — the audit feed, filterable by team event.
  • Settings → Profile — visible to every role; lets each member manage their own name, signature, and security factors.

Troubleshooting

SymptomLikely causeFix
Invitee says “link expired”Token is older than 7 daysResend the invite from Settings → Team.
Invite email never arrivedGreylisted / spamWhitelist noreply@peptideclients.com; resend; have them check spam.
Member can’t see store BRole is staff / read_only with no grant for BAdd the store under Settings → Team → member → Store access.
Removed member still has a tab openPage rendered before the revokeThe next request 401s; the tab redirects to sign-in within 30 seconds at most.
“Cannot remove last owner”Promote another member to owner firstSee Remove a teammate.
MFA prompt loops on a memberOrg-wide MFA is on, member hasn’t enrolledHave them complete enrollment in Settings → Security.