> ## 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.

# Deprecation Plan: pf_user_roles Table

> The pf_user_roles table is being deprecated in favor of the new Permissions System V2, which uses: - pf_user_role_assignments - User role assignments with site…

**Version:** 2.0.0\
**Created:** 2025-12-12\
**Last Updated:** 2026-01-26\
**Status:** Phase 2 (Hard Deprecation) - COMPLETE\
**Target Removal:** Q2 2026\
**Related Spec:** PF-30 (Permissions System V2)

***

## Overview

The `pf_user_roles` table is being deprecated in favor of the new Permissions System V2, which uses:

* `pf_user_role_assignments` - User role assignments with site scoping
* `pf_role_permissions` - Permission mappings for system and custom roles
* `pf_custom_roles` - Organization-defined custom roles
* `pf_module_permissions` - Granular permission definitions

***

## Deprecation Timeline

### Phase 1: Soft Deprecation (COMPLETE)

**Duration:** 2025-12-12 - 2025-12-23

| Item                                                    | Status         |
| ------------------------------------------------------- | -------------- |
| New system (`pf_user_role_assignments`) active          | ✅              |
| Data migrated from `pf_user_roles`                      | ✅              |
| Feature flag (`permissions_v2_enabled`) controls system | ✅ (Historical) |
| `pf_user_roles` still exists (read-only for fallback)   | ✅              |
| Code uses `hasMinimumRole()` with V1 fallback           | ✅ (Removed)    |

### Phase 2: Hard Deprecation (COMPLETE)

**Duration:** 2025-12-23 - 2026-01-26

| Item                                     | Status |
| ---------------------------------------- | ------ |
| `pf_user_roles` becomes read-only        | ✅      |
| `hasMinimumRole()` removed from codebase | ✅      |
| All code uses V2 permission system       | ✅      |
| All organizations migrated to V2         | ✅      |
| Feature flag logic removed               | ✅      |

**Completed Actions:**

* ✅ Removed all `minRole` checks from code
* ✅ Removed `hasMinimumRole()` usage from components
* ✅ All organizations have V2 enabled (mandatory)
* ✅ Removed `usePermissionsV2Enabled` hook
* ✅ Removed `isV2Enabled()` from PermissionService
* ✅ Updated documentation to reflect V2 is mandatory

### Phase 3: Removal

**Duration:** After 180 days (Q3 2026)

| Item                                               | Status |
| -------------------------------------------------- | ------ |
| `pf_user_roles` table archived                     | 🗑️    |
| `hasMinimumRole()` function removed                | 🗑️    |
| V1 fallback logic removed from `PermissionService` | 🗑️    |
| `minRole` property removed from navigation items   | 🗑️    |

**Action Required:**

* Final migration verification
* Archive `pf_user_roles` to `pf_user_roles_archive`
* Remove `minRole` from all navigation item definitions
* Clean up V1 compatibility code from codebase

***

## Tables Affected

| Table                      | Current State | Phase 1    | Phase 2   | Phase 3  |
| -------------------------- | ------------- | ---------- | --------- | -------- |
| `pf_user_roles`            | Active        | Deprecated | Read-only | Archived |
| `pf_user_role_assignments` | Active        | Active     | Active    | Active   |
| `pf_role_permissions`      | Active        | Active     | Active    | Active   |
| `pf_custom_roles`          | Active        | Active     | Active    | Active   |
| `pf_module_permissions`    | Active        | Active     | Active    | Active   |

***

## Migration Checklist

### For Developers

#### Code Changes

* [ ] Replace `user.role === 'admin'` with `useHasPermission('module.entity.admin')`
* [ ] Replace `hasMinimumRole(role, 'staff')` with `hasPermission('module.entity.view')`
* [ ] Add `permission` property to all navigation items
* [ ] Update RLS policies to use `pf_has_permission()` helper
* [ ] Remove direct references to `pf_user_roles` table

#### Navigation Items

* [ ] Add `permission` property to module nav items
* [ ] Add `permission` property to nav groups
* [ ] Keep `minRole` as fallback (Phase 1 only)
* [ ] Test navigation filtering with V2 enabled

#### Testing

* [ ] Update unit tests to mock V2 permission hooks
* [ ] Add RLS tests for permission-based policies
* [ ] Test navigation visibility for different roles
* [ ] Verify custom roles work correctly

