Skip to content

Logs / Auditoría

Logs / Auditoría

Prefijo: /api/logs
Requiere Auth: Sí
Permiso requerido: configuracion, *

Módulo de auditoría que registra eventos importantes del sistema: inicios de sesión (LOGIN_EXITOSO, LOGIN_FALLIDO), cambios de contraseña (USUARIO_PASSWORD_CAMBIO), cambios de rol (USUARIO_ROL_CAMBIO), eliminación de ventas (VENTA_ELIMINADA), cambios de precio (PRODUCTO_PRECIO_CAMBIO). El endpoint /api/logs/global es exclusivo para Superadmin (rol=3) y permite ver logs de todos los tenants.

Schema: LogAuditoria — cada log contiene: id, tenant_id, timestamp, nivel, modulo, accion, usuario, id_referencia, mensaje, stacktrace, clase_origen, metodo_origen, linea_origen, hilo, ip_equipo, datos_extra, valor_anterior, valor_nuevo, correlation_id, request_id, entity_type.


GET /api/logs/

Descripción: Lista los logs de auditoría del tenant autenticado con paginación y filtros opcionales por módulo, tipo de acción, nivel, correlation_id y más. Ideal para auditoría de cambios, investigación de incidentes y cumplimiento normativo.
Requiere Auth: Sí
Permiso requerido: configuracion, leer

Parámetros query:

ParámetroTipoObligatorioDescripciónValores válidos / Ejemplo
skipint❌Registros a saltar (paginación)default: 0
limitint❌Máximo a retornardefault: 20, max: 100
tablastring❌Filtrar por módulo que generó el logusuarios, productos, ventas, clientes, caja, creditos
tipostring❌Filtrar por tipo de acciónLOGIN_EXITOSO, LOGIN_FALLIDO, VENTA_MODIFICADA, CREACION_PRODUCTO, RBAC_DENEGADO, ERROR_API, etc.
nivelstring❌Filtrar por nivel de severidadINFO, WARNING, ERROR
correlation_idstring❌Filtrar por ID de operación completa (UUID)uuid-correlation
entity_typestring❌Filtrar por tipo de entidadventas, productos, usuarios, caja, permisos_rol
fechadate❌Filtrar por fecha exacta2026-09-01
busquedastring❌Búsqueda en mensaje/usuarioTexto libre

Comportamiento / Casos de uso:

  • Auditoría de cambios: ¿quién modificó el precio del producto X y cuándo?
  • Investigación de incidentes: buscar logs de LOGIN_FALLIDO para detectar fuerza bruta
  • Cumplimiento: exportar logs de USUARIO_ROL_CAMBIO para revisión de accesos
  • Trazabilidad: buscar por correlation_id para ver toda la operación de una venta
  • Filtrar errores: buscar por nivel=ERROR para diagnosticar fallas
  • Sin filtros: retorna los 20 logs más recientes del tenant ordenados por timestamp descendente
  • Los filtros se combinan con AND lógico

Respuesta exitosa: 200 OK

Response:

[
{
"id": 1,
"tenant_id": "uuid-tenant",
"timestamp": "2026-09-01T10:30:00",
"nivel": "INFO",
"modulo": "ventas",
"accion": "VENTA_LOCAL",
"usuario": "juan@tienda.com",
"id_referencia": 379,
"mensaje": "Venta #379 por juan: total $72,000, recibido $100,000, vuelto $28,000, medio Efectivo, tipo Local",
"stacktrace": null,
"clase_origen": "VentaService",
"metodo_origen": "create",
"linea_origen": 278,
"hilo": "MainThread",
"ip_equipo": "192.168.1.10",
"datos_extra": null,
"valor_anterior": null,
"valor_nuevo": "{\"id\": 379, \"total\": 72000, \"montoRecibido\": 100000, \"vueltos\": 28000, \"medioPago\": \"Efectivo\", \"tipoPago\": \"Local\", \"vendedor\": \"juan\", \"id_cliente\": 5, \"fecha\": \"2026-09-01\", \"idempotency_key\": \"sale-uuid-abc\"}",
"correlation_id": "sale-uuid-abc",
"request_id": "req-uuid-123",
"entity_type": "ventas"
}
]

