Ir al contenido

Capacitación

El módulo cubre el flujo de autoservicio de capacitación del empleado autenticado: ver los cursos con evaluación activa, estudiar su contenido, rendir el quiz (por curso completo o por capítulo, según la configuración del curso), consultar la malla curricular asignada a su cargo, revisar su historial de capacitaciones y descargar certificados. También incluye la gestión de “procedimientos” (documentos de inducción/procedimiento que requieren registrar una fecha de capacitación).

Acciones cubiertas:

  • Ver cursos con evaluación activa asignados al usuario.
  • Ver el detalle de un curso activo (capítulos, archivos/videos, objetivo, material).
  • Marcar un archivo/video de un capítulo como visto (requisito para poder rendir el quiz del capítulo).
  • Rendir el quiz de un curso (evaluación general o por capítulo, según el curso) y ver el resultado.
  • Ver la malla curricular (capacitaciones asignadas al cargo del usuario, con o sin evaluación).
  • Ver el detalle de una capacitación de la malla curricular.
  • Ver el historial de capacitaciones (evaluaciones en línea, presenciales, cursos virtuales) con filtro por tipo.
  • Descargar el certificado de una capacitación del historial.
  • Ver y registrar procedimientos de inducción asignados al cargo del usuario.

Prerrequisitos:

  • La malla curricular (curricular-mesh) y los procedimientos (procedures) requieren que el usuario tenga información organizacional activa (cargo). Sin ella, el backend rechaza esos endpoints con un error genérico (ver Convenciones).
  • La descarga de certificado (history/certificate) depende de un servicio legacy de generación de documentos; puede fallar con 400 si ese servicio no responde correctamente.
sequenceDiagram
    participant App as App móvil
    participant API as th-core-api

    Note over App,API: Tab Cursos activos
    App->>API: GET /me/training/active
    API-->>App: cursos con evaluación activa (o 404 si no hay ninguno)

    Note over App,API: Usuario abre el detalle de un curso
    App->>API: GET /me/training/active/:trainingId/evaluation/:evaluationId
    API-->>App: capítulos, archivos, evaluaciones (con couldEvaluate por capítulo)
    App->>API: PUT /me/training/active/file
    Note over App: al abrir cada archivo/video del capítulo
    API-->>App: confirmación (marca el archivo como visto)

    Note over App,API: Usuario inicia el quiz (curso completo o de un capítulo)
    App->>API: GET /me/training/active/:trainingId/evaluation/:evaluationId/quiz
    API-->>App: preguntas y respuestas (mezcladas), datos del examen
    App->>API: POST /me/training/active/:trainingId/evaluation/:evaluationId/quiz
    API-->>App: resultado (approval, score, isFinalEvaluation)
    App->>API: GET /me/training/active/:trainingId/evaluation/:evaluationId
    API-->>App: refresco del detalle (couldEvaluate/attempts actualizados)

    Note over App,API: Tab Malla curricular
    App->>API: GET /me/training/curricular-mesh
    API-->>App: capacitaciones asignadas al cargo del usuario
    App->>API: GET /me/training/curricular-mesh/:id
    Note over App: al abrir el detalle de una capacitación
    API-->>App: capítulos, archivos y cargos recomendados

    Note over App,API: Tab Historial
    App->>API: GET /me/training/history/:type
    API-->>App: historial paginado, filtrable por tipo
    App->>API: GET /me/training/history/certificate/:type/:id
    Note over App: acción Ver certificado, solo si hasCertificate = true
    API-->>App: url del PDF generado

    Note over App,API: Tab Procedimientos
    App->>API: GET /me/training/procedures
    API-->>App: procedimientos asignados al cargo del usuario
    App->>API: GET /me/training/procedures/:id
    Note over App: al abrir el detalle de un procedimiento
    API-->>App: detalle completo del procedimiento
    App->>API: PUT /me/training/procedures
    Note over App: solo si el procedimiento aun no tiene fecha registrada
    API-->>App: procedimiento actualizado

Cursos con evaluación activa asignados al usuario autenticado (usuario o cargo).

Query params:

Param Tipo Obligatorio Default Descripción
page number No 1 Página a consultar.
limit number No 5 Elementos por página.

Response — paginado, cada item es una evaluación de curso:

