Skip to main content

Staff Roles

This guide covers role management in Shyfts, including role hierarchy, permissions, role assignment, and customisation options.


Understanding Roles

Role Purpose

Staff roles in Shyfts serve multiple purposes:

  1. Identification - Categorise staff by their function
  2. Permissions - Control access to system features
  3. Scheduling - Filter staff by role for scheduling
  4. Visual Identity - Colour-coded role indicators throughout the system
  5. Reporting - Generate role-based analytics

Role Database Structure

// Source: src/types/database.types.ts:2671-2716
staff_roles: {
Row: {
id: string
company_id: string
name: string
display_name: string | null
description: string | null
color: string | null
hierarchy_level: number | null
can_manage_schedules: boolean | null
can_manage_staff: boolean | null
can_view_reports: boolean | null
permissions: Json | null
created_at: string | null
updated_at: string | null
}
}

Role Hierarchy

Hierarchy Levels

Shyfts uses a numeric hierarchy system to determine role authority:

LevelRole TypeDescription
1ManagerFull company management access
2Senior StaffLimited management capabilities
3+Regular StaffStandard staff permissions

Hierarchy in Practice

// Source: src/app/api/companies/[companyId]/staff/route.ts:94-111
if (roleId) {
const { data: role, error: roleError } = await supabase
.from('staff_roles')
.select('id, hierarchy_level')
.eq('id', roleId)
.eq('company_id', params.companyId)
.single()

if (roleError || !role) {
return ApiResponses.badRequest('Role does not belong to this company')
}

// hierarchy_level = 1 -> COMPANY_MANAGER
// hierarchy_level >= 2 -> STAFF
hierarchyLevel = role.hierarchy_level ?? 2
}

System Role Assignment

Hierarchy LevelSystem RoleCapabilities
1COMPANY_MANAGERFull dashboard access, staff management
2+STAFFStaff portal access only

Role Properties

Core Properties