Errores:

CódigoCausaSolución
401Token inválido/expiradoRe-login
403Sin permiso configuracion, leerSolicitar a admin

cURL:

Terminal window
curl "http://localhost/api/logs/?skip=0&limit=20&tabla=productos&tipo=ACTUALIZACION_PRODUCTO" -H "Authorization: Bearer <token>"

Python:

import httpx
resp = httpx.get("http://localhost/api/logs/",
params={"skip": 0, "limit": 20, "tabla": "productos", "tipo": "ACTUALIZACION_PRODUCTO"},
headers={"Authorization": f"Bearer {token}"})
logs = resp.json()

JavaScript:

const params = new URLSearchParams({skip: '0', limit: '20', tabla: 'productos', tipo: 'ACTUALIZACION_PRODUCTO'});
const resp = await fetch(`http://localhost/api/logs/?${params}`, {
headers: {'Authorization': `Bearer ${token}`}
});
const logs = await resp.json();

GET /api/logs/:log_id

Descripción: Obtiene el detalle completo de un log de auditoría específico por ID. Para investigación detallada de un evento puntual.
Requiere Auth: Sí
Permiso requerido: configuracion, leer

Parámetros path:

ParámetroTipoObligatorioDescripción
log_idint✅ID del log de auditoría

Comportamiento / Casos de uso:

  • Investigación forense: ver todos los campos del log incluyendo stacktrace y datos_extra
  • Verificación: confirmar qué usuario realizó una acción específica

Respuesta exitosa: 200 OK

Response: (mismo schema que GET /api/logs/)

Errores:

CódigoCausaSolución
404Log no encontradoVerificar log_id
403Sin permiso configuracion, leerSolicitar a admin

cURL:

Terminal window
curl http://localhost/api/logs/1 -H "Authorization: Bearer <token>"

GET /api/logs/count

Descripción: Cuenta el total de logs del tenant con los mismos filtros opcionales que GET /api/logs/. Diseñado para paginación del frontend: primero se llama /count para saber cuántos registros hay, luego se llama /api/logs/ con skip y limit para la página actual.
Requiere Auth: Sí
Permiso requerido: configuracion, leer

Parámetros query:

ParámetroTipoObligatorioDescripciónValores válidos
fechadate❌Filtrar por fecha exacta (YYYY-MM-DD)2026-07-28
modulostring❌Filtrar por móduloproductos, ventas, usuarios, etc.
nivelstring❌Filtrar por nivel de severidadINFO, WARNING, ERROR, DEBUG
busquedastring❌Búsqueda en mensaje/usuarioTexto libre

Comportamiento / Casos de uso:

  1. Frontend muestra “Total de logs: 1,234”
  2. Calcula número de páginas: Math.ceil(count / limit)
  3. Renderiza paginador

Respuesta exitosa: 200 OK

Response:

{
"count": 42
}

Errores: 401, 403 (igual que GET /api/logs/)

cURL:

Terminal window
curl "http://localhost/api/logs/count?modulo=productos&nivel=ERROR&fecha=2026-07-28" -H "Authorization: Bearer <token>"

GET /api/logs/modulos

Descripción: Lista los módulos que tienen logs registrados en el tenant. Útil para poblar select/filtro de módulo en el frontend.
Requiere Auth: Sí
Permiso requerido: configuracion, leer

Comportamiento / Casos de uso:

  • Poblar dropdown “Filtrar por módulo” en panel de auditoría
  • Solo retorna módulos que realmente tienen logs en el tenant

Respuesta exitosa: 200 OK

Response:

[
"usuarios",
"productos",
"ventas",
"clientes",
"caja",
"creditos"
]

Errores: 401, 403

cURL:

Terminal window
curl http://localhost/api/logs/modulos -H "Authorization: Bearer <token>"

GET /api/logs/tabla/:tabla/ref/:id_referencia

