Multi-role RBAC

Feature Owner: scorevi (Sean Patrick Caintic)
Module: User Mgmt & Enrollment
Priority: P0
Sprint #12: Fully Implemented & Deployed
Date: 2026-06-29


EXECUTIVE SUMMARY

What is this feature?
Three-layer Role-Based Access Control system governing the entire platform: (1) Platform Roles (ADMIN, CREATOR, REVIEWER, LEARNER), (2) Agency Membership Roles (OWNER, CREATOR, REVIEWER), (3) Folder Permissions (view, edit, admin, owner). Central auth engine at lib/auth/authenticate.ts (885 lines) provides all authentication and authorization functions with circuit breaker, in-memory caching, and user sync fallback.

Why does it matter?
Without RBAC, every user would have the same permissions — a security and usability nightmare. RBAC ensures admins manage the platform, creators build content, reviewers QA content, and learners consume it. Agency ownership enables B2B self-service.

What's the MVP scope?
Fully deployed. 5 platform roles. 10 auth functions (authenticateUser, authenticateUserWithRole, authenticateRole, authenticateAnyRole, authenticateUserWithAgency, authenticateRoleWithAgency, authenticateAgencyAdmin, authenticateAgencyMember, getViewAsStatus, handleAuthError). View As role preview. 8-rule agency invitation validation. Folder-level permissions.


1. USER PAIN POINT & SOLUTION

Current State (Without Feature)

All users have the same access level. No role-based routing, no agency ownership, no content review. Everything is either "logged in" or "not logged in."

Pain Point

Emotional: "Why can learners see the admin panel? This feels insecure."
Functional: No granular access control.
Business Impact: Security vulnerability; impossible to operate as a platform.

Future State (With Feature)

Each user sees exactly the dashboard and features their role permits. Layout guards block unauthorized access. RLS policies enforce data isolation.

Marketing Hook

"Five roles. Three permission layers. Every feature, precisely gated."


2. 4D FRAMEWORK MAPPING

Diagnose

View As feature lets admins diagnose learner issues by previewing their experience.

Design

Folder permissions control who can edit shared content.

Develop

Agency membership controls who can produce content within an agency.

Deliver

Not directly applicable.


3. USER FLOWS

Entry Point

User signs in → role resolved → redirected to role-specific dashboard.

Success Criteria

User sees only their authorized routes. Sensitive actions checked against permission hierarchy.

Main Flow (Happy Path)

  1. User signs in via Clerk

  2. authenticateUser() resolves Clerk ID → internal UUID via app_users

  3. authenticateUserWithRole() fetches platform role from app_users.role

  4. Layout guard (authenticateRole('ADMIN')) verifies role matches route

  5. Agency guard (authenticateAgencyMember()) verifies agency membership if applicable

  6. All API routes call appropriate authenticate*() function

  7. RLS policies enforce data-level access (Supabase-level)

Decision Points

  • IF user role != required → AuthorizationError → redirect or 403.

  • IF DB outage → circuit breaker → 503 + cooldown.

  • IF user not in app_userssyncUserIfNotExists() → auto-create with LEARNER role.


4. INFORMATION ARCHITECTURE

N/A — infrastructure layer.


5. WIREFRAMES

N/A — infrastructure layer.

6. WIREFLOWS

N/A.

7. PROTOTYPE

N/A.


8. BACKEND SCHEMA

Three-Layer Model

Layer 1: Platform Roles (app_users.role)

Role

Access

ADMIN

Full platform control: manage users, agencies, system config

AGENCY

Legacy — functionally disabled (exists in CHECK but not in View As hierarchy)

CREATOR

Content creation, editing, publishing

REVIEWER

Content review QA pipeline

LEARNER

Content consumption (default for new users)

Layer 2: Agency Membership Roles (agency_members.role)

Role

Source

Notes

OWNER

agencies.owner_clerk_id (derived)

Virtual role — not in agency_members table

CREATOR

agency_members.role

Agency content creators

REVIEWER

agency_members.role

Agency reviewers

ADMIN

DEPRECATED Jun 2026

Rows converted to CREATOR; previous_platform_role preserved

Layer 3: Folder Permissions (folder_permissions)

Level

Access

view

Read files in folder

edit

Read + modify files

admin

Invite users, modify permissions

owner

Full control (assigned at creation)


9. API ENDPOINTS

Auth Functions (All in lib/auth/authenticate.ts)

Function

Returns

Use Case

authenticateUser()

string (internal id)

Any authenticated endpoint

authenticateUserWithRole()

{id, role}

Endpoints needing role context

authenticateRole(role)

string (id)

Single-role dashboards

