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.
GET /api/logs/
Descripción: Lista los logs de auditoría del tenant autenticado con paginación y filtros opcionales por módulo y tipo de acción. Ideal para auditoría de cambios, investigación de incidentes y cumplimiento normativo.
Requiere Auth: Sí
Permiso requerido: configuracion, leer
Parámetros query:
| Parámetro | Tipo | Obligatorio | Descripción | Valores válidos / Ejemplo |
|---|---|---|---|---|
skip | int | ❌ | Registros a saltar (paginación) | default: 0 |
limit | int | ❌ | Máximo a retornar | default: 20, max: 100 |
tabla | string | ❌ | Filtrar por módulo que generó el log | usuarios, productos, ventas, clientes, caja, creditos |
tipo | string | ❌ | Filtrar por tipo de acción | LOGIN_EXITOSO, LOGIN_FALLIDO, USUARIO_PASSWORD_CAMBIO, USUARIO_ROL_CAMBIO, VENTA_ELIMINADA, PRODUCTO_PRECIO_CAMBIO, CREACION_PRODUCTO, ACTUALIZACION_PRODUCTO, ELIMINACION_PRODUCTO, etc. |
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_FALLIDOpara detectar fuerza bruta - Cumplimiento: exportar logs de
USUARIO_ROL_CAMBIOpara revisión de accesos - 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-07-28T10:00:00", "nivel": "INFO", "modulo": "productos", "accion": "ACTUALIZACION_PRODUCTO", "usuario": "admin@neoapp.com", "id_referencia": 15, "mensaje": "Precio actualizado de 5000 a 5500", "stacktrace": null, "clase_origen": "ProductoService", "metodo_origen": "update", "linea_origen": 45, "hilo": "MainThread", "ip_equipo": "192.168.1.1", "datos_extra": null }]Errores:
| Código | Causa | Solución |
|---|---|---|
| 401 | Token inválido/expirado | Re-login |
| 403 | Sin permiso configuracion, leer | Solicitar a admin |
cURL:
curl "http://localhost/api/logs/?skip=0&limit=20&tabla=productos&tipo=ACTUALIZACION_PRODUCTO" -H "Authorization: Bearer <token>"Python:
import httpxresp = 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ámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
log_id | int | ✅ | 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ódigo | Causa | Solución |
|---|---|---|
| 404 | Log no encontrado | Verificar log_id |
| 403 | Sin permiso configuracion, leer | Solicitar a admin |
cURL:
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ámetro | Tipo | Obligatorio | Descripción | Valores válidos |
|---|---|---|---|---|
fecha | date | ❌ | Filtrar por fecha exacta (YYYY-MM-DD) | 2026-07-28 |
modulo | string | ❌ | Filtrar por módulo | productos, ventas, usuarios, etc. |
nivel | string | ❌ | Filtrar por nivel de severidad | INFO, WARNING, ERROR, DEBUG |
busqueda | string | ❌ | Búsqueda en mensaje/usuario | Texto libre |
Comportamiento / Casos de uso:
- Frontend muestra “Total de logs: 1,234”
- Calcula número de páginas: Math.ceil(count / limit)
- Renderiza paginador
Respuesta exitosa: 200 OK
Response:
{ "count": 42}Errores: 401, 403 (igual que GET /api/logs/)
cURL:
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:
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ámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
tabla | string | ✅ | Nombre del módulo/tabla |
id_referencia | int | ✅ | 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ódigo | Causa | Solución |
|---|---|---|
| 404 | No hay logs para esa tabla/ID | Verificar tabla e id_referencia |
| 403 | Sin permiso configuracion, leer | Solicitar a admin |
cURL:
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:
| Campo | Tipo | Obligatorio | Descripción | Valores válidos |
|---|---|---|---|---|
timestamp | datetime | ✅ | Fecha/hora del evento (hora Colombia) | ISO 8601: 2026-07-28T22:00:00 |
nivel | string | ✅ | Severidad | INFO, WARNING, ERROR, DEBUG |
modulo | string | ✅ | Módulo origen | usuarios, productos, ventas, caja, creditos, etc. |
accion | string | ✅ | Tipo de acción | Ver lista completa abajo |
usuario | string | ✅ | Usuario que realizó la acción | Email o nombre |
id_referencia | int | ❌ | ID de la entidad afectada | ID de venta, producto, etc. |
mensaje | string | ❌ | Descripción legible | Texto libre |
ip_equipo | string | ❌ | IP del equipo | 192.168.1.1 |
Acciones válidas (accion):
| Categoría | Acciones |
|---|---|
| Autenticación | LOGIN_EXITOSO, LOGIN_FALLIDO |
| Usuarios | USUARIO_CREACION, USUARIO_ACTUALIZACION, USUARIO_ELIMINACION, USUARIO_PASSWORD_CAMBIO, USUARIO_ROL_CAMBIO |
| Productos | CREACION_PRODUCTO, ACTUALIZACION_PRODUCTO, ELIMINACION_PRODUCTO, PRODUCTO_PRECIO_CAMBIO, PRODUCTO_STOCK_CAMBIO |
| Ventas | VENTA_CREACION, VENTA_ELIMINACION, VENTA_ABONO, VENTA_FACTURACION |
| Caja | APERTURA_CAJA, CIERRE_CAJA, APERTURA_JORNADA, CIERRE_JORNADA |
| Créditos | CREDITO_CREACION, CREDITO_PAGO, CREDITO_RECONCILIACION |
| Config | CONFIGURACION_CAMBIO |
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}Errores:
| Código | Causa | Solución |
|---|---|---|
| 400 | Campos obligatorios faltantes | Verificar timestamp, nivel, modulo, accion, usuario |
| 403 | Sin permiso configuracion, crear | Solicitar a admin |
cURL:
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 httpxresp = 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ámetro | Tipo | Obligatorio | Descripción | Valores válidos |
|---|---|---|---|---|
skip | int | ❌ | Registros a saltar | default: 0 |
limit | int | ❌ | Máximo a retornar | default: 50, max: 100 |
tenant_id | UUID | ❌ | Filtrar por tenant específico | UUID del tenant |
tabla | string | ❌ | Filtrar por módulo | productos, ventas, usuarios, etc. |
tipo | string | ❌ | Filtrar por acción | Ver lista completa en GET /api/logs/ |
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ódigo | Causa | Solución |
|---|---|---|
| 403 | No es Superadmin (rol ≠ 3) | Usar usuario con rol Superadmin |
cURL:
curl "http://localhost/api/logs/global?skip=0&limit=50&tabla=usuarios&tipo=LOGIN_FALLIDO" -H "Authorization: Bearer <token>"Python:
import httpxresp = 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()