Skip to main content

Overview

ARCA implements a hierarchical role-based access control (RBAC) system with four distinct user roles. Each role has specific permissions and access levels that control what users can see and do within the system.
The role system uses a numeric hierarchy where lower numbers indicate higher privileges. This design allows for efficient permission checks throughout the application.

Role Hierarchy

ARCA defines four user roles in order of privilege level:

Admin

Role ID: 1 - Highest privilege levelFull system access including user management and system configuration.

Secretário

Role ID: 2 - Administrative staffManages users, patients, and administrative tasks.

Supervisor

Role ID: 3 - Clinical supervisorOversees estagiários and reviews clinical work.

Estagiário

Role ID: 4 - InternProvides patient care under supervision.

Database Schema

Roles are defined in the database schema:
apps/backend/prisma/schema.prisma
model Role {
  id_Role   Int       @id @default(autoincrement()) @map("ID_Role") @db.SmallInt
  role      String    @db.VarChar(50)
  descricao String    @db.VarChar(255)
  usuarios  Usuario[]

  @@map("ROLES")
}

model Usuario {
  id_User   String  @id @default(uuid()) @map("ID_User") @db.Uuid
  nome      String  @db.VarChar(50)
  email     String  @unique @db.VarChar(100)
  senhaHash String  @map("SenhaHash") @db.VarChar(255)
  roleId    Int     @map("ID_Role") @db.SmallInt
  isActive  Boolean @default(true)

  role Role @relation(fields: [roleId], references: [id_Role])
  // ... other relations
}

Role Initialization

Roles are seeded into the database during initial setup:
apps/backend/prisma/seed.ts
await prisma.role.createMany({
  data: [
    {
      role: 'ADMIN',
      descricao: 'Administrador do sistema'
    },
    {
      role: 'SECRETARIO',
      descricao: 'Secretário administrativo'
    },
    {
      role: 'SUPERVISOR',
      descricao: 'Supervisor de estagiários'
    },
    {
      role: 'ESTAGIARIO',
      descricao: 'Estagiário em psicologia'
    }
  ]
})

Permission System

Hierarchical Access Control

The permission system follows a hierarchical model where users can only manage other users with equal or lower privilege levels:
1

Admin (Role ID: 1)

Can manage all users including other Admins, Secretários, Supervisors, and Estagiários
2

Secretário (Role ID: 2)

Can manage Supervisors and Estagiários, but not Admins or other Secretários
3

Supervisor (Role ID: 3)

Can manage Estagiários only, not Admins, Secretários, or other Supervisors
4

Estagiário (Role ID: 4)

Cannot manage any users

User Management Permissions

Creating Users

Users can only create accounts with equal or lower privilege levels:
apps/backend/src/users/users.service.ts
async create(createUserDto: CreateUserDto, creator: TokenDto) {
  // Verifica se o criador tem permissão para criar usuários
  if (
    // 1. A regra geral: proíbe se o novo usuário tiver acesso igual ou superior
    createUserDto.roleId <= creator.access &&
    // 2. A exceção: a regra acima NÃO se aplica se for um Admin (1) criando outro Admin (1)
    !(creator.access === 1 && createUserDto.roleId === 1)
  ) {
    throw new ForbiddenException(
      'Você não tem permissão para criar um usuário com nível de acesso igual ou superior ao seu.',
    );
  }
  // ... create user
}
Special Case: Only Admins can create other Admin accounts. This prevents privilege escalation.

Viewing Users

Users can only view accounts with equal or lower privilege levels:
apps/backend/src/users/users.service.ts
async findAll(creator: TokenDto) {
  // Lista apenas os usuários com nível de acesso menor ou igual ao do criador
  const users = await this.prisma.usuario.findMany({
    where: {
      roleId: {
        gte: creator.access, // Greater than or equal to creator's role ID
      },
    },
    // ...
  });
  return users;
}

Updating Users

Users cannot edit accounts with higher or equal privilege levels (with Admin exception):
apps/backend/src/users/users.service.ts
async update(id: UUID, updateUserDto: UpdateUserDto, creator: TokenDto) {
  const user = await this.prisma.usuario.findFirst({
    where: { id_User: id },
  });

  // REGRA 1: Você não pode editar um usuário com nível igual ou superior ao seu
  const canEditUser =
    creator.access < user.roleId ||
    (creator.access === 1 && user.roleId === 1);

  if (!canEditUser) {
    throw new ForbiddenException(
      'Você não tem permissão para editar um usuário com nível de acesso igual ou superior ao seu.',
    );
  }
  // ... update user
}
Users cannot change role assignments during updates. Role changes require special administrative procedures to prevent privilege escalation.