### For Org Admins

* [ ] Enable V2 in Organization Settings → Security → Permissions
* [ ] Verify all users can access expected features
* [ ] Create custom roles if specialized access needed
* [ ] Assign permissions to custom roles
* [ ] Review audit logs for permission denials

***

## Rollback Procedure

### Quick Rollback (Disable V2) - NO LONGER SUPPORTED

**Note:** V2 is now mandatory. Rollback to V1 is not supported. The `permissions_v2_enabled` column exists for historical purposes only and is not checked by the application code.

If critical issues arise, contact the Platform Foundation team for assistance.

### Full Rollback (Admin Only)

If critical issues require complete rollback:

```sql theme={null}
-- Run the rollback function
SELECT pf_rollback_v2_migration();
```

This will:

* Delete all `pf_user_role_assignments` records tagged with `_migrated_from_v1`
* Delete all system role permission mappings from `pf_role_permissions`
* **NOT** delete records from the original `pf_user_roles` table (preserved for safety)

### Re-Migrate After Rollback

If you need to re-migrate after a rollback:

```sql theme={null}
-- Re-run the migration
SELECT pf_migrate_to_v2_permissions();

-- Verify the migration
SELECT pf_verify_v2_migration();
```

***

## Compatibility Matrix

| Feature              | V1 (minRole)   | V2 (permission)      | Migration Path      |
| -------------------- | -------------- | -------------------- | ------------------- |
| Role hierarchy       | ✅              | ✅ (via system roles) | Automatic           |
| Site-scoped access   | ❌              | ✅                    | New feature         |
| Custom roles         | ❌              | ✅                    | New feature         |
| Granular permissions | ❌              | ✅                    | New feature         |
| Navigation filtering | ✅ (minRole)    | ✅ (permission)       | Add permission prop |
| RLS policies         | ✅ (role-based) | ✅ (permission-based) | Update policies     |

***

## Code Examples

### Before (V1)

```typescript theme={null}
// Component
if (hasMinimumRole(userRole, 'org_admin')) {
  return <AdminPanel />;
}

// Navigation
{
  label: 'Settings',
  path: '/settings',
  minRole: 'org_admin',
}

// RLS Policy
CREATE POLICY "admin_access" ON some_table
USING (pf_get_user_role(auth.uid()) IN ('org_admin', 'platform_admin'));
```

### After (V2)

```typescript theme={null}
// Component
import { useHasPermission, PermissionGate } from '@/platform/permissions';

const hasAdminAccess = useHasPermission('module.admin');
if (hasAdminAccess) {
  return <AdminPanel />;
}

// Or using PermissionGate
<PermissionGate permission="module.admin">
  <AdminPanel />
</PermissionGate>

// Navigation
{
  label: 'Settings',
  path: '/settings',
  permission: 'system.settings.admin',
  minRole: 'org_admin', // Fallback for V1 orgs
}

// RLS Policy
CREATE POLICY "admin_access" ON some_table
USING (pf_has_permission(auth.uid(), organization_id, 'module.admin'));
```

***

## Monitoring

### Key Metrics to Track

During the deprecation period, monitor:

1. **Permission check latency** - V2 should be \<50ms
2. **V1 fallback rate** - Should decrease over time
3. **Permission denial rate** - Watch for unexpected increases
4. **Custom role adoption** - Measure V2 feature usage

### Telemetry Events

The PermissionService logs the following events:

| Event                          | Description                  |
| ------------------------------ | ---------------------------- |
| `permission.check.v2`          | V2 permission check executed |
| `permission.check.v1_fallback` | Fell back to V1 role check   |
| `permission.denied`            | Permission was denied        |
| `permission.cache.hit`         | Cache hit (performance)      |

***

## Contact

For questions about this deprecation:

* **Spec Owner:** Platform Foundation Team
* **Documentation:** See `specs/pf/permissions-v2-migration.md`
* **Rollout Guide:** See `specs/pf/permissions-v2-rollout.md`

***

## Changelog

| Date       | Version | Change                                                                             |
| ---------- | ------- | ---------------------------------------------------------------------------------- |
| 2025-12-12 | 1.0.0   | Initial deprecation plan created                                                   |
| 2026-01-26 | 2.0.0   | Phase 2 (Hard Deprecation) marked complete - V2 is mandatory, feature flag removed |
