> ## Documentation Index
> Fetch the complete documentation index at: https://docs.charle.agency/llms.txt
> Use this file to discover all available pages before exploring further.

# Permissions

> Role-based access control in CharleOS

CharleOS uses a flexible permission system based on **access levels** and **work types**. All permission logic is centralized in `lib/permissions.ts`.

## Permission Model

### Two-Tier System

CharleOS combines two concepts for access control:

<CardGroup cols={2}>
  <Card title="Access Level" icon="shield">
    System-wide permission tier

    * **Admin**: Full access (Luke)
    * **Manager**: Management features (Simon, Andre, Ben, Nic)
    * **Staff**: Standard access (everyone else)
  </Card>

  <Card title="Work Type" icon="briefcase">
    Role-based feature access

    * **development/design/qa**: IC features
    * **pm**: Project management features
    * **csm**: Client success features
    * **sdr**: Limited features
  </Card>
</CardGroup>

### Combined Logic

The permission system uses **both** factors:

```typescript theme={null}
// Example: Can view manager dashboard?
function canViewManagerDashboard(user) {
  return user.accessLevel === "admin" || user.accessLevel === "manager";
}

// Example: Can view IC dashboard?
function canViewICDashboard(user) {
  const isIC = ["development", "design", "qa"].includes(user.workType);
  return isIC && user.accessLevel === "staff";
}
```

**Result:** A developer with `manager` access level sees the Manager Dashboard, not the IC Dashboard.

## Permission Functions

All permission checks are in `lib/permissions.ts`:

### Access Level Checks

```typescript theme={null}
import { isAdmin, isAdminOrManager, hasManagerAccess } from "@/lib/permissions";

// Check if user is admin
if (isAdmin(user)) {
  // Show admin-only features
}

// Check if user is admin or manager
if (isAdminOrManager(user)) {
  // Show management features
}

// Alias for isAdminOrManager
if (hasManagerAccess(user)) {
  // Show management features
}
```

### Work Type Checks

```typescript theme={null}
import { isIC, isPM, isCSM } from "@/lib/permissions";

// Check if user is an Individual Contributor (dev/design/qa)
if (isIC(user)) {
  // Show IC-specific features
}

// Check if user is a PM
if (isPM(user)) {
  // Show PM features
}

// Check if user is a CSM
if (isCSM(user)) {
  // Show CSM features
}
```

## Dashboard Access

### Dashboard Types

CharleOS has 5 dashboard types based on role:

| Dashboard               | Who Sees It                           | Permission Check                |
| ----------------------- | ------------------------------------- | ------------------------------- |
| **Manager Dashboard**   | Admin/Manager access level            | `canViewManagerDashboard()`     |
| **PM Dashboard**        | PMs (staff level)                     | `canViewPMDashboard()`          |
| **CSM Dashboard**       | CSMs (staff level)                    | `canViewCSMDashboard()`         |
| **IC Dashboard**        | Developers/Designers/QA (staff level) | `canViewICDashboard()`          |
| **Executive Dashboard** | Users with `hasExecutiveAccess` flag  | `canViewCommercialsDashboard()` |

**Code:**

```typescript theme={null}
import {
  canViewManagerDashboard,
  canViewPMDashboard,
  canViewCSMDashboard,
  canViewICDashboard,
} from "@/lib/permissions";

function getDashboardForUser(user) {
  if (canViewManagerDashboard(user)) return "/dashboard/manager";
  if (canViewPMDashboard(user)) return "/dashboard/pm";
  if (canViewCSMDashboard(user)) return "/dashboard/csm";
  if (canViewICDashboard(user)) return "/dashboard/ic";
  return "/dashboard";  // Fallback
}
```

## Sidebar Visibility

Sidebar items are shown/hidden based on permissions:

```typescript theme={null}
import {
  canViewClients,
  canViewTasks,
  canViewSchedule,
  canViewMyTasks,
  canViewMySchedule,
  canViewCapacity,
  canViewReports,
  canViewAdmin,
} from "@/lib/permissions";

// Example: Sidebar navigation
const sidebarItems = [
  {
    label: "My Tasks",
    href: "/my-tasks",
    visible: canViewMyTasks(user),  // ICs only
  },
  {
    label: "Clients",
    href: "/clients",
    visible: canViewClients(user),  // Admin/Manager/PM/CSM
  },
  {
    label: "Schedule",
    href: "/schedule",
    visible: canViewSchedule(user),  // Admin/Manager/PM
  },
  {
    label: "Reports",
    href: "/reports",
    visible: canViewReports(user),  // Admin/Manager only
  },
  {
    label: "Admin",
    href: "/admin",
    visible: canViewAdmin(user),  // Admin only
  },
];
```

## Operational Permissions

### Task Management