PropertyTypeDescription
nameStringInternal reference name
display_nameStringUser-facing label
descriptionTextRole purpose/responsibilities
colorHexVisual identifier (e.g., #FFB5B0)
hierarchy_levelNumberAuthority level (1 = highest)

Permission Flags

PermissionTypeControls
can_manage_schedulesBooleanCreate/edit shifts
can_manage_staffBooleanAdd/edit staff members
can_view_reportsBooleanAccess reporting features

Extended Permissions

The permissions JSON field allows granular control:

{
"scheduling": {
"create": true,
"edit": true,
"delete": false
},
"staff": {
"view": true,
"create": false,
"edit": false
},
"reports": {
"view": true,
"export": false
},
"leave": {
"approve": false,
"request": true
}
}

Industry Templates

Default Roles by Industry

Roles are pre-configured based on your company's industry template:

GP Practice

RoleColourHierarchy
Practice Manager#4F46E51
Senior GP#10B9812
GP#22C55E3
Nurse#EF44443
Receptionist#F59E0B3
Administrator#6B72803

Dental Practice

RoleColourHierarchy
Practice Manager#4F46E51
Principal Dentist#10B9812
Associate Dentist#22C55E3
Dental Hygienist#3B82F63
Dental Nurse#EF44443
Receptionist#F59E0B3

Restaurant

RoleColourHierarchy
General Manager#4F46E51
Head Chef#EF44442
Sous Chef#F973163
Line Cook#FBBF243
Server#22C55E3
Host#3B82F63

Office

RoleColourHierarchy
Office Manager#4F46E51
Team Lead#10B9812
Senior Staff#22C55E3
Staff#6B72803
Administrator#F59E0B3

Assigning Roles

During Staff Creation

When adding a new staff member, select their role from the dropdown:

// Source: src/components/staff/EnhancedStaffForm.tsx:573-596
<div className="form-field">
<label className="form-label required">Role</label>
<select
{...register('role_id')}
className="form-select"
disabled={loadingRoles}
>
<option value="" disabled>
{loadingRoles ? 'Loading roles...' : 'Select a role...'}
</option>
{roles.map((role) => (
<option key={role.id} value={role.id}>
{role.display_name || role.name}
</option>
))}
</select>
{errors.role_id && (
<p className="text-sm text-red-400 mt-1">{errors.role_id.message}</p>
)}
</div>

Role Loading

Roles are loaded for the specific company:

// Source: src/components/staff/EnhancedStaffForm.tsx:140-152
async function loadRoles() {
if (!companyId) return

try {
setLoadingRoles(true)
const response = await fetch(`/api/companies/${companyId}/roles`)
const data = await response.json()
setRoles(data.roles || [])
} catch (error) {
console.error('Error loading roles:', error)
} finally {
setLoadingRoles(false)
}
}

Changing Staff Role

To change a staff member's role:

  1. Navigate to Staff Management
  2. Click on the staff member
  3. Click Edit Profile
  4. Select new role from the dropdown
  5. Click Save Changes
Role Change Impact

Changing a staff member's role may affect:

  • Their system access permissions
  • Their visibility in scheduling filters
  • Their reporting categorisation
  • Calendar colour display

Role Colours

Purpose

Role colours provide visual identification throughout Shyfts:

  • Staff List - Role badge colouring
  • Calendar - Shift block colours
  • Reports - Chart segment colours
  • Staff Cards - Role indicator dots

Colour Display

// Source: src/components/staff/StaffList.tsx:196-200
<span
className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100"
style={{ color: member.statusColor }}>
{member.statusDisplay}
</span>

Shift Block Colouring

// Source: src/components/calendar/RoomTimeGridCalendar.tsx:312-315
style={{
left: `${left}px`,
width: `${width}px`,
backgroundColor: shift.staff?.role?.color || '#FFB5B0'
}}

Default Fallback

If no colour is set, shifts display with the coral accent (#FFB5B0).


Security Considerations

Cross-Company Protection

Roles are scoped to individual companies. The system validates that:

  1. Role belongs to company - Prevents cross-company role assignment
  2. Hierarchy is respected - Staff cannot assign roles above their level
  3. Permissions are enforced - Actions checked against role permissions
// Source: src/app/api/companies/[companyId]/staff/route.ts:97-106
const { data: role, error: roleError } = await supabase
.from('staff_roles')
.select('id, hierarchy_level')
.eq('id', roleId)
.eq('company_id', params.companyId)
.single()

if (roleError || !role) {
return ApiResponses.badRequest('Role does not belong to this company')
}

Permission Enforcement

Role-based access is enforced at multiple levels:

LevelProtection
DatabaseRow Level Security (RLS) policies
APIRoute-level role checks
FrontendConditional UI rendering
ContextUser role state management

API Endpoints

List Company Roles

Endpoint: GET /api/companies/[companyId]/roles

Response:

{
"success": true,
"roles": [
{
"id": "uuid",
"name": "nurse",
"display_name": "Nurse",
"description": "Clinical nursing staff",
"color": "#EF4444",
"hierarchy_level": 3,
"can_manage_schedules": false,
"can_manage_staff": false,
"can_view_reports": true
}
]
}

Create Role

Endpoint: POST /api/companies/[companyId]/roles

Request Body:

{
"name": "senior_nurse",
"display_name": "Senior Nurse",
"description": "Senior nursing staff with additional responsibilities",
"color": "#DC2626",
"hierarchy_level": 2,
"can_manage_schedules": true,
"can_manage_staff": false,
"can_view_reports": true
}

Update Role

Endpoint: PUT /api/companies/[companyId]/roles/[roleId]

Request Body:

{
"display_name": "Updated Name",
"color": "#3B82F6",
"can_manage_schedules": true
}

Delete Role

Endpoint: DELETE /api/companies/[companyId]/roles/[roleId]

Deletion Restrictions

A role cannot be deleted if staff members are assigned to it. Reassign staff first.


Best Practices

Role Design

  1. Keep it simple - Don't create too many roles
  2. Clear naming - Use descriptive display names
  3. Distinct colours - Choose contrasting colours for visual clarity
  4. Appropriate hierarchy - Set hierarchy levels that reflect organisational structure

Permission Assignment

  1. Principle of least privilege - Only grant necessary permissions
  2. Separate duties - Different roles for different responsibilities
  3. Regular review - Periodically audit role permissions
  4. Document changes - Track permission modifications

Hierarchy Guidelines

LevelTypical Roles
1Managers, Directors, Practice Owners
2Team Leaders, Senior Staff, Supervisors
3Regular Staff, Associates, Assistants
4Trainees, Temporary Staff, Contractors

Troubleshooting

Role Not Appearing

IssueSolution
Role not in dropdownVerify role belongs to correct company
Role created but missingRefresh the page or re-fetch roles
Deleted role still showingClear browser cache

Permission Issues

IssueSolution
Staff can't access featureCheck role permission flags
Manager missing permissionsVerify hierarchy_level is 1
Inconsistent accessCheck for conflicting RLS policies


Source Files:

  • src/types/database.types.ts - Role type definitions
  • src/components/staff/EnhancedStaffForm.tsx - Role selection UI
  • src/app/api/companies/[companyId]/staff/route.ts - Role validation
  • src/app/api/companies/[companyId]/roles/route.ts - Role management API