Campo Tipo Descripción
id number Id de la evaluación (evaluationId en el resto de los endpoints).
trainingId number Id del curso (virtualTraining.id).
referenceType enum VirtualTrainingEvaluationReferenceTypeEnum C Capacitación, S Selección, I Inducción.
referenceId number Id de referencia del proceso origen (-1 si no aplica).
userType enum U asignado por usuario, C asignado por cargo.
directedTo enum C quienes lo requiere su cargo, E usuarios específicos, T todos.
studentStartDate / studentEndDate date Período habilitado para estudiar el contenido.
finalValidityPeriod S / N Si S, la vigencia final del curso aplica reglas adicionales (no relevantes para mobile).
examStartDate / examEndDate date Período habilitado para rendir el quiz.
examQuestionCount number Cantidad de preguntas del examen.
examDurationMinutes number Duración máxima del examen, en minutos.
examAttempts number Intentos máximos permitidos.
minimumScorePercentage number Nota mínima de aprobación (%).
passApproach S / N Si S, la nota mínima real es minimumScorePercentage + 1 (ver Lógica de cliente).
questionWeight S / N Si S, las preguntas del examen se distribuyen proporcionalmente por capítulo.
chapterEvaluation S / N Si S, el curso se evalúa por capítulo (generalEvaluation = false); si N, es una única evaluación general.
orderedResponses A / O A = respuestas mezcladas aleatoriamente, O = orden fijo.
virtualTraining object { id, subcategoryId, certificateFormatId, trainingId, name, description, objective, archive, image, link }.
userEvaluations array Evaluaciones del usuario para este curso — ver tabla siguiente.

userEvaluations[]:

Campo Tipo Descripción
evaluationId number Id de la evaluación.
studyStartDate / studyEndDate date | null Fechas de estudio del usuario.
studyStatus string A = activo.
evaluationDate date | null Fecha en que rindió el quiz.
correctQuestionsCount / incorrectQuestionsCount / unansweredQuestionsCount number | null Detalle de respuestas del último intento.
result number | null Nota obtenida (%).
numberOfTries number Intentos ya usados.
approval S / N / null null = aún no rindió el quiz.
{
"items": [
{
"id": 4521,
"trainingId": 363,
"referenceType": "C",
"referenceId": -1,
"userType": "U",
"directedTo": "T",
"studentStartDate": "2026-06-01",
"studentEndDate": "2026-08-31",
"finalValidityPeriod": "S",
"examStartDate": "2026-06-01",
"examEndDate": "2026-08-31",
"examQuestionCount": 10,
"examDurationMinutes": 30,
"examAttempts": 3,
"minimumScorePercentage": 70,
"passApproach": "S",
"questionWeight": "N",
"chapterEvaluation": "N",
"orderedResponses": "A",
"virtualTraining": {
"id": 363,
"subcategoryId": 62,
"certificateFormatId": 1,
"trainingId": "SSA-05",
"name": "PLAN DE EMERGENCIAS",
"description": "",
"objective": "Dar a conocer a los colaboradores el plan de emergencia anual de la compañía.",
"archive": "",
"image": "",
"link": ""
},
"userEvaluations": [
{
"evaluationId": 4521,
"studyStartDate": "2026-07-10T14:02:00.000Z",
"studyEndDate": null,
"studyStatus": "A",
"evaluationDate": null,
"correctQuestionsCount": null,
"incorrectQuestionsCount": null,
"unansweredQuestionsCount": null,
"result": null,
"token": null,
"numberOfTries": 0,
"approval": null
}
]
}
],
"meta": {
"totalItems": 1,
"itemCount": 1,
"itemsPerPage": 5,
"totalPages": 1,
"currentPage": 1
}
}

Errores específicos:

Código Cuándo ocurre
404 El usuario no tiene evaluaciones de capacitación activas ("No se encontraron capacitaciones activas"). Tratar como estado vacío, no como error de red.

GET /me/training/active/:trainingId/evaluation/:evaluationId

Sección titulada «GET /me/training/active/:trainingId/evaluation/:evaluationId»

Detalle completo de un curso activo: capítulos con su contenido/archivos y las evaluaciones asociadas.

Path params: trainingId (number), evaluationId (number).

Response:

Campo Tipo Descripción
id / trainingId / name / description / objective / archive / image / link Datos del curso (trainingId aquí es el código string, ej. "SSA").
status string Estado del curso (A activo).
chapters TrainingChapterDto[] Ver tabla siguiente.
evaluations TrainingEvaluationDto[] Ver tabla siguiente.

chapters[]:

Campo Tipo Descripción
trainingId number Id del curso.
id number Id del capítulo.
name string Nombre del capítulo.
couldEvaluate boolean true sólo si el capítulo tiene archivos y el usuario vio todos. Habilita el botón “Rendir quiz del capítulo” cuando chapterEvaluation = S. Un capítulo sin archivos nunca queda en true (ver Lógica de cliente).
numberOfTries number Intentos ya usados en el quiz de este capítulo.
text string Contenido HTML del capítulo (sanitizado).
userChapterEvaluations array Historial de intentos del capítulo: { evaluationDate, attempts, result, approval, status }.
files ChapterFileDto[] Ver tabla siguiente.

chapters[].files[]:

Campo Tipo Descripción
chapterId number Id del capítulo dueño.
id number Id del archivo.
type D | V | U | A Documento / Video / URL / Audio.
name string Nombre visible.
file string Ruta interna del archivo (si aplica; usar junto al repositorio de storage para resolver la URL).
link string URL externa directa (ej. YouTube); si viene vacío, usar file.
order number Orden de presentación.
userViewed boolean Si el usuario ya vio este archivo (userViews.length > 0).
userViews array { viewedDate }[], historial de vistas.

evaluations[]:

Campo Tipo Descripción
id number Id de la evaluación (evaluationId).
trainingId number Id del curso.
studentStartDate / studentEndDate / examStartDate / examEndDate date Ver tabla de GET active.
ValidityPeriod string (nótese la mayúscula inicial, viene así del backend) Vigencia final.
examDurationMinutes / examAttempts / minimumScorePercentage number Ver tabla de GET active.
chapterEvaluation S / N Igual que en GET active.
generalEvaluation boolean true cuando chapterEvaluation = N (una sola evaluación para todo el curso). Calculado por el backend.
numberOfTries number Intentos usados por el usuario (tomado de userEvaluations[0]).
userEvaluations array Igual forma que en GET active, más status.
{
"id": 363,
"trainingId": "SSA",
"name": "SALUD PREVENTIVA VOLUMEN 1",
"description": "PREVENCIÓN DE ENFERMEDADES CARDIOVASCULARES",
"objective": "",
"archive": "",
"image": "",
"link": "",
"status": "A",
"chapters": [
{
"trainingId": 363,
"id": 144,
"name": "MODULO 1. PREVENCIÓN DE ACCIDENTE CEREBRO VASCULAR",
"couldEvaluate": true,
"numberOfTries": 0,
"text": "",
"userChapterEvaluations": [],
"files": [
{
"chapterId": 144,
"id": 179,
"type": "U",
"name": "PREVENCIÓN DE ENFERMEDADES CARDIOVASCULARES",
"file": "",
"link": "https://www.youtube.com/watch?v=V263s5BCjsE",
"order": 0,
"userViewed": true,
"userViews": [{ "viewedDate": "2026-07-10T14:05:00.000Z" }]
}
]
}
],
"evaluations": [
{
"id": 4521,
"trainingId": 363,
"studentStartDate": "2026-06-01",
"studentEndDate": "2026-08-31",
"ValidityPeriod": "S",
"examStartDate": "2026-06-01",
"examEndDate": "2026-08-31",
"examDurationMinutes": 30,
"examAttempts": 3,
"minimumScorePercentage": 70,
"chapterEvaluation": "N",
"generalEvaluation": true,
"numberOfTries": 0,
"userEvaluations": []
}
]
}

Errores específicos:

Código Cuándo ocurre
404 El curso/evaluación no existe ("Capacitación no encontrada").
400 El período de estudio y de examen de la evaluación consultada ya finalizaron ("El período de estudio y evaluación ha finalizado"). Sólo aplica si ambas fechas (studentEndDate y examEndDate) están definidas y ya pasaron.

GET /me/training/active/:trainingId/evaluation/:evaluationId/quiz

Sección titulada «GET /me/training/active/:trainingId/evaluation/:evaluationId/quiz»

