A single permissions map defines what each role can view and do: which nav tabs appear, whether they can edit projects, pipeline cards or estimates, whether they see contracts, invoices and change orders, granular stage controls (status, dates, details, tasks, photos, issue reporting), and admin abilities like deleting, managing users, linking building plans, inviting members and seeing all crews.
Also called: who can see what · user roles · access control · stop the crew seeing prices · permissions
- 1ROLE_PERMISSIONS in lib/permissions.ts is the canonical map; getPermissions(role) returns a copy.
- 2The client uses it to hide or show controls; server routes enforce the real authorisation boundary.
- 3Roles come from the signed-in user's account metadata, written on onboarding for owners and by the invite-accept handler for invitees.
- 4Anyone with no explicit role defaults to worker — the least-privileged role.
The file records two real incidents. Permission overrides used to be stored in localStorage, which 'let any user grant themselves permissions via DevTools' — they were removed and the functions left as documented no-ops. And the client role used to default to admin, so '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 visible effect was Danny's bug — 'I can see Sales Pipeline but it's empty'. The Project Manager row carries its own note: canViewEstimates was originally false 'but operators kept hitting my PM can't see what we sold the customer', so PMs now view estimates while still not being able to edit them.
- Everyone who could sign in saw everything.
- Permission overrides could be self-granted from the browser.
- A user with no role defaulted to full access.
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 →