Skip to the article
Aniq-UI

NorthstackTeam, roles and permissions

Team, roles and permissions

How a workspace's members, invitations and seats work, the four workspace roles and the fourteen permissions of each workspace's roles matrix, what each seeded account sees, and how ownership moves.

For the Full Stack package

How access works

  • An account is anyone who signs in. It belongs to a workspace through a membership with one role: Owner (exactly one per workspace), Admin, Member or Billing. The same account can hold a different role in each workspace it belongs to.
  • Each workspace keeps its own roles matrix: which role holds which of fourteen permissions. The owner holds them all and cannot be edited, and two of them, workspace.delete and roles.manage, stay with the owner whatever the matrix says. A new workspace starts from the defaults below.
  • The API checks every workspace request on the server: an account that is not a member gets 404, as if the workspace did not exist, and a missing permission gets 403. A suspended workspace keeps every read and refuses every write.
  • The dashboard hides the sidebar rows and buttons a role does not include, and a page opened by its address shows Access required.
  • A change to a member's role or to the matrix applies to that member's next request to the API. Their sidebar and buttons follow the next time the dashboard reads the workspace, at the latest on a reload.
  • Platform staff (Platform admin and Support) are a separate set of roles across every workspace: see Platform administration.

The seeded roles and accounts

Forma Studio, the seeded workspace, uses the default matrix. Each role has one seeded account that signs in to the dashboard; the installation guide lists their sign-in details.