Genera el set de preguntas para rendir el quiz (mezcladas y, opcionalmente, filtradas por capítulo). Se debe llamar cada vez que el usuario abre el quiz — las preguntas y el orden de las respuestas cambian en cada llamada.

Path params: trainingId (number), evaluationId (number).

Query params:

Param Tipo Obligatorio Descripción
chapterId number Sólo si chapterEvaluation = S Capítulo a evaluar. Si el curso evalúa por capítulo y no se envía, el backend responde 400. Omitir si chapterEvaluation = N (evaluación general).

Response:

Campo Tipo Descripción
questionsAndAnswers QuizQuestionDto[] Preguntas a mostrar, ya mezcladas/filtradas/limitadas por el backend.
evaluationComplete object Metadatos del examen: { id, trainingId, studentStartDate, studentEndDate, finalValidityPeriod, examStartDate, examEndDate, examQuestionCount, examDurationMinutes, examAttempts, minimumScorePercentage, chapterEvaluation }.

questionsAndAnswers[]:

Campo Tipo Descripción
id number Id de la pregunta.
type enum VirtualTrainingQuestionTypeEnum SINGLE (una respuesta), MULTIPLE (varias), OPEN (texto libre).
text string Enunciado.
file string Archivo/imagen asociado a la pregunta (puede venir vacío).
answers QuizAnswerDto[] { questionId, id, text, type: "TEXT", image } — nunca incluye cuál es la correcta.
{
"questionsAndAnswers": [
{
"id": 1293,
"type": "SINGLE",
"text": "Un accidente cerebrovascular sucede cuando el flujo de sangre al cerebro se detiene por pocos segundos",
"file": "",
"answers": [
{ "questionId": 1293, "id": 3631, "text": "VERDADERO", "type": "TEXT", "image": "" },
{ "questionId": 1293, "id": 3632, "text": "FALSO", "type": "TEXT", "image": "" }
]
}
],
"evaluationComplete": {
"id": 683,
"trainingId": 273,
"studentStartDate": "2026-06-01",
"studentEndDate": "2026-08-31",
"finalValidityPeriod": "YES",
"examStartDate": "2026-06-01",
"examEndDate": "2026-08-31",
"examQuestionCount": 10,
"examDurationMinutes": 30,
"examAttempts": 3,
"minimumScorePercentage": 70,
"chapterEvaluation": "NOT"
}
}

Errores específicos:

Código Cuándo ocurre
404 La evaluación no existe, o el usuario no está asignado a ella ("Evaluation not found" / "Evaluation user not found").
400 Fuera del período de examen: "Evaluation has not started yet" o "Evaluation has ended" (según examStartDate/examEndDate).
400 El usuario ya agotó los intentos permitidos ("You have reached the maximum number of attempts"). Comparar numberOfTries vs examAttempts en el cliente para deshabilitar la acción antes de llamar.
400 chapterEvaluation = S y no se envió chapterId ("Chapter ID is required").

POST /me/training/active/:trainingId/evaluation/:evaluationId/quiz

Sección titulada «POST /me/training/active/:trainingId/evaluation/:evaluationId/quiz»

Envía las respuestas del usuario y calcula el resultado. Usa los mismos path params y el mismo query param opcional chapterId que el GET — debe coincidir con el quiz que se le mostró al usuario (mismo capítulo o evaluación general).

Body (SaveUserEvaluationQuizDto):

Campo Tipo Obligatorio Descripción
answers Record<number, string> Mapa questionId -> respuesta. Para SINGLE/OPEN: el valor como string ("3631" o el texto libre). Para MULTIPLE: ids separados por coma ("3631, 3632"). Preguntas sin respuesta: no es necesario omitirlas, pero si se envían vacías el backend las normaliza a "-1" (no contestada).

Response (objeto plano, sin envoltorio de paginación):

Campo Tipo Descripción
approval A / N A = aprobado, N = no aprobado (para el capítulo o la evaluación general, según el modo).
status A / F A = activo/pendiente (le quedan intentos y no aprobó), F = finalizado.
result number Nota obtenida (%), sobre las preguntas respondidas (no sobre el total del capítulo).
totalCorrectQuestions / totalIncorrectQuestions / totalUnansweredQuestions number Conteo del intento. En evaluación por capítulo, son los acumulados de todos los capítulos ya presentados, no sólo el actual.
isFinalEvaluation boolean true cuando ya no hay más capítulos pendientes de evaluar (o el curso no es por capítulos). Usar para decidir si mostrar el resultado como definitivo del curso o como resultado parcial de un capítulo.
{
"approval": "A",
"status": "F",
"result": 90,
"totalCorrectQuestions": 9,
"totalIncorrectQuestions": 1,
"totalUnansweredQuestions": 0,
"isFinalEvaluation": true
}

