Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/TheSerchCp/SEAM/llms.txt

Use this file to discover all available pages before exploring further.

SEAM uses a two-layer access control model. Roles are named profiles (e.g. admin, profesor, alumno) that are assigned to users and used to populate dropdown selectors throughout the application. Permissions are fine-grained URI-shaped strings (e.g. ver_reportes) that can be created, deleted, and freely assigned to or removed from any role. The Permissions page presents both dimensions side-by-side and reacts in real time when any connected client changes the configuration.

Roles

Roles are read-only from the UI perspective — they are fetched on demand and used to populate <select> fields in the user and permissions forms. There is no create/edit/delete UI for roles in the current release; management is expected to happen directly in the database or via a future admin panel.
// roles.repository.js
import { ApiClient } from '../core/ApiClient.js';

export const getAll = () => ApiClient.get('/roles');
// roles.service.js
import * as RolesRepo from '../repositories/roles.repository.js';

export const getRoles = () => RolesRepo.getAll();
The RolesPage falls back to session.roles seed data if the API call fails, ensuring the page renders even in offline or dev environments.

Permissions repository

Every permission operation is handled by permissions.repository.js, which maps directly onto the REST API:
// permissions.repository.js
import { ApiClient } from '../core/ApiClient.js';

export const getAllPermissions    = ()                     =>
    ApiClient.get('/permission');

export const getPermissionsByRole = (roleId)               =>
    ApiClient.get(`/permission/getByRoleId?roleId=${roleId}`)
             .then(r => r.map(p => ({ ...p, permissionId: p.idPermission })));

export const createPermission     = (data)                 =>
    ApiClient.post('/permission/register', data);

export const removePermission     = (id)                   =>
    ApiClient.delete(`/permission/${id}`);

export const assignToRole         = (roleId, permissionId) =>
    ApiClient.post('/permission/assign', { roleId, permissionId });

export const removeFromRole       = (roleId, permissionId) =>
    ApiClient.delete('/permission/unassign', { roleId, permissionId });

Permissions service

// permissions.service.js
import * as PermRepo from '../repositories/permissions.repository.js';

export const getAllPermissions        = ()                     => PermRepo.getAllPermissions();
export const getPermissionsByRole     = (roleId)               => PermRepo.getPermissionsByRole(roleId);
export const createPermission         = (data)                 => PermRepo.createPermission(data);
export const removePermission         = (id)                   => PermRepo.removePermission(id);
export const assignPermissionToRole   = (roleId, permissionId) => PermRepo.assignToRole(roleId, permissionId);
export const removePermissionFromRole = (roleId, permissionId) => PermRepo.removeFromRole(roleId, permissionId);

API endpoints

MethodPathDescription
GET/rolesList all roles
GET/permissionList all permissions
GET/permission/getByRoleId?roleId=XList permissions assigned to role X
POST/permission/registerCreate a new permission { nameUri, description }
DELETE/permission/:idDelete a permission by ID
POST/permission/assignAssign a permission to a role { roleId, permissionId }
DELETE/permission/unassignRemove a permission from a role { roleId, permissionId }

Create permission payload

nameUri
string
required
A URI-style identifier for the permission, e.g. ver_reportes.
description
string
A human-readable description shown in the permissions table.

Permissions page UI

The page renders two panels side-by-side:
  • Permisos disponibles — all permissions not yet assigned to the selected role. Each row has an Assign button and a Delete button.
  • Permisos del rol — permissions currently assigned to the selected role. Each row has a Remove and a Delete button.
A role dropdown selector at the top of the page drives both panels. Changing the selection re-fetches and re-renders both tables.
const reloadPanels = async () => {
    const roleId = getSelectedRole();
    const [all, assigned] = await Promise.all([
        getAllPermissions(),
        roleId ? getPermissionsByRole(roleId) : Promise.resolve([])
    ]);
    // ...render tables
};

Real-time updates

The permissions page listens for data:changed events from the WebSocket and calls reloadPanels() when any of the following operations are broadcast by the server:
// OperationListeners.js
permissions: [
    'permissions:create',
    'permissions:update',
    'permissions:delete',
    'permissions:assign',
    'permissions:unassign',
    'roles:create',
    'roles:update',
    'roles:delete'
],
const unsubSocket = EventBus.on('data:changed', async (payload) => {
    if (shouldUpdatePage('permissions', payload?.operation)) {
        // Ignore events originated by this client — page:reload already fired
        if (payload?.initiatorSocketId === EventBus.socketId) return;
        await reloadPanels();
    }
});
Role changes (roles:create, roles:update, roles:delete) are included in the permissions listener because the role selector dropdown must stay in sync when another admin modifies the roles list.
Deleting a permission removes it globally — all role assignments for that permission are also removed by the backend. This action cannot be undone from the UI.

Build docs developers (and LLMs) love