```typescript theme={null}
import {
  canCreateTasks,
  canEditTasks,
  canDeleteTasks,
  canAssignSubtasks,
} from "@/lib/permissions";

// Can create tasks? (Admin/Manager/CSM/PM)
if (canCreateTasks(user)) {
  return <CreateTaskButton />;
}

// Can edit tasks? (Admin/Manager/PM/CSM - edits task-level fields)
// Allows editing: title, description, estimatedTime, clientId, pmId
// Does NOT allow: creating/deleting tasks, assigning subtasks
// Note: ICs (developers, designers, QA) cannot edit task-level fields
if (canEditTasks(user)) {
  return <EditTaskButton />;
}

// Can delete tasks? (Admin/Manager only)
if (canDeleteTasks(user)) {
  return <DeleteTaskButton />;
}

// Can assign subtasks? (Admin/Manager/PM)
if (canAssignSubtasks(user)) {
  return <AssignSubtaskButton />;
}
```

### Quote Management

```typescript theme={null}
import {
  canCreateQuotes,
  canDeleteQuotes,
  canEditQuote,
  canApproveQuote,
  canManageQuotes,
} from "@/lib/permissions";

// Can create quotes? (Admin/Manager/CSM)
if (canCreateQuotes(user)) {
  return <CreateQuoteButton />;
}

// Can delete quotes? (Admin/Manager/CSM)
if (canDeleteQuotes(user)) {
  return <DeleteQuoteButton />;
}

// Can edit quote details? (Admin/Manager only)
if (canEditQuote(user)) {
  return <EditQuoteDetailsForm />;
}

// Can approve quotes? (Admin/Manager/CSM)
if (canApproveQuote(user)) {
  return <ApproveQuoteButton />;
}
```

### Client Management

```typescript theme={null}
import {
  canEditClients,
  canEditClientSchedule,
  canManageClientUsers,
} from "@/lib/permissions";

// Can edit client details? (Admin/Manager only)
if (canEditClients(user)) {
  return <EditClientForm />;
}

// Can edit client schedule/blocks? (Admin/Manager/PM/CSM)
if (canEditClientSchedule(user)) {
  return <ClientScheduleEditor />;
}

// Can manage client portal users? (Admin/Manager/CSM)
if (canManageClientUsers(user)) {
  return <ClientUserManagement />;
}
```

### Project Management

```typescript theme={null}
import {
  canCreateProjects,
  canEditProjectBudget,
  canManageProjectTasks,
  canAddProjectPhases,
} from "@/lib/permissions";

// Can create projects? (Admin/Manager only)
if (canCreateProjects(user)) {
  return <CreateProjectButton />;
}

// Can edit project budget? (Admin/Manager only)
if (canEditProjectBudget(user)) {
  return <EditBudgetForm />;
}

// Can manage project tasks? (Admin/Manager/PM)
if (canManageProjectTasks(user)) {
  return <ProjectTaskManager />;
}

// Can add phases? (Admin/Manager/PM)
if (canAddProjectPhases(user)) {
  return <AddPhaseButton />;
}
```

## Implementation Patterns

### Protected Server Component

```typescript theme={null}
// app/(dashboard)/admin/page.tsx
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import { redirect } from "next/navigation";
import { canViewAdmin } from "@/lib/permissions";

export default async function AdminPage() {
  const { data: session } = await auth.api.getSession({
    headers: headers(),
  });

  if (!session) {
    redirect("/auth");
  }

  // Check permission
  if (!canViewAdmin(session.user)) {
    redirect("/dashboard");  // Redirect to safe page
  }

  return <AdminPanel />;
}
```

### Protected API Route

```typescript theme={null}
// app/api/internal/users/route.ts
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import { canViewAdmin } from "@/lib/permissions";

export async function GET(req: Request) {
  const { data: session } = await auth.api.getSession({
    headers: headers(),
  });

  if (!session) {
    return Response.json({ error: "Unauthorized" }, { status: 401 });
  }

  if (!canViewAdmin(session.user)) {
    return Response.json({ error: "Forbidden" }, { status: 403 });
  }

  // Fetch admin data...
}
```

### Conditional UI Rendering

```typescript theme={null}
"use client";

import { useSession } from "@/lib/auth-client";
import { canCreateTasks } from "@/lib/permissions";

export function TaskActions() {
  const { data: session } = useSession();

  if (!session) return null;

  return (
    <div>
      {canCreateTasks(session.user) && (
        <CreateTaskButton />
      )}
      
      {canEditTasks(session.user) && (
        <EditTaskButton />
      )}
      
      {canDeleteTasks(session.user) && (
        <DeleteTaskButton />
      )}
    </div>
  );
}
```

## Complete Permission Reference

### Dashboard Access

| Function                      | Who Gets Access                      |
| ----------------------------- | ------------------------------------ |
| `canViewManagerDashboard`     | Admin, Manager                       |
| `canViewPMDashboard`          | PM (staff level)                     |
| `canViewCSMDashboard`         | CSM (staff level)                    |
| `canViewICDashboard`          | Dev/Design/QA (staff level)          |
| `canViewCommercialsDashboard` | Users with `hasExecutiveAccess` flag |

### Sidebar Visibility

