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

# Roles

> Define custom roles and manage user access

Modelence provides built-in support for user roles. You can define roles in
`startApp`, assign them to users, and check them on both the server and client.

## Defining Roles

Register the roles your app uses in your `startApp` call:

```typescript theme={null}
import { startApp } from 'modelence/server';

startApp({
  roles: {
    admin: { description: 'Full access to all features' },
    editor: { description: 'Can edit content' },
    viewer: {},
  },
});
```

Each role has an optional `description` that is shown in the Modelence Cloud
dashboard.

<Note>
  Roles defined in `startApp` are synced to Modelence Cloud so you can assign
  them to users directly from the dashboard.
</Note>

## Checking Roles in Handlers

Use `user.requireRole` to throw an error if the user lacks a role, or
`user.hasRole` for manual checking:

```typescript theme={null}
import { Module } from 'modelence/server';
import { AuthError } from 'modelence';

export default new Module('myModule', {
  mutations: {
    adminAction: {
      handler: async (args, { user }) => {
        if (!user) {
          throw new AuthError('Not authenticated');
        }

        // Throws if the user doesn't have the "admin" role
        user.requireRole('admin');

        // Admin-only logic here
      }
    },

    anotherAdminAction: {
      handler: async (args, { user }) => {
        if (!user) {
          throw new AuthError('Not authenticated');
        }

        // Check without throwing for custom error handling
        if (!user.hasRole('admin')) {
          throw new Error('Admin access required');
        }

        // Admin-only logic here
      }
    }
  }
});
```

## Assigning Roles

The recommended way to assign roles is through the Modelence Cloud user
management dashboard. If that is not available, you can update roles
directly via the `dbUsers` collection:

```typescript theme={null}
import { dbUsers, ObjectId } from 'modelence/server';

// Add a role
await dbUsers.updateOne(
  { _id: new ObjectId(userId) },
  { $addToSet: { roles: 'admin' } }
);

// Add multiple roles
await dbUsers.updateOne(
  { _id: new ObjectId(userId) },
  { $addToSet: { roles: { $each: ['editor', 'viewer'] } } }
);

// Remove a role
await dbUsers.updateOne(
  { _id: new ObjectId(userId) },
  { $pull: { roles: 'admin' } }
);
```

## Frontend Usage

Use `useSession` to check roles on the client and conditionally render UI:

```typescript theme={null}
import { useSession } from 'modelence/client';

function AdminPanel() {
  const { user } = useSession();

  if (!user?.hasRole('admin')) {
    return <div>Access denied</div>;
  }

  return <div>Admin content</div>;
}
```

```typescript theme={null}
import { useSession } from 'modelence/client';

function Navigation() {
  const { user } = useSession();

  return (
    <nav>
      <a href="/">Home</a>
      {user?.hasRole('admin') && <a href="/admin">Admin Panel</a>}
      {user?.hasRole('editor') && <a href="/editor">Editor</a>}
    </nav>
  );
}
```

## API Reference

**`startApp` options:**

* `roles` — `Record<string, RoleDefinition>` — role definitions keyed by name

**`RoleDefinition`:**

* `description?: string` — optional human-readable description shown in the Modelence Cloud dashboard

**User methods:**

* `user.roles: string[]` — the roles assigned to the user
* `user.hasRole(role: string): boolean` — check if user has a specific role
* `user.requireRole(role: string): void` — throw error if user doesn't have role
