Overview
The Positions API (Cargos) allows you to manage employee positions and roles within Core Projects. Positions define job titles and responsibilities, and are used to control access and permissions through role-based access control. This API supports CRUD operations, employee listings, and employee counting.
The Position Object
Unique identifier for the position
Position name/title (max 80 characters, must be unique)
Position description explaining responsibilities and duties (max 200 characters)
Array of employees assigned to this position Employee’s department details
Number of employees assigned to this position (available when using withCount endpoint)
Timestamp when the position was created
Timestamp when the position was last updated
List All Positions
Returns a list of all positions with their associated employees.
Response
{
"success" : true ,
"data" : [
{
"id_cargo" : 1 ,
"nombre" : "Gerente de Proyectos" ,
"descripcion" : "Responsable de la gestión y supervisión de proyectos de construcción" ,
"empleados" : [
{
"id_empleado" : 1 ,
"nombre" : "Juan" ,
"apellido" : "Pérez" ,
"email" : "[email protected] " ,
"estado" : true ,
"dependencia" : {
"id_dependencia" : 1 ,
"nombre" : "Proyectos"
}
}
],
"created_at" : "2024-01-10T08:00:00.000000Z" ,
"updated_at" : "2024-01-10T08:00:00.000000Z"
},
{
"id_cargo" : 2 ,
"nombre" : "Arquitecto" ,
"descripcion" : "Diseño y planificación arquitectónica de proyectos" ,
"empleados" : [],
"created_at" : "2024-01-10T08:00:00.000000Z" ,
"updated_at" : "2024-01-10T08:00:00.000000Z"
}
]
}
Create Position
Creates a new position in the organization.
Body Parameters
Position name/title (max 80 characters, must be unique)
Position description (max 200 characters)
Request Example
{
"nombre" : "Ingeniero Civil" ,
"descripcion" : "Responsable del diseño y supervisión de estructuras civiles"
}
Response
{
"success" : true ,
"message" : "Cargo creado exitosamente" ,
"data" : {
"id_cargo" : 3 ,
"nombre" : "Ingeniero Civil" ,
"descripcion" : "Responsable del diseño y supervisión de estructuras civiles" ,
"created_at" : "2024-01-20T10:30:00.000000Z" ,
"updated_at" : "2024-01-20T10:30:00.000000Z"
}
}
Validation Errors
{
"success" : false ,
"errors" : {
"nombre" : [ "Este cargo ya existe en el sistema" ],
"descripcion" : [ "La descripción no puede exceder 200 caracteres" ]
}
}
Get Position
Retrieves a specific position by ID with all associated employees and their departments.
Path Parameters
The position’s unique identifier (id_cargo)
Response
{
"success" : true ,
"data" : {
"id_cargo" : 1 ,
"nombre" : "Gerente de Proyectos" ,
"descripcion" : "Responsable de la gestión y supervisión de proyectos de construcción" ,
"empleados" : [
{
"id_empleado" : 1 ,
"nombre" : "Juan" ,
"apellido" : "Pérez" ,
"email" : "[email protected] " ,
"telefono" : "+57 300 123 4567" ,
"estado" : true ,
"dependencia" : {
"id_dependencia" : 1 ,
"nombre" : "Proyectos" ,
"descripcion" : "Departamento de gestión de proyectos"
}
},
{
"id_empleado" : 4 ,
"nombre" : "Carlos" ,
"apellido" : "Ramírez" ,
"email" : "[email protected] " ,
"telefono" : "+57 302 345 6789" ,
"estado" : true ,
"dependencia" : {
"id_dependencia" : 1 ,
"nombre" : "Proyectos" ,
"descripcion" : "Departamento de gestión de proyectos"
}
}
],
"created_at" : "2024-01-10T08:00:00.000000Z" ,
"updated_at" : "2024-01-10T08:00:00.000000Z"
}
}
Error Response
{
"success" : false ,
"message" : "Cargo no encontrado"
}
Update Position
Updates an existing position’s information.
Path Parameters
The position’s unique identifier (id_cargo)
Body Parameters
Position name/title (max 80 characters, must be unique except for current record)
Position description (max 200 characters)
Request Example
{
"nombre" : "Gerente Senior de Proyectos" ,
"descripcion" : "Responsable de la gestión, supervisión y coordinación de múltiples proyectos"
}
Response
{
"success" : true ,
"message" : "Cargo actualizado exitosamente" ,
"data" : {
"id_cargo" : 1 ,
"nombre" : "Gerente Senior de Proyectos" ,
"descripcion" : "Responsable de la gestión, supervisión y coordinación de múltiples proyectos" ,
"created_at" : "2024-01-10T08:00:00.000000Z" ,
"updated_at" : "2024-01-21T09:15:00.000000Z"
}
}
Delete Position
Deletes a position from the system. This operation will fail if the position has associated employees.
Path Parameters
The position’s unique identifier (id_cargo)
Response
{
"success" : true ,
"message" : "Cargo eliminado exitosamente"
}
Error Responses
Position Not Found
{
"success" : false ,
"message" : "Cargo no encontrado"
}
Has Associated Employees
{
"success" : false ,
"message" : "No se puede eliminar el cargo porque tiene empleados asociados"
}
You cannot delete a position that has employees assigned to it. First reassign or remove the employees, then delete the position.
List Positions with Count
GET /api/cargos/with-count
Returns all positions with a count of employees assigned to each position.
Response
{
"success" : true ,
"data" : [
{
"id_cargo" : 1 ,
"nombre" : "Gerente de Proyectos" ,
"descripcion" : "Responsable de la gestión de proyectos" ,
"empleados_count" : 3 ,
"created_at" : "2024-01-10T08:00:00.000000Z" ,
"updated_at" : "2024-01-10T08:00:00.000000Z"
},
{
"id_cargo" : 2 ,
"nombre" : "Arquitecto" ,
"descripcion" : "Diseño arquitectónico" ,
"empleados_count" : 5 ,
"created_at" : "2024-01-10T08:00:00.000000Z" ,
"updated_at" : "2024-01-10T08:00:00.000000Z"
},
{
"id_cargo" : 3 ,
"nombre" : "Ingeniero Civil" ,
"descripcion" : "Diseño de estructuras" ,
"empleados_count" : 8 ,
"created_at" : "2024-01-10T08:00:00.000000Z" ,
"updated_at" : "2024-01-10T08:00:00.000000Z"
}
]
}
This endpoint is particularly useful for organizational charts and reporting dashboards that need to show staffing levels by role.
Get Position Employees
GET /api/cargos/{id}/empleados
Returns all active employees assigned to a specific position with their department information.
Path Parameters
The position’s unique identifier (id_cargo)
Response
{
"success" : true ,
"data" : {
"cargo" : "Gerente de Proyectos" ,
"descripcion" : "Responsable de la gestión y supervisión de proyectos de construcción" ,
"empleados" : [
{
"id_empleado" : 1 ,
"nombre" : "Juan" ,
"apellido" : "Pérez" ,
"email" : "[email protected] " ,
"telefono" : "+57 300 123 4567" ,
"estado" : true ,
"dependencia" : {
"id_dependencia" : 1 ,
"nombre" : "Proyectos" ,
"descripcion" : "Departamento de gestión de proyectos"
}
},
{
"id_empleado" : 4 ,
"nombre" : "Carlos" ,
"apellido" : "Ramírez" ,
"email" : "[email protected] " ,
"telefono" : "+57 302 345 6789" ,
"estado" : true ,
"dependencia" : {
"id_dependencia" : 2 ,
"nombre" : "Ventas" ,
"descripcion" : "Departamento comercial"
}
}
]
}
}
This endpoint only returns employees with estado = true (active employees).
Error Response
{
"success" : false ,
"message" : "Cargo no encontrado"
}
Relationships
Has Many
Empleados (Employees)
Foreign Key: empleados.id_cargo
References: id_cargo
A position can have many employees
Deletion is prevented if employees exist
Validation Rules
Create Position
Field Rules Error Messages nombre required, string, max:80, unique:cargos ”Este cargo ya existe en el sistema” descripcion nullable, string, max:200 ”La descripción no puede exceder 200 caracteres”
Update Position
Same rules as creation, except:
nombre uniqueness excludes the current record
Database Schema
Table : cargos
Columns:
- id_cargo ( primary key )
- nombre ( varchar 80 , unique )
- descripcion ( varchar 200 , nullable)
- created_at ( timestamp )
- updated_at ( timestamp )
Relationships:
- Has many empleados (one - to - many)
Role-Based Access Control
Positions (cargos) are used for role-based access control throughout the application. The middleware cargo:1 in the commented routes suggests that certain positions have administrative privileges.
Example Middleware Usage
// From routes/api.php (commented)
Route :: middleware ([ 'auth:sanctum' , 'cargo:1' ]) -> group ( function () {
Route :: get ( 'paises/' , [ PaisController :: class , 'index' ]);
});
This indicates that position ID 1 likely represents an administrative role with elevated permissions.
Business Rules
Unique Names : Position names must be unique across the organization
Deletion Constraints : Positions with employees cannot be deleted
Employee Filtering : The empleados endpoint only returns active employees
Cascade Prevention : No cascade delete - must manually reassign employees first
Role-Based Permissions : Certain positions may have system-level permissions
Common Use Cases
Organizational Structure
Use the with-count endpoint to visualize your organizational structure:
const response = await fetch ( '/api/cargos/with-count' );
const { data } = await response . json ();
// Display position hierarchy with employee counts
data . forEach ( position => {
console . log ( ` ${ position . nombre } : ${ position . empleados_count } employees` );
});
Position Reassignment
Before deleting a position, reassign employees:
// 1. Get all employees with this position
const positionResponse = await fetch ( '/api/cargos/1/empleados' );
const { data : { empleados } } = await positionResponse . json ();
// 2. Reassign each employee to a new position
for ( const emp of empleados ) {
await fetch ( `/api/empleados/ ${ emp . id_empleado } ` , {
method: 'PUT' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({ ... emp , id_cargo: 2 })
});
}
// 3. Now delete the position
await fetch ( '/api/cargos/1' , { method: 'DELETE' });
Permission Checking
// Get current user's position
const userResponse = await fetch ( '/api/user' );
const user = await userResponse . json ();
// Check if user has admin position (id_cargo = 1)
const isAdmin = user . id_cargo === 1 ;
if ( isAdmin ) {
// Show admin features
console . log ( 'User has administrative access' );
}
Staffing Report by Role
const positionsResponse = await fetch ( '/api/cargos/with-count' );
const { data : positions } = await positionsResponse . json ();
// Generate staffing report
const totalEmployees = positions . reduce (
( sum , pos ) => sum + pos . empleados_count ,
0
);
console . log ( `Total Employees: ${ totalEmployees } ` );
console . log ( ' \n Breakdown by Position:' );
positions . forEach ( pos => {
const percentage = (( pos . empleados_count / totalEmployees ) * 100 ). toFixed ( 1 );
console . log ( ` ${ pos . nombre } : ${ pos . empleados_count } ( ${ percentage } %)` );
});
Notes
Position IDs and Permissions : Position ID 1 appears to have special significance in the codebase for administrative access. Be cautious when modifying or deleting this position.
Best Practice : Always check for associated employees before attempting to delete a position. Use the with-count or empleados endpoint first.