docs/features/members.md

Members

Members are the humans in a Vocion deployment — distinct from agent Teams. Every deployment is a multi-user product: an account holds people with roles, and admins manage them from the dashboard without touching the database.

The page

Dashboard → Settings → Members (/dashboard/members) shows everyone in the account:

  • Name, email, role, join date for each member.
  • Admins can change roles (admin ↔ member) and remove members inline.
  • Everyone else sees the roster read-only.

Two guardrails are enforced server-side: you cannot remove yourself, and you cannot demote or remove the last admin — promote someone else first.

Roles

RoleCan
adminEverything: manage members, send invites, approve actions, edit budgets, all admin-gated pages.
memberUse the workspace: chat, search, review queues, and every non-admin surface.

Roles live on the account membership (account_membership), carried in the session JWT, and checked by the same guardRole layer that protects every RPC route.

Invites are links, not emails. Vocion deliberately ships with no mail dependency — a fresh deployment has working invites with zero SMTP/SES/Resend setup:

  1. An admin clicks Invite member, enters an email + role.
  2. Vocion mints a one-time token (14-day expiry) and shows the invite URL.
  3. The admin copies the link and shares it directly — Slack, DM, however the team talks.
  4. The invitee opens /sign-up?invite=<token>, sets a name + password, and lands in the dashboard with the assigned role.

Each link is bound to the invited email and single-use: sign-up rejects a different email, a reused token, or an expired one. Re-inviting the same address revokes the old link and mints a fresh one. Pending invites are listed on the page with copy + revoke controls.

If you later wire a mailer, the same token flow is the delivery payload — email is a transport, not a dependency.

API

All operations are standard oRPC routes under members.*:

RouteGuardDoes
members.listmemberRoster with roles
members.invitesadminPending invites
members.inviteadminMint an invite link (email + role)
members.revokeInviteadminKill a pending link
members.changeRoleadminPromote / demote
members.removeadminRemove a member