RoleAccountPermissionsSidebar
Ownerowner@northstack.example (Alex Morgan)All 14Overview, Projects, Team, Roles, Billing, Settings and AI assistant
Adminadmin@northstack.example (Sam Carter)workspace.read, workspace.update, projects.read, projects.write, members.invite, members.remove, keys.manage, audit.read, ai.read, ai.applyOverview, Projects, Team, Roles (read only), Settings with API keys, and AI assistant; no Billing
Membermember@northstack.example (Noor Hassan)workspace.read, projects.read, projects.write, ai.read, ai.applyOverview, Projects, Team, Roles (read only), Settings (read only for the workspace's details) and AI assistant
Billingbilling@northstack.example (Jordan Ellis)workspace.read, billing.read, billing.manageOverview, Team, Roles (read only), Billing and Settings; no Projects and no AI assistant
  • workspace.read is what opens the Team, Roles and Settings rows, so every role, Billing included, sees the member list, the read-only matrix and the settings. The overview's projects, its weekly chart and the projects needing attention need projects.read. Its recent activity and the bell show every event to a role holding projects.read or audit.read; a role with billing.read and neither of those (Billing, as seeded) sees only the billing events, and any other role sees none. The full activity log and its export need audit.read.
  • The workspace's billing email comes back only to a role with billing.read or billing.manage.
  • Forma Studio has 8 members (an owner, an admin, five members and a billing contact) on the Pro plan's 10 seats, with two pending invitations and one archived project. The owner is also an admin of a second workspace, Monogram, which has its own owner, team, invitation and API key.
  • yarn seed writes a workspace's matrix only when it has none, so running it again keeps the changes you made on the Roles page. Change every seeded password, or delete the sample accounts, before the dashboard is reachable from the internet.

Every workspace permission

The Roles page groups the permissions under the labels below. The list is defined once, in back-end/src/modules/workspaces/constants/workspace-permissions.ts, with the defaults every new workspace starts from.

GroupPermissionOn the Roles pageDefault roles
Workspaceworkspace.readView workspace: the workspace and its teamOwner, Admin, Member, Billing
Workspaceworkspace.updateEdit workspace: its details and notification switchesOwner, Admin
Workspaceworkspace.deleteDelete workspace (owner only)Owner
Projectsprojects.readRead projects: projects, tasks and filesOwner, Admin, Member
Projectsprojects.writeEdit projects: create, edit, archive and restore projects and tasks, upload filesOwner, Admin, Member
Membersmembers.inviteInvite members: send, resend and revoke invitationsOwner, Admin
Membersmembers.removeRemove membersOwner, Admin
Membersroles.manageManage roles: change a member's role and the matrix (owner only)Owner
Billingbilling.readView invoices: the plan and invoicesOwner, Billing
Billingbilling.manageManage subscription: the plan, the payment details and the billing emailOwner, Billing
Developerkeys.manageManage API keysOwner, Admin
Developeraudit.readRead activity log: read and export itOwner, Admin
AI assistantai.readUse the assistantOwner, Admin, Member
AI assistantai.applyApply suggestions the assistant makesOwner, Admin, Member

What the assistant can reach

ai.read opens the AI assistant and grants nothing else. The assistant is offered only the tools the member's role allows, each needing the same permission as its page: without billing.read it cannot read the plan or the invoices, and without audit.read it cannot read the activity. It writes nothing by itself: applying the tasks it proposes needs both ai.apply and projects.write, checked again when Add is pressed.

The Team page

/en/dashboard/team has two tabs, Members and Invitations, each with a search and a Role filter. Members are listed owner first, then by role and by when they joined.

ActionWhereNeeds
Invite memberThe page headermembers.invite
Change role (Admin, Member or Billing)A member's actions menuroles.manage, so the owner
Make ownerA member's actions menuThe owner, with their password
Remove from workspaceA member's actions menumembers.remove
Resend invitation and Revoke invitationAn invitation's actions menumembers.invite
  • The owner's row has no actions: ownership moves only through Make owner.
  • Removing someone takes them out of this workspace at once; their projects and tasks stay. Nobody removes themselves from this menu, and an admin may remove members and billing contacts but not another admin (the API answers 403).
  • A removed member keeps their account and their other workspaces.

Invitations and seats

  • Invite a member asks for an email address and a role, and lists what that role will be able to do. The person is mailed a link to /en/invitations/<token> that lasts seven days; without SMTP_HOST the message, link included, is written to the API's log.
  • The invitation page shows the workspace, the role, the invited email (masked) and who sent it. Accepting needs the invited email signed in: someone new creates an account with that email first. An invitation for another email, an expired one or a revoked one is refused with its own message.
  • Each plan has a number of seats: 3 on Starter, 10 on Pro and 30 on Scale. A pending invitation uses no seat; accepting one does. With no free seat, a new invitation is refused ("There is no free seat. Change the plan to invite more people."), and so is accepting one, checked in the same transaction so two people cannot take the last seat at once.
  • Resend invitation makes a new link and a new seven-day expiry, once a minute at most and five times per invitation. Revoke invitation makes the link stop working.
  • Inviting someone who is already a member, or who already has a pending invitation, is refused. Once a past-due workspace's grace period (BILLING_GRACE_DAYS) has run out, new invitations are refused until it is paid.

The Roles page

/en/dashboard/roles shows the workspace's matrix: one row per permission, in the six groups above, and one column per role, each cell Allowed or Not allowed. The Owner column is locked, and the Delete workspace and Manage roles rows say Owner only.

  • Only the owner changes it. Everyone else who holds workspace.read sees it read only: "Only the workspace owner changes what each role can do."
  • Save changes first shows what each role gains and loses, then saves the whole matrix and writes one roles.updated event to the activity log. Reset goes back to the saved matrix.
  • The four roles are fixed: a workspace cannot add a fifth. To give someone less than a role, take the permission away from that role, which changes it for everyone who holds it.

Ownership

  • Make owner asks for the owner's password, then makes the chosen member the owner and the previous owner an admin, in one step. It is written to the activity log as ownership.transferred.
  • The owner alone deletes the workspace, from Settings, with its name and their password.
  • On the platform, an account that owns a workspace cannot be deleted until another member is made owner.

The routes behind these pages

RoutePermission
GET /api/workspaces/:workspaceId/membersworkspace.read
PATCH /api/workspaces/:workspaceId/members/:memberIdroles.manage
DELETE /api/workspaces/:workspaceId/members/:memberIdmembers.remove
POST /api/workspaces/:workspaceId/members/transfer-ownershipthe owner
GET /api/workspaces/:workspaceId/invitationsworkspace.read
POST /api/workspaces/:workspaceId/invitations, POST .../invitations/:id/resend, DELETE .../invitations/:idmembers.invite
GET /api/invitations/:token and POST /api/invitations/:token/acceptnone to read; signed in as the invited email to accept
GET /api/workspaces/:workspaceId/rolesworkspace.read
PUT /api/workspaces/:workspaceId/rolesthe owner (roles.manage)

:workspaceId is the workspace's public id, such as org_forma. Errors come back as codes: seat_limit_reached, already_member, already_invited, resend_too_soon, resend_limit_reached, owner_protected, workspace_owner_only and invalid_password among them.

How the permission checks are built

Included with your purchase. Sign in to read, or open it in your download.

Where the API and the dashboard check a workspace permission, and how to add one.

Stuck on a step?

Find a fix before you start over.

Troubleshooting

Cookie Preferences

We use cookies to enhance your browsing experience, analyze site traffic, and personalize content. By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising.