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.removedrows 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
- Go to Settings → Team.
- Click Invite.
-
Fill in:
- Email — the address the invite goes to. Becomes the sign-in email.
- Role —
admin,staff, orread_only. Owners can promote a member toownerlater. - Stores — for
staffandread_only, pick which stores they can see. Default is all. - Modules — optionally hide specific modules (e.g. Vendors, Reports) from this member.
- Click Send invite. We email a tokenized link that expires in 7 days.
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— everythingadmincan 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, vendors | yes | yes | yes | yes |
| Create / edit orders, clients, vendors | yes | yes | yes | no |
| Record payments, refunds | yes | yes | yes | no |
| Send email / SMS to clients | yes | yes | yes | no |
| Mint / rotate / revoke integration keys | yes | yes | no | no |
| Edit webhook endpoints | yes | yes | no | no |
| Invite / remove teammates | yes | yes | no | no |
| Change another member’s role | yes | yes (not owner) | no | no |
| Edit billing / change plan | yes | yes | no | no |
| Export audit log | yes | yes | no | no |
| Add / archive a store | yes | yes | no | no |
| Promote / demote owners | yes | no | no | no |
| Delete the workspace | yes | no | no | no |
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 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
- Go to Settings → Team.
- Click the row for the member you want to remove.
- Click Remove at the bottom of the panel and confirm.
- 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.removedentry to the audit log.
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
| Symptom | Likely cause | Fix |
|---|---|---|
| Invitee says “link expired” | Token is older than 7 days | Resend the invite from Settings → Team. |
| Invite email never arrived | Greylisted / spam | Whitelist noreply@peptideclients.com; resend; have them check spam. |
| Member can’t see store B | Role is staff / read_only with no grant for B | Add the store under Settings → Team → member → Store access. |
| Removed member still has a tab open | Page rendered before the revoke | The next request 401s; the tab redirects to sign-in within 30 seconds at most. |
| “Cannot remove last owner” | Promote another member to owner first | See Remove a teammate. |
| MFA prompt loops on a member | Org-wide MFA is on, member hasn’t enrolled | Have them complete enrollment in Settings → Security. |
Related
- Auth & MFA — the per-member enrollment walk-through.
- Audit log — the full record of every team and operational event.
- Multi-store workspaces — per-store grants, what’s scoped where.
- Billing & quotas — some plan tiers cap the team size.