User and admin roles
How Cascadia Marquee models access: platform account types, Cascadia staff roles, client organization roles, and brand-scoped access.
User and admin roles
Access in Cascadia Marquee comes from a few separate systems that stack together. This document explains each one, who gets what, and how they interact, so anyone deciding "what should this person be able to do?" has a single reference.
There are three layers:
- Account type (platform-wide): are you Cascadia staff, a client, or a free-scan lead?
- Staff role (Cascadia staff only): which parts of the admin workspace a staff member can open.
- Organization role and brand access (clients): what a person can do inside their own company's dashboard, and which brands they can see.
A single person has one account type, may have staff roles (if they are staff), and has one organization role per company they belong to.
For the technically curious: account types live in
src/lib/app-role.ts, staff roles insrc/lib/staff-tags.tsandsrc/lib/staff-permissions.ts, and client organization access insrc/lib/client-brand-scope.tsandsrc/lib/client-team-api.ts.
Layer 1: Account types
The account type is the top-level identity for a user across the whole platform. It is stored on the user (not per organization) and decides which workspace they land in after signing in.
| Account type | Stored slug | Who it is for | Primary workspace |
|---|---|---|---|
| Super Admin | super_admin | Cascadia platform operators | /admin |
| Employee | team | Cascadia staff | /admin (gated by staff role) |
| Contractor | contractor | External contractors working with Cascadia | /admin (gated by staff role) |
| Client | client | Customers managing their own company | /dashboard |
| Scan lead | scan_lead | Free-scan funnel sign-ups | Limited dashboard |
Notes:
- Super Admin always has full platform access and bypasses every permission check. A user is Super Admin if their account type is
super_adminor their email is listed inADMIN_EMAILS. - Employee and Contractor are both "staff," but they see nothing in the admin workspace until they are given one or more staff roles (see Layer 2). The two account types are treated the same for permission purposes; the label just records employment relationship.
- Client users get the full client dashboard for the organizations they belong to. What they can do there depends on Layer 3.
- Scan lead is a lightweight account created through the free accessibility scan funnel. It has limited dashboard access and is meant to convert into a full client later.
Historic rows may store
adminas the account type; that value is normalized tosuper_adminon read. Never write new rows withadmin.
Layer 2: Cascadia staff roles
Employees and Contractors do not automatically see the admin workspace. Access is granted by assigning staff roles (also called staff tags). Each role maps to a set of admin permissions, and a staff member's effective permissions are the union of all their roles.
Super Admins skip this entirely: they receive every permission regardless of roles.
Staff roles
| Role | Slug | Grants access to |
|---|---|---|
| Sales | sales | Clients (read), Users (read), Team (read) |
| Developer | developer | Projects (read/manage), Accessibility (read/manage), Documents (read) |
| Design | design | Projects (read), Clients (read), Documents (read) |
| UX/UI | ux_ui | Projects (read), Accessibility (read), Documents (read) |
| Account Manager | account_manager | Clients (read), Users (read), Documents (read/manage), Projects (read) |
| Project Manager | project_manager | Projects (read/manage), Documents (read/manage), Clients (read) |
| Accounting | accounting | Billing (read/manage), Documents (read) |
| IT | it | Settings (read), Users (read), Team (read) |
| Marketing | marketing | Analytics (read), Accessibility (read), Clients (read), Documents (read) |
Every role includes admin.access (the ability to open the admin workspace at all). A staff member with no roles cannot enter /admin.
How permissions gate the admin workspace
Admin navigation and routes are gated by permission keys. For example, opening /admin/billing requires admin.billing.read, and /admin/projects requires admin.projects.read. A staff member only sees the nav items their roles unlock.
Permission keys follow a admin.<area>.<action> shape, where action is usually read or manage (manage implies write). The full list lives in src/lib/staff-permissions.ts (STAFF_PERMISSIONS), and the nav mapping is ADMIN_NAV_ITEM_PERMISSIONS.
Layer 3: Client organization roles
Inside a client company (an "organization"), each member has an organization role. This is separate from their account type: a person is a client account type, and within their company they might be an owner, admin, member, or brand manager.
| Organization role | What it means |
|---|---|
| Owner | Full control of the company, including deleting the organization. |
| Admin | Same day-to-day powers as Owner in this app (manage people, settings, all brands). |
| Member | Participates in the company. Can be company-wide or limited to specific brands. |
| Brand Manager | A brand-limited member who can also invite and remove members for the brands they manage. |
Owner vs Admin
Owner and Admin are intentionally equivalent for everyday work: both can update the organization, manage members and invitations, manage brands, and approve join requests. Both are always company-wide (they see every brand).
The differences are safeguards, not capabilities:
- The UI labels them "Company owner" and "Company admin."
- The organization must keep at least one Owner or Admin; the last Owner cannot be demoted to member or removed unless another admin exists.
- New organizations default the first member to Owner.
Member
A Member participates in the company but cannot manage the team, brands, or company settings. A Member's reach depends on brand access (below): they are either company-wide (see everything) or brand-limited (see only assigned brands).
Billing and revenue remain company-wide only, so brand-limited members never see them.
Brand Manager
A Brand Manager is a Member who has been marked as brand admin on at least one of their assigned brands. It is not a separate stored role; it is a Member with brand-admin rights on one or more brands. This lets a company delegate team management for a brand without granting company-wide control.
A Brand Manager can:
- View only the brands they are assigned to (like any brand-limited member).
- Invite new members to the brands they manage.
- Remove members who belong to the brands they manage.
- Cancel pending member invitations scoped to their brands.
A Brand Manager cannot:
- See or manage brands they are not assigned to.
- Invite or create Owners or Admins.
- Remove or edit Owners or Admins.
- Change organization roles or edit another member's brand scope.
- Access company-wide settings, brands administration, or billing.
Brand access scope
Independent of the organization role, every member has a brand access scope that controls which brand data they can see. This is what enforces "you can only view brands you are assigned to."
| Scope | Who has it | What they see |
|---|---|---|
| Company-wide | Owners and Admins, or any Member with no brand assignments | All brands and org-level data |
| Brand-limited | Members assigned to one or more specific brands | Only their assigned brands' data |
Key rules:
- Owners and Admins are always company-wide and cannot be limited to specific brands.
- A Member with zero brand assignments is treated as company-wide; a Member with one or more brand assignments is brand-limited.
- Brand-limited members are filtered on projects, tasks, documents, websites, contacts, and brand lists to only their assigned brands.
- The brand admin flag on a brand assignment is what turns a brand-limited member into a Brand Manager for that brand.
How brand access is assigned
Brand access is set when inviting a member or editing an existing member:
- Access scope: "Full company" (company-wide) or "Specific brands" (brand-limited).
- Brand picker: which brands the member can access.
- Brand admin: an optional per-brand checkbox that promotes the member to Brand Manager for that brand.
When someone is invited with brand scope, the selection is stored on the invitation and copied to their membership when they accept, so the role activates automatically.
Admins inviting from the admin workspace can also set brand scope: for an existing organization with brands, a member invite can be limited to specific brands rather than the whole company.
Putting it together
A few worked examples:
- A Cascadia developer: account type Employee, staff role Developer. Sees Projects and Accessibility in the admin workspace, but not Billing or Settings.
- A client company owner: account type Client, organization role Owner. Full control of their company and all its brands; can manage team and billing.
- A brand lead at a multi-brand client: account type Client, organization role Member, brand-limited to "Brand A," with brand admin on "Brand A." This is a Brand Manager: they see only Brand A, and can invite or remove Brand A members, but cannot touch owners, admins, or other brands.
- A single-brand client contributor: account type Client, organization role Member, brand-limited with no brand admin. They see their brand's data but cannot manage the team.
Quick reference
| Capability | Super Admin | Staff (by role) | Owner / Admin | Brand Manager | Member |
|---|---|---|---|---|---|
Admin workspace (/admin) | Full | Per staff role | No | No | No |
| Manage own company team | n/a | n/a | Yes | Their brands only | No |
| Invite Owners / Admins | n/a | n/a | Yes | No | No |
| Remove Owners / Admins | n/a | n/a | Yes (with guards) | No | No |
| Edit member roles / brand scope | n/a | n/a | Yes | No | No |
| View all brands | Yes | Per staff role | Yes | No | No |
| View assigned brands only | n/a | n/a | n/a | Yes | Yes (if brand-limited) |
| Company settings and billing | Yes | Per staff role | Yes | No | No |