Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Glemynart/SaaS/llms.txt

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

Access control in La Oficina Nítida is built around three roles that define what each user can see and do within their organization. Every user belongs to exactly one tenant and carries exactly one role, encoded directly in the JWT access token. The platform enforces these roles at the route level using RolesGuard, which inspects the token before any controller logic runs.

Roles

RoleDescription
ADMINFull access to all modules. Can create, edit, and delete employees, manage contracts and bulk batches, access billing and invoicing, upload branding assets, manage branches, invite and update users, and change organization settings. The first user created for any organization is always an ADMIN.
OPERADORDay-to-day operational access. Can create and edit employees (including bulk import), create and manage contracts, generate documents, access the expedient and alerts, and work with billing and invoicing. Cannot delete records, cannot manage users, and cannot change organization-level settings.
VIEWERRead-only access across all modules. Intended for stakeholders who need visibility without the ability to make changes.
The UserRole enum in the database defines these three values: ADMIN, OPERADOR, VIEWER. The default role assigned to new users created through the service is OPERADOR.

How Role Enforcement Works

Every controller that requires a specific role is decorated with @Roles(UserRole.ADMIN) (or the appropriate role). The RolesGuard reads the rol claim from the verified JWT and rejects requests from users whose role does not match. Role guards always run after JwtAuthGuard and ActiveTenantGuard, so a request must be both authenticated and from an active tenant before roles are even evaluated.
Request → JwtAuthGuard → ActiveTenantGuard → RolesGuard → Controller method

User Data Model

Each user belongs to a single tenant. The email address is unique within a tenant, but two users in different organizations can share the same email.
FieldTypeDescription
idString (UUID)Primary key
tenantIdStringThe organization this user belongs to
emailStringLogin email — unique per tenant, stored in lowercase
nombreStringFirst name
apellidoStringLast name
rolUserRoleRole: ADMIN, OPERADOR, or VIEWER
activoBooleanWhether the user can log in; defaults to true
lastLoginAtDateTime?Timestamp of the most recent successful login

Creating Users

There is no standalone user invitation endpoint in the current MVP. New users are created via UsersService.create(), which is called by authorized flows within the platform (such as the admin user interface). The service enforces the following rules:
  • The email must not already exist for the same tenant
  • The password is hashed with bcrypt (10 rounds) before storage
  • The tenantId is always supplied by the calling service, never by the client
When creating a user programmatically (e.g., from a seed script or future admin endpoint), provide:
{
  "tenantId": "<derived from JWT>",
  "email": "operador@miempresa.com",
  "passwordPlain": "SecurePass123!",
  "nombre": "Laura",
  "apellido": "Pérez",
  "rol": "OPERADOR"
}
If a user with the same email already exists within the tenant, the service throws 409 Conflict.

Inviting Users: Expected Flow

When an admin adds a new user through the platform UI:
  1. The admin fills in the new user’s name, email, password, and role
  2. The platform calls UsersService.create() with the admin’s tenantId (from the JWT) injected automatically
  3. The new user can immediately log in using POST /auth/login with the organization’s NIT, their email, and the assigned password
Login requires three pieces of information: the organization’s NIT (tenantNit), the user’s email, and their password. This three-factor login model ensures that email addresses can be reused across different organizations without collision.
curl -X POST https://api.example.com/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "tenantNit": "900123456",
    "email": "operador@miempresa.com",
    "passwordPlain": "SecurePass123!"
  }'
The first ADMIN user for every organization is created automatically during tenant registration via POST /auth/register. This user is the organization’s initial super-user and is the only way to bootstrap access to the platform for a new tenant. Subsequent users must be created by an existing ADMIN within that organization.
The VIEWER role is defined in the schema and recognized by the RolesGuard, but it is not yet fully implemented in the current MVP. Protected read-only routes for VIEWER-level access are planned for a future release. Assigning the VIEWER role to a user today may result in limited or inconsistent access until that work is complete.

Build docs developers (and LLMs) love