Descripción: Obtiene logs filtrados por tabla (módulo) y ID de referencia específico. Para trazabilidad completa de una entidad: ver todo el historial de cambios de una venta, producto, usuario, etc.
Requiere Auth: Sí
Permiso requerido: configuracion, leer

Parámetros path:

ParámetroTipoObligatorioDescripción
tablastring✅Nombre del módulo/tabla
id_referenciaint✅ID de la entidad referenciada

Comportamiento / Casos de uso:

  • Historial de una venta: ver quién la creó, modificó, anuló
  • Trazabilidad de producto: ver cambios de precio, stock, descripción
  • Auditoría de usuario: ver cambios de rol, contraseña, datos

Respuesta exitosa: 200 OK

Response: Array de LogAuditoria (mismo schema que GET /api/logs/)

Errores:

CódigoCausaSolución
404No hay logs para esa tabla/IDVerificar tabla e id_referencia
403Sin permiso configuracion, leerSolicitar a admin

cURL:

Terminal window
curl http://localhost/api/logs/tabla/ventas/ref/15 -H "Authorization: Bearer <token>"

POST /api/logs/

Descripción: Crea un nuevo log de auditoría manual. Útil para registrar eventos personalizados, migraciones de datos, o integraciones externas que necesiten dejar trazabilidad.
Requiere Auth: Sí
Permiso requerido: configuracion, crear

Request:

{
"timestamp": "2026-07-28T22:00:00",
"nivel": "INFO",
"modulo": "productos",
"accion": "CREACION_PRODUCTO",
"usuario": "admin",
"id_referencia": 1,
"mensaje": "Producto creado exitosamente",
"ip_equipo": "192.168.1.1"
}

Campos:

CampoTipoObligatorioDescripciónValores válidos
timestampdatetime✅Fecha/hora del evento (hora Colombia)ISO 8601: 2026-07-28T22:00:00
nivelstring✅SeveridadINFO, WARNING, ERROR, DEBUG
modulostring✅Módulo origenusuarios, productos, ventas, caja, creditos, etc.
accionstring✅Tipo de acciónVer lista completa abajo
usuariostring✅Usuario que realizó la acciónEmail o nombre
id_referenciaint❌ID de la entidad afectadaID de venta, producto, etc.
mensajestring❌Descripción legibleTexto libre
ip_equipostring❌IP del equipo192.168.1.1
valor_anteriorstring❌Estado ANTES del cambio (JSON serializado){"precio": 5000}
valor_nuevostring❌Estado DESPUÉS del cambio (JSON serializado){"precio": 5500}
correlation_idstring❌ID que agrupa logs de una operación de negocio completaUUID
request_idstring❌ID de la petición HTTP (X-Request-ID)UUID
entity_typestring❌Tipo de entidad afectadaventas, productos, usuarios, etc.

Acciones válidas (accion):

CategoríaAcciones
AutenticaciónLOGIN_EXITOSO, LOGIN_FALLIDO
UsuariosUSUARIO_CREACION, USUARIO_ACTUALIZACION, USUARIO_ELIMINACION, USUARIO_PASSWORD_CAMBIO, USUARIO_ROL_CAMBIO
ProductosCREACION_PRODUCTO, ACTUALIZACION_PRODUCTO, ELIMINACION_PRODUCTO, PRODUCTO_PRECIO_CAMBIO, PRODUCTO_STOCK_CAMBIO, ACTUALIZACION_STOCK
VentasVENTA_CREACION, VENTA_ELIMINACION, VENTA_ABONO, VENTA_FACTURACION, VENTA_MODIFICADA, VENTA_ELECTRONICA, VENTA_LOCAL
CajaAPERTURA_CAJA, CIERRE_CAJA, APERTURA_JORNADA, CIERRE_JORNADA
CréditosCREDITO_CREACION, CREDITO_PAGO, CREDITO_RECONCILIACION
ConfigCONFIGURACION_CAMBIO
SeguridadRBAC_DENEGADO (nivel WARNING), ERROR_API (nivel ERROR)

