# App roles

In our app, you may find two types of roles:

* **Global App Role** - This role is related to the UserEntity and is visible in any team. Roles are connected to users with a @ManyToMany relation. As you understand, you can add multiple roles to the UserRoleEntity and assign as many as you want to a user. Currently, there are only three roles: "User", "Admin" (customer support) and "Super Admin."
* **Team Role** - This role is related to the TeamMembershipEntity and is visible only when you are in a team. A team member can have only one team role, so the role field in the TeamMembershipEntity is an enum that consists of "Viewer," "Manager," and "Owner."

{% hint style="success" %}
You can be an Admin globally but have different roles within teams.
{% endhint %}

### Team role descriptions

<table><thead><tr><th width="337">Action</th><th>Owner</th><th>Manager</th><th>Viewer</th></tr></thead><tbody><tr><td>Assign "Manager" role </td><td>✅</td><td>✅</td><td>❌</td></tr><tr><td>Demote "Manager" to "Viewer"</td><td>✅</td><td>❌</td><td>❌</td></tr><tr><td>Delete, edit, or restore team members</td><td>✅</td><td>❌ (only "Viewer")</td><td>❌</td></tr><tr><td>Invite members to the team</td><td>✅ (all roles)</td><td>✅ ("Viewer" or "Manager")</td><td>❌</td></tr><tr><td>Manage the team's subscription</td><td>✅</td><td>❌</td><td>❌</td></tr><tr><td>Full access to the Businesses page</td><td>✅ (CRUD + comments)</td><td>🔒 (read-only + comments)</td><td>🔒 (read-only)</td></tr><tr><td>Full access to the Leads page</td><td>✅ (CRUD + comments)</td><td>✅ (CRUD + comments)</td><td>🔒 (read-only)</td></tr><tr><td>Full access to the Settings page</td><td>✅</td><td>❌</td><td>❌</td></tr><tr><td>Access to the Dashboard page</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>Delete or transfer ownership of the team</td><td>✅</td><td>❌</td><td>❌</td></tr><tr><td>Ability to leave the team</td><td>✅</td><td>✅</td><td>✅</td></tr></tbody></table>

#### **Owner** The primary role in the team, assigned to the person who creates the team. Each team can have only one Owner. The Owner has the following permissions:

* Grant the "Manager" role to other members or demote them to "Viewer."
* Add, edit, delete, or restore team members who were archived when the subscription ended.
* Full CRUD access on the Businesses page with the ability to leave comments.
* Full CRUD access on the Leads page with the ability to leave comments.
* Full CRUD access on the Settings page (lead statuses).
* Ability to delete the team or leave it while transferring ownership.
* Manage the team's subscription.
* Access to the Dashboard page.

#### **Manager** The secondary role in the team, which can be assigned by another Manager or the team Owner. A team can have multiple Managers. Managers have the following permissions:

* Grant the "Manager" role to "Viewers."
* Delete and edit members with the "Viewer" role.
* Invite members to the team with "Viewer" or "Manager" roles.
* Read-only access on the Businesses page with the ability to leave comments.
* Full CRUD access on the Leads page with the ability to leave comments.
* Ability to leave the team.
* Access to the Dashboard page.

#### **Viewer** The third role in the team, set by default when a Manager or Owner invites a new member. A team can have multiple Viewers. Viewers have the following permissions:

* Read-only access on the Team page.
* Read-only access on the Businesses page.
* Read-only access on the Leads page.
* Access to the Dashboard page.
* Ability to leave the team.

To edit a membership role, we use the `update()` function in `team-membership.service.ts`. This function updates the entire `TeamMembershipEntity`, including the role. In the code, we use a simple `if` statement to update the role.

```typescript
const updateData: any = {};

if (membership.role) {
    updateData.role = membership.role;
}
```

### App roles description

<table><thead><tr><th width="258">Action</th><th width="142">Super Admin</th><th>Admin</th><th width="194">User</th></tr></thead><tbody><tr><td>Access to Users List page</td><td>✅ (full access: delete/edit/restore)</td><td>🔒 (read-only, manage memberships)</td><td>❌</td></tr><tr><td>Manage user roles and memberships</td><td>✅ (all except Owner memberships)</td><td>✅ (manage memberships only)</td><td>❌</td></tr><tr><td>Access to Teams List page</td><td>✅</td><td>✅</td><td>❌</td></tr><tr><td>Impersonation</td><td>✅ (except Super Admins)</td><td>✅ (default users only)</td><td>❌</td></tr><tr><td>Global search by users, businesses, and leads</td><td>✅</td><td>✅</td><td>✅ (only realted to team businesses/leads)</td></tr><tr><td>Delete other users' comments</td><td>✅ (via API)</td><td>❌</td><td>❌</td></tr><tr><td>Manage subscription tiers</td><td>✅</td><td>❌</td><td>❌</td></tr><tr><td>Access to Demo page</td><td>✅</td><td>❌</td><td>❌</td></tr><tr><td>General app functionality (teams, leads, etc.)</td><td>✅</td><td>✅</td><td>✅ (based on team role)</td></tr></tbody></table>

