Roles inside your company

Five roles — admin, sales, project manager, crew leader, worker — each with a defined set of what they can see and change, enforced on the server.

What it is

A permission matrix with roughly thirty named capabilities covering navigation (which sections appear), actions (edit projects, edit estimates, take photos, mark stages, delete, manage users, send messages), granular stage controls (status, dates, details, tasks and notes, photos, issues), and crew scope. Each role is a preset over that matrix, and the server enforces the same rules the UI renders.

Also called: permissions · user roles · who can see what · admin sales PM crew lead worker

See it
Roles inside your company
Area
Platform & Admin
Group
Roles & permissions
System
Multi-Tenancy & Identity
Solves
3 named problems
01permissions.ts defines the Permissions shape and the five role presets.
02The role lives in the user's identity metadata and is read client-side by RoleContext for rendering.
03serverAuth's requireApproved / requireAdmin / requireRole enforce the same boundaries on every API route.
The permissions matrix screen: roles as columns, capability rows with checkmarks. src/components/settings/PermissionPresetsTab.tsx over the presets in src/lib/permissions.ts. Sample data — no customer information appears here.
How it works
  1. 1permissions.ts defines the Permissions shape and the five role presets.
  2. 2The role lives in the user's identity metadata and is read client-side by RoleContext for rendering.
  3. 3serverAuth's requireApproved / requireAdmin / requireRole enforce the same boundaries on every API route.
  4. 4The data proxy applies table-level gates on top: admin-only reads, worker-excluded reads, admin-only writes for configuration tables.
  5. 5Crew scope is defence in depth: when a role can't view all crews the project list is filtered to the user's own crew regardless of UI state.
Why we built it

The default is the story here. roles.ts records that the client used to default an unset role to admin, and what that meant: 'an invitee who accidentally landed on /sign-in (instead of going through the invite-accept handshake) would see every section of the app as if they owned the tenant.' The server had already defaulted to worker, so the visible symptom was a nav full of empty screens. The permission comments also show the matrix being tuned by real complaints rather than theory — project managers were given estimate viewing because 'operators kept hitting my PM can't see what we sold the customer' — and the crew-scope note spells out the defence-in-depth intent: 'even if a UI control leaks through, the project list filter is hardcoded to the user's crew.'

The problem
  • A single 'user' level means everyone in the company sees margins, pay and other crews' work.
  • UI-only permissions are bypassable by calling the API directly.
  • An unset role defaulting high exposes the whole app to anyone who signs in off the happy path.
Sound familiar?
What you get
Field staff see their work without seeing pricing or other crews.
Sales can quote without touching the build schedule.
Every permission the interface hides is also refused by the server.
What's inside

See it on your own jobs

Twenty minutes, your numbers, no slide deck. We’ll build one of your real buildings in front of you and send you the estimate link at the end — yours to keep either way.

or keep browsing features →