authenticateAnyRole(roles[])

string (id)

Multi-role layouts

authenticateUserWithAgency()

{id, role, agency_id}

Agency-scoped routes

authenticateRoleWithAgency(role)

{id, agency_id}

Agency + platform role

authenticateAgencyAdmin()

{id, agency_id, role:'OWNER'}

Team mgmt, billing

authenticateAgencyMember()

{id, agency_id, role}

Agency dashboard entry

getViewAsStatus()

{actualRole, ...}

Layout re-auth guards

handleAuthError(error)

NextResponse

Standard error → HTTP

View As Hierarchy

ADMIN → AGENCY, CREATOR, REVIEWER, LEARNER
AGENCY → (none — legacy disabled)
CREATOR → REVIEWER, LEARNER
REVIEWER → LEARNER
LEARNER → (none)

Cookie: wyzquests_view_as_role (httpOnly, 4-hour TTL, secure in production).

Role-Based API Routes

GET /api/user/available-roles (all authenticated)
POST /api/user/switch-role (set/clear View As cookie)
GET /api/folder/permissions/[folder_id] (with folder permissions)

10. DATA REQUIREMENTS

Frontend Needs

  • role for sidebar navigation visibility (getNavGroups.ts).

  • isViewingAsOther for View As indicator.

  • Agency membership status for agency features.

Caching Strategy

  • userIdCache (5-min TTL) + roleCache (30-sec TTL) in authenticate.ts.

  • AgencyStatusContext (1-min TTL) for agency membership.


11. PERFORMANCE CONSIDERATIONS

Database Optimization

  • In-memory caches reduce DB lookups for repeated auth checks.

  • Circuit breaker prevents cascading failures during DB outages.

API Response Time

Target: <50ms for cached auth checks. <200ms for uncached.


12. SECURITY & AUTHORIZATION

Who can access this feature?

All authenticated users — each at their authorized level.

Authorization Logic

  • Circuit Breaker: Tracks consecutive DB failures; after 1 failure → 503 for 30s cooldown.

  • View As: Validated against VIEW_AS_HIERARCHY — tampered cookies ignored.

  • RLS: Supabase-level row filtering uses auth.uid() (actual JWT, not View As).

Agency Invitation Validation (8 Rules)

  1. No self-invite

  2. Cannot invite platform ADMINS

  3. Cannot invite AGENCY owners

  4. Cannot invite LEARNERs

  5. Role compatibility check

  6. Single-agency constraint

  7. Active-only (cannot invite suspended users)

  8. Owner-only for admin invites


13. ERROR HANDLING

Error

How Handled

AuthenticationError

401 Unauthorized

AuthorizationError

403 Forbidden

ServiceUnavailableError

503 Service Unavailable (circuit breaker)

Invalid View As cookie

Ignored, console.warn logged


14. TESTING CHECKLIST

Happy Path
□ ADMIN accesses admin routes
□ CREATOR accesses creator routes, blocked from admin
□ LEARNER blocked from creator/admin/agency/reviewer
□ View As works within hierarchy

Edge Cases
□ Circuit breaker activates on DB failure
□ Tampered View As cookie → ignored
□ User without app_users row → auto-created
□ AGENCY platform role → functionally disabled


15. OPEN QUESTIONS

For Backend:

  • Should we remove the AGENCY platform role entirely from the CHECK constraint? It's been functionally disabled but still exists in the schema.


16. OUT OF SCOPE (v1.1+)

  • Dynamic per-agency role customization.

  • Role expiration / temporary role grants.

  • Multi-agency membership.


17. SUCCESS METRICS

  • 0 unauthorized access incidents — achieved via layout guards + RLS.

  • Circuit breaker uptime >99.9%.

  • Auth check performance <50ms for cached lookups.


18. DEPENDENCIES

This feature depends on:

  • [0.1] Secure Login — Clerk integration.

  • app_users, agencies, agency_members, folder_permissions tables.

These features depend on this:

  • Every feature with a protected route or API endpoint.

  • [0.1.1] User Role Switching — View As cookie.

  • [0.5] Sensitive Action Re-Auth — re-auth tokens.

  • [5.1]/[5.2]/[5.4] — Dashboard layouts.

  • [11.1]/[11.3] — Folder permissions.


19. TIMELINE & OWNERSHIP

Sprint #12: Already deployed.
Backend: scorevi
Frontend: scorevi
QA: N/A
Estimated Completion: Complete.


Document Version

1.0 - Initial version - 2026-06-29 08:22 UTC

1.1 - Added Document Version section and update author to have full name - 2026-06-29 08:47 UTC


Was this article helpful?