Deleting Users

Users cannot delete their own account or accounts with higher/equal privilege:
apps/backend/src/users/users.service.ts
async remove(id: UUID, creator: TokenDto) {
  const user = await this.prisma.usuario.findUnique({
    where: { id_User: id },
  });

  // Você não pode deletar a si mesmo.
  if (creator.sub === user.id_User) {
    throw new ForbiddenException('Você não pode deletar sua própria conta.');
  }

  // Você não pode deletar um usuário com nível de acesso igual ou superior.
  const canDelete =
    creator.access < user.roleId ||
    (creator.access === 1 && user.roleId === 1);

  if (!canDelete) {
    throw new ForbiddenException(
      'Você não tem permissão para deletar um usuário com nível de acesso igual ou superior ao seu.',
    );
  }
  // ... delete user
}

Route-Level Permissions

The frontend middleware enforces route-level access control:
apps/frontend/middleware.ts
const routePermissions: Record<string, number> = {
  "/dashboard/usuarios": 2, // Secretário (2) or superior (Admin = 1)
  "/dashboard/usuarios/criar": 2, // Secretário or superior
  "/dashboard/usuarios/permissoes": 1, // Apenas Admin
};

// Verifica se a rota tem restrições
for (const [route, maxRoleId] of Object.entries(routePermissions)) {
  if (pathname.startsWith(route)) {
    const userRoleId = token?.roleId as number
    
    if (!userRoleId || userRoleId > maxRoleId) {
      // Redireciona para página de acesso negado
      return NextResponse.redirect(new URL('/dashboard/unauthorized', req.url))
    }
  }
}
Route permissions use maximum role ID values. A user can access a route if their role ID is less than or equal to the specified maximum.

Clinical Workflow Roles

Estagiário-Supervisor Relationship

ARCA’s patient management system enforces the estagiário-supervisor relationship:
apps/backend/prisma/schema.prisma
model Paciente {
  // ... other fields
  id_Estagiario_Responsavel String @db.Uuid
  id_Supervisor_Responsavel String @db.Uuid

  estagiarioResponsavel Usuario @relation("EstagiarioResponsavel", fields: [id_Estagiario_Responsavel], references: [id_User])
  supervisorResponsavel Usuario @relation("SupervisorResponsavel", fields: [id_Supervisor_Responsavel], references: [id_User])
}

model Atendimento {
  // ... other fields
  id_Estagiario_Executor String @db.Uuid
  id_Supervisor_Executor String @db.Uuid

  estagiarioExecutor Usuario @relation("EstagiarioAtendimentos", fields: [id_Estagiario_Executor], references: [id_User])
  supervisorExecutor Usuario @relation("SupervisorAtendimentos", fields: [id_Supervisor_Executor], references: [id_User])
}

Report Approval Workflow

Discharge reports require both estagiário creation and supervisor approval:
apps/backend/prisma/schema.prisma
model RelatorioAlta {
  id_Documento  String              @id @default(uuid())
  id_Paciente   String              @db.Uuid
  id_Estagiario String              @db.Uuid
  id_Supervisor String              @db.Uuid
  conteudo      String              @db.Text
  dataEmissao   DateTime            @default(now())
  status        StatusRelatorioEnum @default(PENDENTE)

  paciente   Paciente @relation(fields: [id_Paciente], references: [id_Paciente])
  estagiario Usuario  @relation("EstagiarioRelatorios", fields: [id_Estagiario], references: [id_User])
  supervisor Usuario  @relation("SupervisorRelatorios", fields: [id_Supervisor], references: [id_User])
}

enum StatusRelatorioEnum {
  PENDENTE
  EMITIDO
  CANCELADO
}

Best Practices

Assign users the minimum role level required for their responsibilities. For example, if someone only needs to supervise estagiários, assign the Supervisor role rather than Secretário.
Periodically review user roles and permissions to ensure they align with current responsibilities. Remove or downgrade access for users who no longer require elevated privileges.
Limit the number of Admin accounts and use strong authentication. Admin accounts have unrestricted access and should be closely monitored.
Maintain an audit trail when changing user roles, especially elevating privileges. This helps with compliance and security investigations.

Authentication

Learn about login, JWT tokens, and session management

User Accounts

Create, update, and manage user accounts

Build docs developers (and LLMs) love