Errores específicos:

Código Cuándo ocurre
404 Evaluación no encontrada, o (en modo por capítulo) el chapterId no pertenece al curso ("Chapter not valid").
400 Mismas validaciones de fechas/intentos que el GET del quiz (fuera de período, intentos agotados).
400 answers contiene un questionId que no pertenece a esta evaluación, o un id de respuesta que no pertenece a la pregunta.

Marca un archivo/video de un capítulo como visto por el usuario. Debe llamarse cada vez que el usuario abre el material de un archivo (antes o al mismo tiempo que se abre el enlace), no sólo la primera vez — es idempotente.

Body (CreateRegisterUserViewFileDto):

Campo Tipo Obligatorio Descripción
trainingId number Id del curso.
evaluationId number Id de la evaluación del curso.
chapterId number Id del capítulo dueño del archivo.
fileId number Id del archivo marcado como visto.

Response: true (boolean).

Errores específicos:

Código Cuándo ocurre
404 El curso/evaluación (trainingId/evaluationId) no existe para este usuario — el endpoint valida esto internamente antes de registrar la vista, reutilizando la misma validación que GET active/:trainingId/evaluation/:evaluationId.
400 El período de estudio y evaluación del curso ya finalizó (misma regla que el GET de detalle).

Malla curricular: capacitaciones (con o sin evaluación formal) asignadas al cargo del usuario autenticado.

Query params:

Param Tipo Obligatorio Default Descripción
page number No 1 Página a consultar.
limit number No 5 Elementos por página.

Response — paginado:

Campo Tipo Descripción
id number Id de la capacitación.
name / description / objective / archive / image / link Datos del curso.
modality enum TrainingModalityEnum PRESENTIAL si link está vacío, E_LEARNING en caso contrario. Calculado por el backend, no persistido.
subcategory object { name, category: { name, type: { name, description } } }.
trainingDetails object Ver tabla siguiente — resumen del avance del usuario en esta capacitación.

trainingDetails:

Campo Tipo Descripción
trainingId number Id de la capacitación.
approvalStatus enum UserHistoryTrainingApprovalStatusEnum APPROVED, NOT_APPROVED, PENDING, NOT_REQUIRED. Ver tabla de estados en Lógica de cliente.
type string Tipo de capacitación.
score number Nota obtenida (si aplica).
registrationDate date Fecha de inscripción/registro.
{
"items": [
{
"id": 363,
"name": "PLAN DE EMERGENCIAS",
"description": "",
"objective": "Dar a conocer a los colaboradores el plan de emergencia anual de la compañía.",
"archive": "",
"image": "",
"link": "",
"modality": "PRESENTIAL",
"subcategory": {
"name": "SEGURIDAD Y SALUD",
"category": {
"name": "GESTION DE TALENTO HUMANO",
"type": { "name": "GENERAL" }
}
},
"trainingDetails": {
"trainingId": 363,
"approvalStatus": "PENDING",
"type": "GENERAL",
"score": 0,
"registrationDate": "2026-06-01T00:00:00.000Z"
}
}
],
"meta": {
"totalItems": 1,
"itemCount": 1,
"itemsPerPage": 5,
"totalPages": 1,
"currentPage": 1
}
}

Sin errores específicos adicionales a los comunes (requiere información organizacional, ver Prerrequisitos).

Detalle de una capacitación de la malla curricular: capítulos con su contenido y cargos recomendados.

Path param: id (number).

Response:

Campo Tipo Descripción
id number Id de la capacitación.
trainingId string Código string del curso.
name / description / link Datos del curso.
modality enum TrainingModalityEnum PRESENTIAL si no tiene link ni capítulos; E_LEARNING en caso contrario.
trainingPositions string[] Nombres de los cargos recomendados, ya limitados a un máximo de 3 y sin duplicados (el backend deduplica por nombre de cargo).
countRemainingPositions number Cantidad de cargos adicionales no incluidos en trainingPositions (para un texto tipo “+N cargos más”).
chapters ChapterDto[] { trainingId, id, name, text, content }text viene sanitizado (HTML seguro).
{
"id": 363,
"trainingId": "SSA-05",
"name": "PLAN DE EMERGENCIAS",
"description": "",
"modality": "PRESENTIAL",
"link": "",
"trainingPositions": ["Analista de Nómina", "Analista de RRHH", "Asistente Administrativo"],
"countRemainingPositions": 4,
"chapters": [
{
"trainingId": 363,
"id": 144,
"name": "MODULO 1. PROTOCOLO DE EVACUACIÓN",
"text": "<p>Contenido del capítulo...</p>",
"content": ""
}
]
}

Errores específicos:

Código Cuándo ocurre
404 La capacitación no existe ("Capacitación no encontrada").

Historial de capacitaciones del usuario, filtrable por tipo.

Query params:

Param Tipo Obligatorio Default Descripción
page number No 1 Página a consultar.
limit number No 5 Elementos por página.

Response — paginado:

Campo Tipo Descripción
approvalStatus enum UserHistoryTrainingApprovalStatusEnum Ver tabla de estados en Lógica de cliente.
score number Nota obtenida.
registrationDate date Fecha de registro/rendición.
name string Nombre de la capacitación.
code number Id interno de la capacitación (curso/evaluación/capacitación real, según referenceType).
description string Descripción.
type string Tipo de capacitación (catálogo).
category / subcategory string Categoría/subcategoría.
hasCertificate boolean true sólo si la capacitación tiene formato de certificado configurado y el usuario está APPROVED. Controla si se muestra la acción “Ver certificado”.
referenceId number Id a usar en history/certificate/:type/:id.
referenceType EV | CA | CU Tipo real de referencia (código corto del backend, no confundir con el :type de la URL).
realTrainingEvaluation S | N | U | null Sólo para referenceType = CA: cuantitativa/abierta/cualitativa.
{
"items": [
{
"approvalStatus": "APPROVED",
"score": 90,
"registrationDate": "2026-06-15",
"name": "SALUD PREVENTIVA VOLUMEN 1",
"code": 273,
"description": "PREVENCIÓN DE ENFERMEDADES CARDIOVASCULARES",
"type": "GENERAL",
"category": "GESTION DE TALENTO HUMANO",
"subcategory": "GESTION DE TALENTO HUMANO",
"hasCertificate": true,
"referenceId": 683,
"referenceType": "EV"
}
],
"meta": {
"totalItems": 1,
"itemCount": 1,
"itemsPerPage": 5,
"totalPages": 1,
"currentPage": 1
}
}

Errores específicos:

Código Cuándo ocurre
400 :type no coincide con ninguna clave del enum ("Invalid type: {valor enviado}").

GET /me/training/history/certificate/:type/:id

Sección titulada «GET /me/training/history/certificate/:type/:id»

Genera y devuelve la URL del certificado PDF de una capacitación del historial.

Path params:

Param Tipo Descripción
type string Misma convención de clave de enum que en history/:type — usar referenceType del ítem del historial mapeado a su clave (EVEVALUATION, CAREAL_TRAINING). No usar ALL aquí.
id number referenceId del ítem del historial.

Response: { "url": "https://.../certificate.pdf" } (URL prefirmada de S3, expira en 1 hora).

{
"url": "https://<bucket>.s3.amazonaws.com/capacitacion/certificadosgenerados/jperez-683-Certificado_SSA.pdf?X-Amz-Expires=3600&..."
}

Errores específicos:

Código Cuándo ocurre
400 El servicio legacy de generación de certificados falló ("Failed to generate training certificate: ..."). Tratar como error transitorio; reintentar u ofrecer soporte, no asumir que el certificado no existe.

Procedimientos de inducción asignados al cargo del usuario autenticado, con indicador de si ya fueron registrados.

Query params:

Param Tipo Obligatorio Default Descripción
page number No 1 Página a consultar.
limit number No 10 Elementos por página.

Response — paginado:

Campo Tipo Descripción
id number Id del procedimiento.
identifier string Código identificador del procedimiento.
name string Nombre del procedimiento.
userName string Nombre del dueño (fullName del usuario asociado, o cadena vacía).
inductionDate date | null Fecha en que el usuario registró haber recibido la inducción. null = pendiente.
url string URL del material del procedimiento.
hasNote boolean true si el usuario ya registró una fecha de inducción (tiene al menos un userProcedure).
{
"items": [
{
"id": 51,
"identifier": "PROC-INDUC-05",
"name": "PROTOCOLO DE SEGURIDAD EN PLANTA",
"userName": "Juan Pérez",
"inductionDate": null,
"url": "https://cdn.twiinshrm.com/procedures/proc-induc-05.pdf",
"hasNote": false
}
],
"meta": {
"totalItems": 1,
"itemCount": 1,
"itemsPerPage": 10,
"totalPages": 1,
"currentPage": 1
}
}

Sin errores específicos adicionales a los comunes (requiere información organizacional, ver Prerrequisitos).

Detalle completo de un procedimiento, incluyendo datos del dueño y período de vigencia.

Path param: id (number).

Response:

Campo Tipo Descripción
id / identifier / name / description Datos del procedimiento.
user object | null { fullName, position, avatar } del dueño/responsable.
startDate / endDate date Período de vigencia del procedimiento.
modificationDate date Última fecha de modificación.
inductionDate date | null Fecha registrada por el usuario (null = pendiente).
url string URL del material.
isEvaluated boolean true si el usuario ya registró la inducción (mismo criterio que hasNote en el listado).
{
"id": 51,
"identifier": "PROC-INDUC-05",
"name": "PROTOCOLO DE SEGURIDAD EN PLANTA",
"description": "Procedimiento de seguridad para personal de planta.",
"user": {
"fullName": "María Rojas",
"position": "Jefe de Seguridad Industrial",
"avatar": "https://cdn.twiinshrm.com/avatars/mrojas.png"
},
"startDate": "2026-01-01T00:00:00.000Z",
"endDate": "2026-12-31T00:00:00.000Z",
"modificationDate": "2026-06-01T00:00:00.000Z",
"inductionDate": null,
"url": "https://cdn.twiinshrm.com/procedures/proc-induc-05.pdf",
"isEvaluated": false
}

Sin errores específicos adicionales a los comunes.

Registra la fecha en que el usuario recibió la inducción de un procedimiento. Sólo puede registrarse una vez.

Body (UpdateInductionDateProcedureDto):

Campo Tipo Obligatorio Descripción
id number Id del procedimiento.
inductionDate date Fecha en que el usuario recibió la inducción. El portal de referencia la envía como YYYY-MM-DD.

Response: el procedimiento actualizado, misma forma que GET /me/training/procedures/:id.

Errores específicos:

Código Cuándo ocurre
404 El procedimiento no existe ("Procedure not found").
400 El usuario ya había registrado una fecha de inducción para este procedimiento ("Induction date procedure found"). El cliente debe evitar este caso ocultando la acción cuando hasNote/isEvaluated = true (ver Lógica de cliente).

Catálogo global de tipos de capacitación (no es un endpoint /me, no requiere contexto organizacional). Se consulta al abrir la pantalla de historial.

No recibe query params.

Response — array de:

Campo Tipo Descripción
id number Id del tipo.
name string Nombre.
description string Descripción.
status enum TrainingStatusEnum A activo, I inactivo, X eliminado.
[
{ "id": 1, "name": "GENERAL", "description": "Capacitación general", "status": "A" }
]

Sin errores específicos adicionales a los comunes.

Estados de aprobación (UserHistoryTrainingApprovalStatusEnum)

Sección titulada «Estados de aprobación (UserHistoryTrainingApprovalStatusEnum)»
Valor Significado backend Texto sugerido Color sugerido
APPROVED Aprobado Aprobado success / verde
NOT_APPROVED No aprobado No aprobado error / rojo
PENDING En proceso / aún no rinde En progreso warning / amarillo o info / azul
NOT_REQUIRED No requiere evaluación (curso CU completado) Realizado info / azul

Para score: si approvalStatus = NOT_REQUIRED, mostrar “No aplica” en vez de un porcentaje; si score es null/undefined, mostrar “–”.

Tipo de pregunta (VirtualTrainingQuestionTypeEnum)

