Saltar a contenido

API Incidencias de Fichaje v2

Documentación de endpoints para la gestión de incidencias de fichaje (check-in incidents).

GET /api/v2/incident/

Obtiene el listado paginado de incidencias y estadísticas globales.

  • Auth: Authorization: Bearer <token>
  • Query Params:
  • status (opcional): "open" | "closed" - Filtra el listado por estado
  • limit (opcional): number - Límite de resultados (default: todos)
  • offset (opcional): number - Offset para paginación (default: 0)
  • schoolCourseId (opcional): number - Filtra por curso escolar
  • search (opcional): string - Búsqueda por nombre/apellido de empleado o descripción
  • startDate (opcional): ISO date string - Fecha de inicio para filtrar (ej: 2026-01-01)
  • endDate (opcional): ISO date string - Fecha de fin (si no se especifica, filtra desde startDate hasta hoy)
  • incidentType (opcional): string - Tipo de incidencia (EARLY_EXIT, OUT_OF_RANGE, NO_SCHEDULE_TODAY, OUT_OF_SCHEDULE_WINDOW)

Ejemplo

curl -X GET "$HOST/api/v2/incident/?status=open&limit=10&offset=0&search=Juan&startDate=2026-01-01" \
  -H "Authorization: Bearer $TOKEN"

Respuesta (200)

{
  "status": "success",
  "data": {
    "incidents": [
      {
        "id": 1,
        "description": "Fichaje fuera de horario",
        "status": "open",
        "reviewStatus": "underReview",
        "incidentType": "OUT_OF_SCHEDULE_WINDOW",
        "timeRecordId": 456,
        "employeeId": 123,
        "schoolCourseId": 1,
        "createdAt": "2026-01-27T10:00:00.000Z",
        "updatedAt": "2026-01-27T10:00:00.000Z",
        "employee": {
          "id": 123,
          "name": "Juan",
          "lastName": "Pérez"
        }
      }
    ]
  },
  "counts": {
    "total": 50,
    "open": 15,
    "inReview": 8,
    "closed": 35
  },
  "pagination": {
    "totalItems": 15,
    "limit": 10,
    "offset": 0
  }
}

Campos de Respuesta

Campo Descripción
data.incidents Array de incidencias filtradas y paginadas
counts.total Total de incidencias (sin filtros de estado)
counts.open Incidencias con status = 'open'
counts.inReview Incidencias con status = 'open' AND reviewStatus = 'underReview'
counts.closed Incidencias con status = 'closed'
pagination.totalItems Total de items que coinciden con el filtro actual
pagination.limit Límite usado en la consulta
pagination.offset Offset usado en la consulta

Notas

  • Los contadores (counts) son globales y no se ven afectados por el filtro status. Esto permite mostrar los números de las "tabs" (Todas, Abiertas, En Revisión, Cerradas) mientras se filtra el listado.
  • Si se proporciona schoolCourseId, los contadores también se filtran por ese curso.
  • El campo inReview es un subconjunto de open (incidencias abiertas que están bajo revisión).

GET /api/v2/incident/my

Obtiene las incidencias del empleado autenticado.

  • Auth: Authorization: Bearer <token>
  • Query Params:
  • status (opcional): "open" | "closed"
  • limit (opcional): number
  • offset (opcional): number

Ejemplo

curl -X GET "$HOST/api/v2/incident/my?status=open" \
  -H "Authorization: Bearer $TOKEN"

Respuesta (200)

{
  "status": "success",
  "data": {
    "incidents": [...]
  },
  "counts": {
    "total": 5,
    "open": 2,
    "inReview": 1,
    "closed": 3
  }
}

GET /api/v2/incident/:id

Obtiene el detalle de una incidencia por ID.

  • Auth: Authorization: Bearer <token>
  • Params: id - ID de la incidencia

Ejemplo

curl -X GET "$HOST/api/v2/incident/123" \
  -H "Authorization: Bearer $TOKEN"

Respuesta (200)

{
  "status": "success",
  "data": {
    "incident": {
      "id": 123,
      "description": "...",
      "status": "open",
      "reviewStatus": "underReview",
      "incidentType": "EARLY_EXIT",
      "employee": {...},
      "incidentThreads": [...],
      "incidentFiles": [...]
    }
  }
}

Eventos Socket.IO

El backend emite un único evento global incident_notification en la sala correspondiente. El frontend distingue el tipo de notificación por el campo type en la data.

Evento: incident_notification

Salas de escucha: - admins - Para administradores - employee:{id} - Para un empleado específico - incident_chat:{id} - Para el chat de una incidencia

Tipos de Notificación (campo type)

Tipo Destino Descripción
new_incident admins Nueva incidencia creada
new_message admins, incident_chat Empleado envió mensaje
incident_resolved admins Incidencia cerrada
admin_reply employee, incident_chat Admin respondió al hilo
status_changed employee Cambio de estado de incidencia

Payload

interface IncidentNotificationPayload {
  type: "new_incident" | "new_message" | "admin_reply" | "status_changed" | "incident_resolved";
  incidentId: number;
  employeeId?: number;
  employeeName?: string;
  incidentType?: string;
  message?: string;       // Mensaje completo (solo en chat)
  preview?: string;       // Primeros 100 caracteres
  senderType?: "user" | "admin";
  status?: string;
  reviewStatus?: string;
  timestamp: Date;
  data?: {
    checkInType?: "start" | "end";
    adminName?: string;
    changedBy?: "admin" | "system";
  };
}

Cómo conectarse

// Conectarse y unirse a salas
socket.emit("join", { employeeId: 123 }); // Auto-join a "admins" si tiene rol

// Unirse a chat de incidencia
socket.emit("join_incident_chat", { incidentId: 456 });

// Escuchar un solo evento y filtrar por type
socket.on("incident_notification", (data) => {
  switch (data.type) {
    case "new_incident":
      console.log("Nueva incidencia:", data);
      break;
    case "admin_reply":
      console.log("Admin respondió:", data);
      break;
    // ... otros tipos
  }
});

Tipos de Incidencia (incidentType)

Los siguientes son los valores posibles para el campo incidentType, usados tanto para filtrar como para mostrar en el frontend:

Incidencias de Fichaje (creadas automáticamente al fichar con errores)

Valor Descripción (Frontend) Cuándo se genera
early_exit Salida anticipada Empleado sale antes de que termine su última clase
out_of_schedule Fuera de horario Entrada fuera del rango de tolerancia antes de la primera clase
no_schedule Sin clases programadas No hay eventos/clases para ese día
out_of_range Fuera de rango permitido Fichaje desde una ubicación fuera del radio del centro

Incidencias Automáticas (generadas por el cron)

Valor Descripción (Frontend) Cuándo se genera
missing_checkin_entry Falta fichaje de entrada Empleado tenía clase pero no fichó entrada
missing_checkin_exit Falta fichaje de salida Empleado fichó entrada pero no fichó salida
missing_checkin_both Falta entrada y salida Empleado no fichó ni entrada ni salida
no_exit_registered Salida no registrada El cron cerró automáticamente un fichaje abierto
missingClockIn Fichaje faltante Verificación detectó fichaje faltante

Otros Tipos

Valor Descripción (Frontend) Uso
no_events_today Sin eventos hoy Incidencia manual creada por el empleado
general_issue Problema general Valor por defecto si no se especifica tipo

Relacionado: - API Fichaje v2 - Errores de fichaje