| Function                | Who Gets Access              |
| ----------------------- | ---------------------------- |
| `canViewMyTasks`        | ICs (dev/design/qa)          |
| `canViewMySchedule`     | ICs (dev/design/qa)          |
| `canViewMyTimeTracking` | ICs (dev/design/qa)          |
| `canViewClients`        | Admin, Manager, PM, CSM      |
| `canViewTasks`          | Admin, Manager, PM, CSM, ICs |
| `canViewSchedule`       | Admin, Manager, PM           |
| `canViewQuotes`         | Admin, Manager, PM, CSM, ICs |
| `canViewProjects`       | Admin, Manager, PM, ICs      |
| `canViewTimeTracking`   | Admin, Manager               |
| `canViewCapacity`       | Admin, Manager               |
| `canViewAnnualLeave`    | Admin, Manager               |
| `canViewReports`        | Admin, Manager               |
| `canViewAdmin`          | Admin only                   |
| `canViewKnowledgeBase`  | Everyone                     |
| `canViewRag`            | Everyone                     |
| `canViewHelpDesk`       | Admin, Manager, CSM          |

### Operational Permissions

| Function                | Who Gets Access         | What It Allows                                              |
| ----------------------- | ----------------------- | ----------------------------------------------------------- |
| `canCreateTasks`        | Admin, Manager, CSM, PM | Create new tasks                                            |
| `canEditTasks`          | Admin, Manager, PM, CSM | Edit task title, description, estimatedTime, clientId, pmId |
| `canDeleteTasks`        | Admin, Manager          | Delete tasks                                                |
| `canAssignSubtasks`     | Admin, Manager, PM      |                                                             |
| `canCreateQuotes`       | Admin, Manager, CSM     |                                                             |
| `canDeleteQuotes`       | Admin, Manager, CSM     |                                                             |
| `canEditQuote`          | Admin, Manager          |                                                             |
| `canApproveQuote`       | Admin, Manager, CSM     |                                                             |
| `canManageQuotes`       | Admin, Manager, PM, CSM |                                                             |
| `canEditClients`        | Admin, Manager          |                                                             |
| `canEditClientSchedule` | Admin, Manager, PM, CSM |                                                             |
| `canManageClientUsers`  | Admin, Manager, CSM     |                                                             |
| `canCreateProjects`     | Admin, Manager          |                                                             |
| `canEditProjectBudget`  | Admin, Manager          |                                                             |
| `canManageProjectTasks` | Admin, Manager, PM      |                                                             |
| `canAddProjectPhases`   | Admin, Manager, PM      |                                                             |
| `canEditRag`            | Admin, Manager          |                                                             |
| `canViewActivityLog`    | Admin, Manager          |                                                             |

## Adding New Permissions

<Steps>
  <Step title="Add Permission Function">
    Add to `lib/permissions.ts`:

    ```typescript theme={null}
    export function canExportData(user: UserPermissionContext): boolean {
      return isAdmin(user);
    }
    ```
  </Step>

  <Step title="Use in Components">
    ```typescript theme={null}
    import { canExportData } from "@/lib/permissions";

    if (canExportData(user)) {
      return <ExportButton />;
    }
    ```
  </Step>

  <Step title="Protect Routes">
    ```typescript theme={null}
    if (!canExportData(session.user)) {
      return Response.json({ error: "Forbidden" }, { status: 403 });
    }
    ```
  </Step>
</Steps>

## Best Practices

<AccordionGroup>
  <Accordion title="Always Check Permissions Server-Side" icon="server">
    Client-side checks are for UI only. Always verify on the server:

    ```typescript theme={null}
    // ✅ Good: Check on server
    export async function GET(req: Request) {
      const { data: session } = await auth.api.getSession({ headers: headers() });
      if (!canViewAdmin(session.user)) {
        return Response.json({ error: "Forbidden" }, { status: 403 });
      }
      // ... return data
    }

    // ❌ Bad: Only checking client-side
    "use client";
    function AdminPanel() {
      if (!canViewAdmin(user)) return null;
      // ... fetch admin data (anyone can call the API!)
    }
    ```
  </Accordion>

  <Accordion title="Use Specific Permission Functions" icon="bullseye">
    Don't check `accessLevel` or `workType` directly:

    ```typescript theme={null}
    // ✅ Good: Use specific function
    if (canCreateTasks(user)) { ... }

    // ❌ Bad: Direct check
    if (user.accessLevel === "admin" || user.workType === "csm") { ... }
    ```
  </Accordion>

  <Accordion title="Redirect, Don't Hide" icon="arrow-right">
    For pages, redirect unauthorized users:

    ```typescript theme={null}
    // ✅ Good: Redirect
    if (!canViewAdmin(user)) {
      redirect("/dashboard");
    }

    // ❌ Bad: Return null (shows blank page)
    if (!canViewAdmin(user)) {
      return null;
    }
    ```
  </Accordion>
</AccordionGroup>

## Related Documentation

<CardGroup cols={2}>
  <Card title="Authentication" icon="shield" href="/developer/auth">
    Auth architecture overview
  </Card>

  <Card title="Better Auth" icon="lock" href="/developer/auth/better-auth">
    Auth configuration details
  </Card>

  <Card title="Sessions" icon="clock" href="/developer/auth/sessions">
    Session management
  </Card>
</CardGroup>