Sección titulada «Tipo de pregunta (VirtualTrainingQuestionTypeEnum)»
Valor Significado Interacción sugerida
SINGLE Una sola respuesta correcta Selección única (radio); al marcar otra opción se reemplaza la anterior.
MULTIPLE Una o más respuestas correctas Selección múltiple (checkbox).
OPEN Respuesta de texto libre Campo de texto; no se corrige automáticamente (no cuenta para correctas/incorrectas).

Modalidad (TrainingModalityEnum, calculada por backend)

Sección titulada «Modalidad (TrainingModalityEnum, calculada por backend)»
Valor Significado
PRESENTIAL Sin link (y, en el detalle de malla curricular, sin capítulos).
E_LEARNING Tiene link o capítulos.

Tipo de referencia de capacitación (TrainingReferenceTypeEnum)

Sección titulada «Tipo de referencia de capacitación (TrainingReferenceTypeEnum)»
Código corto (referenceType) Clave de enum (usar en :type de la URL) Significado
EV EVALUATION Curso en línea con evaluación formal.
CA REAL_TRAINING Capacitación presencial/ejecutada.
CU VIRTUAL_TRAINING Curso en línea sin evaluación formal.
ALL Sólo válido para history/:type (todos los tipos); no usar en history/certificate.
  • Botón “Rendir quiz del capítulo”: deshabilitado mientras chapter.couldEvaluate = false. Un capítulo sin archivos nunca se habilita — si el curso tiene un capítulo sin material y evaluación por capítulo, esa evaluación queda inalcanzable desde el cliente; tratarlo como contenido mal configurado, no como bug de la app.
  • Botón “Rendir quiz del curso” (evaluación general): mostrar en el footer del detalle del curso sólo cuando evaluation.generalEvaluation === true; deshabilitar cuando attempts >= examAttempts.
  • Acción “Ver certificado” en el historial: mostrar sólo si hasCertificate === true.
  • Botón “Registrar” en el detalle de un procedimiento: mostrar sólo si hasNote/isEvaluated === false. Si ya está registrado, el footer debe ofrecer sólo “Cerrar”.
  • Selector de fecha de inducción: no permitir fecha vacía; habilitar “Guardar” recién cuando el usuario eligió una fecha.
  • Antes de habilitar “Rendir quiz” (curso o capítulo): numberOfTries < examAttempts y la fecha actual dentro de [examStartDate, examEndDate]. El backend valida lo mismo, pero repetir la validación en cliente evita un roundtrip con 400.
  • Antes de armar el body del POST del quiz: recorrer todas las preguntas mostradas y construir answers con el formato esperado por tipo (ver tabla del endpoint POST .../quiz); no enviar ids que no vinieron en el GET de ese mismo quiz — un intento de reenviar un questionId obsoleto de un intento anterior responde 400.
  • Antes de abrir un archivo del capítulo, llamar PUT /me/training/active/file — el detalle del curso no refleja couldEvaluate = true hasta que todos los archivos del capítulo estén marcados como vistos.
  • PUT /me/training/procedures: sólo enviar si hasNote/isEvaluated === false; reenviar sobre un procedimiento ya registrado siempre responde 400.
  • Sin cursos activos: GET /me/training/active responde 404 (no 200 con array vacío). El cliente debe interceptar ese 404 específico de este endpoint y mostrarlo como estado vacío (“No tienes capacitaciones activas”), no como error genérico.
  • Sin capacitaciones en la malla curricular / sin procedimientos / sin historial: estos tres sí siguen la convención estándar, 200 con items: [] — mostrar estado vacío normal.
  • Curso vencido: si GET active/:trainingId/evaluation/:evaluationId responde 400 con el mensaje de período finalizado, no reintentar automáticamente; mostrar el curso como no disponible y sugerir volver al listado (donde ya no debería aparecer en la próxima carga, dado que las fechas están vencidas).
  • Reprobó y se resetean los archivos vistos: después de un POST de quiz fallido que dispara el reseteo de archivos (ver caution en ese endpoint), refrescar el detalle del curso (GET active/:trainingId/evaluation/:evaluationId) para reflejar couldEvaluate = false y userViewed = false en los archivos afectados, en vez de asumir que el estado anterior sigue vigente.
  • Evaluación general vs. por capítulo: no asumir un único flujo — leer chapterEvaluation/generalEvaluation de cada evaluación antes de decidir si se muestra un botón de quiz por capítulo o uno solo para todo el curso.