#### Super Admin

The main role in the app is the Super Admin. By default, it is created with the initial seed, and after that, the only way to grant other users this role is manually through the database. Ideally, there should be only one Super Admin. The Super Admin has access to all pages in the app but can also be a viewer on a team, without permission to edit certain businesses or leads. Additionally, the Super Admin has some extra permissions:

* Access to Users List page
* Ability to delete, archive, restore, edit user roles and manage user memberships (archive/restore them but super admin can not archive owners memberships)
* Access to Teams List page
* Impersonation (including other admins, but not super admins)
* Global search by all users, businesses, leads
* Delete other users comments (through API)
* Manage subscription tiers
* Access to Demo page and working with it

#### Admin

The second main role in the app is the Admin (primarily used for customer support). There can be multiple Admins in the app, and only the Super Admin can grant this role. The Admin has access to almost all pages but with limited functionality. The Admin role does not provide any special privileges within a team, as team functionality is based solely on team roles. Additionally, the Admin has some extra permissions:

* Read only access to Users list (but can manage user memberships)
* Access to Teams List page
* Impersonation (including only default users)
* Global search by all users, businesses, leads

#### User

This is an autogenerated role assigned upon registration. The role does not provide any special privileges; it simply allows you to use basic app functionality, such as creating teams and managing businesses, leads, and team members, based on your team role.

To update a user's app roles, we use the `updateUserRoles()` function in `users-admin/users-admin.service.ts`. The function accepts a user ID and new role IDs that should be granted to the user. The function checks if a user with the provided ID exists and if roles with the provided IDs exist. After that, it deletes any roles that were removed from the user and adds any newly granted roles. Full code:

```typescript
async updateUserRoles(userId: number, roleIds: number[]): Promise<any> {
        const foundRoles = await this.roleRepository.find({
            where: { id: In([...roleIds]) },
        });
        if (!foundRoles) {
            throw new Error('Role not found');
        }

        const user = await this.userRepository.findOne({
            where: { id: userId },
            relations: ['userRoles'],
        });
        if (!user) {
            throw new Error('User not found');
        }

        const roleIdsForAdding = roleIds.filter(
            roleId => !user.userRoles.map(userRole => userRole.roleId).includes(roleId)
        );

        const roleIdsForRemoving = user.userRoles
            .map(userRole => userRole.roleId)
            .filter(roleId => !roleIds.includes(roleId));

        for (const roleId of roleIdsForRemoving) {
            const userRoles = new UserRoleEntity();
            userRoles.userId = user.id;
            userRoles.roleId = roleId;
            await this.userRoleRepository.delete(userRoles);
        }

        for (const roleId of roleIdsForAdding) {
            const userRoles = new UserRoleEntity();
            userRoles.userId = user.id;
            userRoles.roleId = roleId;
            await this.userRoleRepository.save(userRoles);
        }
    }
```

### Security

For security checks on both the backend and frontend, we use guards. On the backend, CASL-based guards verify if a user with a specific role has permission to perform an action. On the frontend, we have a custom guard that checks the user’s role from the context and grants access to the selected page or redirects them to the Dashboard page.

#### Backend role guards:

* admin.guard.ts (SuperAdminGuard) - checks if user is Admin or Super Admin
* super-admin.guard.ts (AdminGuard) - checks if user is Super Admin
* member.guard.ts (AbilitiesGuard) - checks if user role in current team has permission to perform action

All membership role permissions are set in `api/src/team-memberships/team-membership-permissions.ts` and are synchronized with `AbilitiesGuard`. For app role permissions, we create a file in the module directory, for example, `api/src/users-admin/users-admin.permissions.ts`.

#### Frontend role guards:

* SuperAdminGuard
* TeamRoleGuard
* AdminGuard

All guards can be found in `ui/src/components/guards`. Example of usage frontend guard:

```javascript
<TeamRoleGuard role={teamRole.MANAGER}>
    <Settings />
</TeamRoleGuard>
```

```javascript
<SuperAdminGuard>
    <Orders />
</SuperAdminGuard>
```

Code example of SuperAdminGuard:

```javascript
export const SuperAdminGuard = ({ children }) => {
    const { currentUser } = useAuth();
    const hasPermission = checkForSuperAdmin(currentUser);
    return hasPermission ? children : <Navigate to={'/dashboard'} />;
};
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://intercode.gitbook.io/intercode-saas-kit/basics/app-roles.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
