Skip to main content

RBAC & Permissions

NearSync uses a role-based access control (RBAC) system that governs what each user can see and do. Permissions are checked at both the UI layer (navigation gating, component visibility) and the data layer (RLS policies).

System Roles

NearSync defines six system roles in ascending order of access:

RoleDescription
viewerRead-only access to assigned modules
staffStandard operational access - can create and edit records within assigned modules
managerModule-level management - can manage team members' records and approve workflows
adminOrganization-wide administration - can configure settings, manage users, and access all modules
org_ownerFull organization control - includes billing, subscription management, and destructive operations
super_adminPlatform-level access - reserved for NearSync platform operations (managed deployments only)

Permission Architecture

The RBAC system is built on three database tables:

Roles Table

Stores the available roles with metadata:

  • Role identifier (e.g., admin, manager, staff)
  • Display name and description
  • Role hierarchy level (used for determining permission inheritance)

Permissions Table

Defines individual permission keys that map to specific actions:

  • Permission key (e.g., sales.view, finance.invoices.create, people.employees.delete)
  • Module scope (which HQ module the permission belongs to)
  • Description of what the permission controls

Permissions follow a consistent naming pattern: module.feature.action, where actions include view, create, edit, delete, manage, and export.

Role-Permission Mappings

Maps roles to their granted permissions. A single role can have many permissions, and permissions can be shared across roles.

How Permissions Are Checked

Client-Side: Navigation Gating

The navigation system reads the current user's role and permissions to determine which HQ modules, sub-modules, and features are visible. Unauthorized modules are hidden from the sidebar entirely - they are not shown in a disabled state.

The ModuleGuard component wraps protected routes and redirects unauthorized users:

ModuleGuard checks:
1. Is the user authenticated?
2. Does the user's role grant the required permission?
3. Is the module enabled in the system manifest?

If any check fails, the user is redirected rather than shown a forbidden state.

Client-Side: Component-Level Checks

Individual UI elements (buttons, forms, actions) check permissions via the useAuth().checkPermission(key) hook. For example, the "Create Invoice" button is only rendered if the user has the finance.invoices.create permission.

Server-Side: RLS Enforcement

Row-Level Security policies reference the authenticated user's JWT claims to enforce data access at the database level. Even if the UI is manipulated to bypass client-side checks, the database will reject unauthorized queries.

See Row-Level Security for details on server-side enforcement.

Module Gating via System Manifest

Beyond RBAC, module access is also controlled by the system manifest - a per-organization configuration that defines which modules are available based on the subscription tier.

  • Feature flags (60+) provide granular sub-module gating
  • The ModuleGuard component checks both RBAC permissions and manifest flags
  • This dual gating ensures that users cannot access modules their organization has not purchased, regardless of their role

Permission Changes

  • Permission changes are applied via database updates to the role-permission mapping table
  • The application subscribes to realtime updates on permission tables via Supabase Realtime
  • When an admin changes a user's role or modifies role permissions, the affected user's UI updates without requiring a page refresh or re-login

Adding Permissions for New Modules

When new modules are added to NearSync, a database migration defines the new permission keys and assigns default role mappings. This ensures that:

  • Existing roles automatically receive appropriate access to new features
  • The permission hierarchy is maintained
  • No manual permission assignment is required for standard role configurations