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