Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt

Use this file to discover all available pages before exploring further.

Last Updated: 2025-01-25
Status: Active
Comprehensive Guide: For detailed information, see permissions-system-guide.md

Permission Key Format

{module}.{entity}.{action}
Examples:
  • hr.employees.view - View HR employees
  • fa.bills.approve - Approve FA bills
  • rh.residents.create - Create RH residents
  • system.platform.admin - Platform admin access
Categories:
  • view - Read access
  • create - Create new records
  • edit - Modify existing records
  • delete - Remove records
  • approve - Approval workflows
  • admin - Full administrative access

Common Patterns

Component Usage

// Hook for permission checks
import { useHasPermission } from '@/platform/permissions';
const canView = useHasPermission('hr.employees.view');

// Conditional rendering
import { PermissionGate } from '@/platform/permissions';
<PermissionGate permission="hr.employees.edit">
  <EditButton />
</PermissionGate>

// Page-level protection
import { RequirePermission } from '@/platform/permissions';
<RequirePermission permission="hr.employees.view">
  <EmployeesPage />
</RequirePermission>
{
 label: 'Employees',
 path: '/hr/employees',
 permission: 'hr.employees.view', // ✅ Use this
 // minRole: 'staff' // ❌ Don't use (V1 deprecated)
}

RLS Policies

-- ✅ CORRECT: Use SECURITY DEFINER function
CREATE POLICY "users_can_view_employees" ON hr_employees
FOR SELECT
USING (
  pf_has_permission(auth.uid(), organization_id, 'hr.employees.view')
);

-- ❌ WRONG: Direct role check (V1 deprecated)
USING (has_role(auth.uid(), 'staff'));

Role to Permission Mapping

V1 Role (Deprecated)V2 Permission Pattern
platform_adminsystem.platform.admin
org_adminsystem.platform.admin or *.admin
site_admin*.view + *.create + *.edit
staff*.view + *.create
readonly*.view only
finance_adminfa.admin + all FA permissions
finance_stafffa.*.view + fa.*.create
Note: V1 roles are deprecated. Always use V2 permission keys.

Migration Quick Reference

Code Migration Patterns

// ❌ Before (V1)
{ label: 'Employees', path: '/hr/employees', minRole: 'staff' }

// ✅ After (V2)
{ label: 'Employees', path: '/hr/employees', permission: 'hr.employees.view' }

Components

// ❌ Before (V1)
import { useUserRole } from '@/platform/modules/useUserRole';
const { role } = useUserRole();
if (role === 'org_admin') { ... }

// ✅ After (V2)
import { useHasPermission } from '@/platform/permissions';
const canAdmin = useHasPermission('system.platform.admin');
if (canAdmin) { ... }

RLS Policies

-- ❌ Before (V1)
CREATE POLICY "org_admins_can_edit" ON some_table
FOR UPDATE
USING (has_role(auth.uid(), 'org_admin'));

-- ✅ After (V2)
CREATE POLICY "org_admins_can_edit" ON some_table
FOR UPDATE
USING (pf_has_permission(auth.uid(), organization_id, 'module.entity.edit'));

Quick Lookup Tables

Permission Categories

CategoryDescriptionExample
viewRead-only accesshr.employees.view
createCreate new recordshr.employees.create
editModify existing recordshr.employees.edit
deleteRemove recordshr.employees.delete
approveApproval workflowsfa.bills.approve
adminFull administrative accesshr.admin

System Permissions

PermissionDescription
system.platform.adminPlatform-wide administrative access
system.organizations.viewView organizations
system.organizations.createCreate organizations
system.organizations.editEdit organizations

Module Prefixes

PrefixModule
hrHuman Resources (Workforce & HRIS)
faFinance & Accounting
rhRecovery Housing
fwForms & Workflow
fmFacilities Management
grGovernance & Compliance
loLeadership Operating System
pfPlatform Foundation

Anti-Patterns (What NOT to Do)

❌ Hardcode Role Checks

// ❌ WRONG
if (user.role === 'org_admin') { ... }

// ✅ CORRECT
const canAdmin = useHasPermission('system.platform.admin');
if (canAdmin) { ... }

❌ Direct Database Queries

// ❌ WRONG
const { data } = await supabase
  .from('pf_role_permissions')
  .select('*')
  .eq('permission_key', 'hr.employees.view');

// ✅ CORRECT
const canView = useHasPermission('hr.employees.view');

❌ Use V1 Patterns

// ❌ WRONG (V1 deprecated)
import { useUserRole } from '@/platform/modules/useUserRole';
const { role } = useUserRole();
if (hasMinimumRole(role, 'staff')) { ... }

// ✅ CORRECT (V2)
import { useHasPermission } from '@/platform/permissions';
const canView = useHasPermission('hr.employees.view');

❌ Recursive RLS Policies

-- ❌ WRONG (Causes infinite recursion)
CREATE POLICY "document_org_access" ON pf_documents
FOR SELECT USING (
 organization_id IN (
 SELECT organization_id FROM pf_user_role_assignments 
 WHERE user_id = auth.uid() -- This table also has RLS!
 )
);

-- ✅ CORRECT (Use SECURITY DEFINER function with V2 permissions)
CREATE POLICY "document_org_access" ON pf_documents
FOR SELECT USING (
  pf_has_permission(auth.uid(), organization_id, 'pf.documents.view')
);

Common Permission Keys

HR Module

  • hr.employees.view
  • hr.employees.create
  • hr.employees.edit
  • hr.employees.delete
  • hr.ats.view
  • hr.ats.create
  • hr.credentialing.view
  • hr.credentialing.approve

Finance Module

  • fa.accounts.view
  • fa.bills.view
  • fa.bills.create
  • fa.bills.approve
  • fa.transactions.view
  • fa.budgets.view

Recovery Housing Module

  • rh.residents.view
  • rh.residents.create
  • rh.residents.edit
  • rh.beds.view
  • rh.census.view

Forms & Workflow Module

  • fw.forms.view
  • fw.forms.create
  • fw.workflows.view
  • fw.workflows.create
  • fw.workflows.edit
For complete list: See Module Permissions Matrix

Database Tables

TablePurposeStatus
pf_user_role_assignmentsUser-to-role assignments✅ Active
pf_rolesRole definitions (custom + system)✅ Active
pf_role_permissionsPermission-to-role mappings✅ Active
pf_permissionsPermission definitions✅ Active
pf_user_rolesLegacy V1 table🗑️ Dropped (migrated to pf_user_role_assignments)

References


Last Updated: 2025-01-25
Status: Active Quick Reference