Respuesta exitosa: 201 Created

Response:

{
"id": 123,
"tenant_id": "uuid-tenant",
"timestamp": "2026-07-28T22:00:00",
"nivel": "INFO",
"modulo": "productos",
"accion": "CREACION_PRODUCTO",
"usuario": "admin",
"id_referencia": 1,
"mensaje": "Producto creado exitosamente",
"stacktrace": null,
"clase_origen": "Manual",
"metodo_origen": "POST /api/logs/",
"linea_origen": 0,
"hilo": "MainThread",
"ip_equipo": "192.168.1.1",
"datos_extra": null,
"valor_anterior": null,
"valor_nuevo": "{\"nombre\": \"Producto Nuevo\", \"precio\": 5000}",
"correlation_id": null,
"request_id": null,
"entity_type": "productos"
}

Errores:

CódigoCausaSolución
400Campos obligatorios faltantesVerificar timestamp, nivel, modulo, accion, usuario
403Sin permiso configuracion, crearSolicitar a admin

cURL:

Terminal window
curl -X POST http://localhost/api/logs/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"timestamp":"2026-07-28T22:00:00","nivel":"INFO","modulo":"productos","accion":"CREACION_PRODUCTO","usuario":"admin","id_referencia":1,"mensaje":"Producto creado exitosamente","ip_equipo":"192.168.1.1"}'

Python:

import httpx
resp = httpx.post("http://localhost/api/logs/",
json={"timestamp": "2026-07-28T22:00:00", "nivel": "INFO", "modulo": "productos",
"accion": "CREACION_PRODUCTO", "usuario": "admin", "id_referencia": 1,
"mensaje": "Producto creado exitosamente", "ip_equipo": "192.168.1.1"},
headers={"Authorization": f"Bearer {token}"})
log = resp.json()

JavaScript:

const resp = await fetch('http://localhost/api/logs/', {
method: 'POST',
headers: {'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`},
body: JSON.stringify({timestamp: '2026-07-28T22:00:00', nivel: 'INFO', modulo: 'productos',
accion: 'CREACION_PRODUCTO', usuario: 'admin', id_referencia: 1,
mensaje: 'Producto creado exitosamente', ip_equipo: '192.168.1.1'})
});
const log = await resp.json();

GET /api/logs/global

Descripción: Lista logs de auditoría de TODOS los tenants (cross-tenant). Acceso exclusivo para Superadmin (rol=3). Permite al soporte centralizado monitorear actividad, detectar anomalías y auditar tenants sin entrar a cada uno.
Requiere Auth: Sí (rol=3 Superadmin obligatorio)
Permiso requerido: N/A (solo Superadmin)

Parámetros query:

ParámetroTipoObligatorioDescripciónValores válidos
skipint❌Registros a saltardefault: 0
limitint❌Máximo a retornardefault: 50, max: 100
tenant_idUUID❌Filtrar por tenant específicoUUID del tenant
tablastring❌Filtrar por móduloproductos, ventas, usuarios, etc.
tipostring❌Filtrar por acciónVer lista completa en GET /api/logs/
nivelstring❌Filtrar por nivel de severidadINFO, WARNING, ERROR
correlation_idstring❌Filtrar por correlation_id (operación completa)UUID
entity_typestring❌Filtrar por tipo de entidadventas, productos, usuarios, etc.

Comportamiento / Casos de uso:

  • Soporte centralizado: ver actividad sospechosa en todos los tenants
  • Auditoría cross-tenant: detectar patrones de abuso o errores sistémicos
  • Solo Superadmin (rol=3) — Admin (rol=1) y Asistente (rol=2) reciben 403

Respuesta exitosa: 200 OK

Response: Array de LogAuditoria con campo tenant_id visible para identificar el tenant origen.

Errores:

CódigoCausaSolución
403No es Superadmin (rol ≠ 3)Usar usuario con rol Superadmin

cURL:

Terminal window
curl "http://localhost/api/logs/global?skip=0&limit=50&tabla=usuarios&tipo=LOGIN_FALLIDO" -H "Authorization: Bearer <token>"

Python:

import httpx
resp = httpx.get("http://localhost/api/logs/global",
params={"skip": 0, "limit": 50, "tabla": "usuarios", "tipo": "LOGIN_FALLIDO"},
headers={"Authorization": f"Bearer {token}"})
logs = resp.json()

Auditoría Automática

El backend registra automáticamente eventos de auditoría en LogAuditoria para las siguientes operaciones:

OperaciónNivelCampos populateados
Crear ventaINFOvalor_nuevo con total, montoRecibido, vueltos, medioPago, tipoPago
Modificar ventaINFOvalor_anterior + valor_nuevo (before/after snapshot)
Eliminar ventaINFOvalor_anterior + valor_nuevo con estado=ELIMINADO
Crear productoINFOvalor_nuevo con datos del producto
Eliminar productoINFOvalor_anterior + valor_nuevo
Actualizar stockINFOvalor_anterior + valor_nuevo con stock viejo/nuevo
Apertura/Cierre cajaINFOvalor_nuevo con montos de la operación
Error global (HTTP 500)ERRORstacktrace, clase_origen, metodo_origen, linea_origen automáticos
RBAC denegado (403)WARNINGmensaje con descripción del permiso faltante
Cualquier request HTTP—Request logging en stdout con method, path, status, duration, request_id

Campos de correlación

  • correlation_id: Agrupa todos los logs de una operación de negocio completa (ej: una venta completa desde Java hasta la BD). Útil para trazabilidad end-to-end. El cliente Java genera un UUID por cada venta (saleUuid) y lo envía como correlation_id en cada log de la operación.
  • request_id: ID de la petición HTTP (header X-Request-ID). Enlaza el log con la petición específica que lo generó. El cliente Java envía X-Request-ID en cada petición HTTP.
  • entity_type: Tipo explícito de entidad afectada (ventas, productos, usuarios, etc.). Facilita búsquedas por tipo de entidad.
  • terminal_id: Identificador del dispositivo POS que generó el log. El cliente Java lo obtiene de TerminalIdentity y lo incluye en cada log enviado al API.

Flujo de correlación Java → API

1. Usuario hace clic en "Cobrar"
2. Java genera correlation_id = saleUuid (UUID único por carrito)
3. Java envía POST /api/ventas/ con idempotency_key = saleUuid
4. Java registra logs con correlation_id y terminal_id
5. HttpAppender envía cada log a POST /api/logs/ con correlation_id y terminal_id
6. Backend almacena correlation_id en LogAuditoria
7. Consulta: GET /api/logs/?correlation_id=<saleUuid> muestra toda la operación

Cómo consultar logs de una venta específica

Terminal window
# 1. Obtener logs por tabla + ID de referencia
curl http://localhost/api/logs/tabla/ventas/ref/15 -H "Authorization: Bearer <token>"
# 2. Filtrar por correlation_id (operación completa — todos los logs de la venta)
curl "http://localhost/api/logs/?correlation_id=uuid-correlation" -H "Authorization: Bearer <token>"
# 3. Filtrar por entity_type + nivel (ej: errores en ventas)
curl "http://localhost/api/logs/?entity_type=ventas&nivel=ERROR" -H "Authorization: Bearer <token>"
# 4. Filtrar por fecha + búsqueda (ej: ventas del día con "Efectivo" en el mensaje)
curl "http://localhost/api/logs/?fecha=2026-09-01&busqueda=Efectivo" -H "Authorization: Bearer <token>"
# 5. Ver before/after de un cambio específico
# El campo valor_anterior contiene el estado ANTES, valor_nuevo el DESPUÉS
# 6. Logs de RBAC denegados (nivel=WARNING)
curl "http://localhost/api/logs/?nivel=WARNING&entity_type=permisos_rol" -H "Authorization: Bearer <token>"
# 7. Errores globales del API (nivel=ERROR)
curl "http://localhost/api/logs/?nivel=ERROR&tabla=sistema" -H "Authorization: Bearer <token>"