Home Reference Roles & Permissions

Roles & Permissions

Last updated on Jun 12, 2026

Complete reference for role-based access control (RBAC) in CHRIS.

Role Hierarchy

admin
  └── hr_manager
        └── employee

Higher roles inherit all permissions from lower roles.


Roles Overview

admin

Full system access. Can configure all settings and manage all data.

Typical users: System administrators, IT staff

hr_manager

HR operations access. Can manage employees and approve leave.

Typical users: HR personnel, department heads

employee

Basic access. Can manage own profile and submit requests.

Typical users: All regular employees


Permission Matrix

Profiles (Employee Data)

Action admin hr_manager employee
View own profile
Edit own profile
View all profiles -
Edit any profile -
Create employee -
Delete employee - -
View HR notes -
Edit HR notes -
Masquerade as user - -

Leave Requests

Action admin hr_manager employee team_leader
View own requests
Submit request
Cancel own pending
View all requests - -
View team requests -
Approve/reject any - -
Approve/reject team -
Revoke approved - -

Teams

Action admin hr_manager employee
View all teams
Create team -
Edit team -
Delete team - -
Assign members -

Settings

Action admin hr_manager employee
View company settings - -
Edit company settings - -
Configure SMTP - -
Manage leave types - -
Manage holidays -
View audit logs -
Manage translations - -

Contracts

Action admin hr_manager employee
View own contract
View any contract -
Create contract -
Edit contract -
Delete contract - -

Team Leader Role

Team leaders are employees who lead one or more teams. This is not a separate role but additional permissions.

Identifying Team Leaders

// Check if user is a team leader
const { data: isLeader } = await supabase
  .rpc('is_team_leader', { _user_id: userId });

Team Leader Permissions

In addition to employee permissions:

  • View leave requests from team members
  • Approve/reject team member requests
  • View team calendar and availability

Assignment

Team leaders are assigned via the teams.lead_user_id field:

UPDATE teams
SET lead_user_id = 'user-uuid'
WHERE id = 'team-uuid';

Row Level Security (RLS)

Permissions are enforced at the database level via RLS policies.

Example Policies

Profiles - View own:

CREATE POLICY "Users can view own profile"
ON profiles FOR SELECT
USING (auth.uid() = id);

Profiles - HR can view all:

CREATE POLICY "HR can view all profiles"
ON profiles FOR SELECT
USING (
  EXISTS (
    SELECT 1 FROM user_roles
    WHERE user_id = auth.uid()
    AND role IN ('admin', 'hr_manager')
  )
);

Leave requests - Team leader view:

CREATE POLICY "Team leaders can view team requests"
ON leave_requests FOR SELECT
USING (
  user_id IN (
    SELECT id FROM profiles
    WHERE team_id IN (
      SELECT id FROM teams
      WHERE lead_user_id = auth.uid()
    )
  )
);

Checking Permissions in Code

Using the Auth Hook

import { useAuth } from '@/hooks/useAuth';

function MyComponent() {
  const { isAdmin, isHR, isEmployee, user } = useAuth();

  if (isAdmin) {
    // Show admin UI
  } else if (isHR) {
    // Show HR UI
  } else {
    // Show employee UI
  }
}

Using RPC Functions

// Get user's role
const { data: role } = await supabase
  .rpc('get_user_role', { _user_id: userId });

// Check specific role
const { data: isAdmin } = await supabase
  .rpc('has_role', { _user_id: userId, _role: 'admin' });

Role Assignment

During Employee Creation

Roles are assigned when creating an employee:

await supabase.functions.invoke('create-employee', {
  body: {
    email: 'user@company.com',
    full_name: 'John Doe',
    role: 'hr_manager'  // admin, hr_manager, or employee
  }
});

Changing Roles

Only admins can change roles:

UPDATE user_roles
SET role = 'hr_manager'
WHERE user_id = 'user-uuid';

Best Practices

Principle of Least Privilege

Assign the minimum role needed:

  • Most users should be employee
  • Only HR staff need hr_manager
  • Limit admin to essential personnel

Role Auditing

Track role changes via audit logs:

SELECT * FROM audit_logs
WHERE entity_type = 'user_roles'
ORDER BY created_at DESC;

Testing Permissions

Use masquerade to test as different roles:

  1. Sign in as admin
  2. Masquerade as an employee
  3. Verify they see appropriate data
  4. Exit masquerade