756 lines
24 KiB
Markdown
756 lines
24 KiB
Markdown
# RF-ADM-004: Auditoría Completa y Trazabilidad de Cambios
|
|
|
|
**ID:** RF-ADM-004
|
|
**Módulo:** MAI-013 - Administración & Seguridad
|
|
**Tipo:** Requerimiento Funcional
|
|
**Prioridad:** P0 (Crítica)
|
|
**Fecha de creación:** 2025-11-20
|
|
**Versión:** 1.0
|
|
|
|
---
|
|
|
|
## 📋 Descripción
|
|
|
|
El sistema debe proporcionar **auditoría completa y automática** de todas las operaciones críticas, permitiendo:
|
|
|
|
- **Registro automático** de eventos de seguridad, cambios de datos y operaciones financieras
|
|
- **Trazabilidad completa:** Quién, qué, cuándo, dónde, por qué, cómo
|
|
- **Consultas avanzadas** con filtros múltiples (usuario, módulo, fecha, acción)
|
|
- **Retención diferenciada:** Logs operativos (90 días) vs críticos (5 años)
|
|
- **Reportes de cumplimiento** para auditorías internas/externas
|
|
- **Alertas automáticas** ante eventos sospechosos o críticos
|
|
|
|
La auditoría es fundamental para **cumplimiento normativo** (ISO 27001, SOC 2, LFPDPPP) y para investigación de incidentes de seguridad o errores operativos.
|
|
|
|
---
|
|
|
|
## 🎯 Objetivos
|
|
|
|
### Objetivos de Negocio
|
|
|
|
1. **Cumplimiento normativo:** ISO 27001, SOC 2, LFPDPPP, auditorías fiscales
|
|
2. **Investigación de incidentes:** Rastrear errores, fraudes o accesos no autorizados
|
|
3. **Análisis forense:** Reconstruir secuencia de eventos ante problemas
|
|
4. **Responsabilidad:** Identificar quién realizó cada acción crítica
|
|
5. **Mejora de procesos:** Analizar patrones de uso del sistema
|
|
|
|
### Objetivos Técnicos
|
|
|
|
1. **Performance:** Logging asíncrono (no bloquea operaciones)
|
|
2. **Integridad:** Logs inmutables (append-only, no se pueden editar/borrar)
|
|
3. **Búsqueda rápida:** Índices optimizados, queries < 500ms
|
|
4. **Almacenamiento eficiente:** Compresión de logs antiguos, particionamiento
|
|
5. **Disponibilidad:** Logs disponibles 24/7 para consulta
|
|
|
|
---
|
|
|
|
## 🔍 Categorías de Eventos Auditables
|
|
|
|
### 1. Autenticación y Autorización (Security Events)
|
|
|
|
| Evento | Severidad | Retención | Ejemplo |
|
|
|--------|-----------|-----------|---------|
|
|
| Login exitoso | Low | 1 año | Usuario `juan@empresa.com` login exitoso desde IP 192.168.1.10 |
|
|
| Login fallido | Medium | 1 año | Intento fallido para `admin@empresa.com` desde IP 203.0.113.5 |
|
|
| Bloqueo de cuenta | High | 5 años | Cuenta `pedro@empresa.com` bloqueada por 5 intentos fallidos |
|
|
| Cambio de contraseña | Medium | 5 años | Usuario `maria@empresa.com` cambió su contraseña |
|
|
| Cambio de rol | High | 5 años | Usuario `carlos@empresa.com` cambió de `engineer` a `director` |
|
|
| Acceso denegado | Medium | 90 días | Usuario `jorge@empresa.com` intentó acceder a `/admin` (403) |
|
|
| Logout | Low | 90 días | Usuario `ana@empresa.com` cerró sesión |
|
|
| Cambio de empresa | Low | 90 días | Usuario `luis@empresa.com` cambió de Empresa A a Empresa B |
|
|
|
|
### 2. Gestión de Usuarios (User Management Events)
|
|
|
|
| Evento | Severidad | Retención | Ejemplo |
|
|
|--------|-----------|-----------|---------|
|
|
| Creación de usuario | Medium | 5 años | Director creó usuario `nuevo@empresa.com` con rol `engineer` |
|
|
| Invitación enviada | Low | 1 año | Invitación enviada a `invitado@empresa.com` |
|
|
| Suspensión de usuario | High | 5 años | Director suspendió a `empleado@empresa.com` por 30 días |
|
|
| Reactivación | Medium | 5 años | Usuario `empleado@empresa.com` reactivado |
|
|
| Eliminación de usuario | Critical | 10 años | Super admin eliminó usuario `antiguo@empresa.com` |
|
|
| Modificación de permisos | High | 5 años | Director otorgó permiso `budgets:approve` a `ingeniero@empresa.com` |
|
|
|
|
### 3. Operaciones Críticas (Business Critical Events)
|
|
|
|
| Evento | Severidad | Retención | Condición | Ejemplo |
|
|
|--------|-----------|-----------|-----------|---------|
|
|
| Aprobación de estimación | Critical | 10 años | Monto > $50K | Director aprobó Estimación #125 por $2.5M |
|
|
| Aprobación de orden de compra | High | 5 años | Monto > $20K | Finanzas aprobó OC #452 por $150K |
|
|
| Modificación de presupuesto | Critical | 10 años | Cualquier cambio | Ingeniero modificó Presupuesto Obra A: $10M → $10.5M |
|
|
| Cierre de etapa | Critical | 10 años | Irreversible | Ingeniero cerró Etapa 1 de Obra Los Pinos |
|
|
| Eliminación de registro | High | 5 años | Soft delete | Admin eliminó Proyecto #45 |
|
|
| Cambio de estado de proyecto | Medium | 5 años | - | Director cambió Proyecto A de "Ejecución" a "Entregado" |
|
|
| Pago de estimación | Critical | 10 años | Monto > $10K | Finanzas registró pago de $1.2M para Estimación #130 |
|
|
| Modificación de contrato | High | 10 años | - | Ingeniero modificó monto de Contrato #22: $5M → $5.2M |
|
|
|
|
### 4. Administración del Sistema (System Administration Events)
|
|
|
|
| Evento | Severidad | Retención | Ejemplo |
|
|
|--------|-----------|-----------|---------|
|
|
| Cambio de configuración | High | 5 años | Admin cambió `maxLoginAttempts` de 5 a 3 |
|
|
| Creación de backup | Medium | 1 año | Sistema creó backup full `backup-2025-11-20.tar.gz` |
|
|
| Restauración de backup | Critical | 10 años | Admin restauró sistema desde backup del 2025-11-15 |
|
|
| Modificación de centro de costo | High | 5 años | Director creó centro `301 - Etapa 3` |
|
|
| Activación/desactivación de módulo | High | 5 años | Admin activó módulo INFONAVIT para Empresa A |
|
|
| Cambio de política de seguridad | Critical | 10 años | Admin cambió expiración de contraseñas: 90 → 60 días |
|
|
| Actualización de sistema | High | 5 años | Admin desplegó versión v2.1.5 → v2.2.0 |
|
|
|
|
---
|
|
|
|
## 📝 Modelo de Datos de Auditoría
|
|
|
|
### Estructura Completa de AuditLog
|
|
|
|
```typescript
|
|
interface AuditLog {
|
|
// Identificación
|
|
id: string; // UUID
|
|
timestamp: Date; // ISO 8601 con timezone
|
|
|
|
// Usuario (quien hizo la acción)
|
|
userId: string; // UUID
|
|
userName: string; // "Juan Pérez"
|
|
userEmail: string; // "juan@empresa.com"
|
|
userRole: ConstructionRole; // director, engineer, etc.
|
|
|
|
// Contexto empresarial
|
|
constructoraId: string; // UUID (multi-tenancy)
|
|
constructoraName: string; // "Constructora ABC"
|
|
projectId?: string; // Si la acción es sobre un proyecto específico
|
|
projectName?: string;
|
|
|
|
// Acción
|
|
action: AuditAction; // create, update, delete, approve, login, etc.
|
|
actionDescription: string; // "Aprobó estimación #125 por $2.5M"
|
|
module: string; // projects, budgets, estimations, auth, etc.
|
|
|
|
// Entidad afectada
|
|
entityType: string; // project, budget, estimation, user, etc.
|
|
entityId?: string; // UUID del registro afectado
|
|
entityName?: string; // "Proyecto Los Pinos"
|
|
|
|
// Cambios detallados (para updates)
|
|
changes?: AuditChange[];
|
|
|
|
// Contexto técnico
|
|
ipAddress: string; // "192.168.1.100"
|
|
userAgent: string; // "Mozilla/5.0 (Windows NT 10.0; Win64; x64)..."
|
|
sessionId: string; // UUID
|
|
requestId: string; // Para correlacionar requests relacionados
|
|
|
|
// Geolocalización (si disponible)
|
|
geolocation?: {
|
|
latitude: number;
|
|
longitude: number;
|
|
city?: string;
|
|
country?: string;
|
|
};
|
|
|
|
// Metadata adicional
|
|
severity: AuditSeverity; // low, medium, high, critical
|
|
category: AuditCategory; // authentication, user_management, business_critical, system_admin
|
|
success: boolean; // true = exitoso, false = fallido
|
|
errorMessage?: string; // Si success = false
|
|
duration?: number; // Milisegundos (para operaciones largas)
|
|
|
|
// Datos adicionales (JSON flexible)
|
|
metadata?: Record<string, any>;
|
|
|
|
// Control de retención
|
|
retentionPeriod: number; // Días (90, 365, 1825, 3650)
|
|
expiresAt: Date; // Fecha de eliminación automática
|
|
}
|
|
```
|
|
|
|
### ENUMs
|
|
|
|
```typescript
|
|
enum AuditAction {
|
|
// Autenticación
|
|
LOGIN = 'login',
|
|
LOGOUT = 'logout',
|
|
LOGIN_FAILED = 'login_failed',
|
|
PASSWORD_CHANGED = 'password_changed',
|
|
ACCOUNT_LOCKED = 'account_locked',
|
|
ACCOUNT_UNLOCKED = 'account_unlocked',
|
|
|
|
// CRUD
|
|
CREATE = 'create',
|
|
READ = 'read', // Solo para lecturas de datos sensibles
|
|
UPDATE = 'update',
|
|
DELETE = 'delete',
|
|
RESTORE = 'restore', // Restaurar soft delete
|
|
|
|
// Aprobaciones
|
|
APPROVE = 'approve',
|
|
REJECT = 'reject',
|
|
|
|
// Cambios de estado
|
|
STATUS_CHANGE = 'status_change',
|
|
|
|
// Administración
|
|
ROLE_CHANGE = 'role_change',
|
|
PERMISSION_GRANT = 'permission_grant',
|
|
PERMISSION_REVOKE = 'permission_revoke',
|
|
CONFIG_CHANGE = 'config_change',
|
|
BACKUP_CREATED = 'backup_created',
|
|
BACKUP_RESTORED = 'backup_restored',
|
|
|
|
// Accesos denegados
|
|
ACCESS_DENIED = 'access_denied',
|
|
}
|
|
|
|
enum AuditSeverity {
|
|
LOW = 'low', // Informativo (login exitoso, logout)
|
|
MEDIUM = 'medium', // Operaciones normales (crear proyecto, actualizar datos)
|
|
HIGH = 'high', // Operaciones críticas (aprobaciones >$20K, cambios de rol)
|
|
CRITICAL = 'critical' // Máxima criticidad (aprobaciones >$100K, eliminaciones, backups)
|
|
}
|
|
|
|
enum AuditCategory {
|
|
AUTHENTICATION = 'authentication',
|
|
USER_MANAGEMENT = 'user_management',
|
|
BUSINESS_CRITICAL = 'business_critical',
|
|
SYSTEM_ADMIN = 'system_admin'
|
|
}
|
|
```
|
|
|
|
### Cambios Detallados
|
|
|
|
```typescript
|
|
interface AuditChange {
|
|
field: string; // "totalAmount", "status", "role"
|
|
oldValue: any; // Valor anterior
|
|
newValue: any; // Valor nuevo
|
|
dataType: 'string' | 'number' | 'boolean' | 'date' | 'object' | 'array';
|
|
}
|
|
```
|
|
|
|
**Ejemplo:**
|
|
|
|
```json
|
|
{
|
|
"id": "uuid-audit-123",
|
|
"timestamp": "2025-11-20T14:30:25.123Z",
|
|
"userId": "uuid-user-456",
|
|
"userName": "Juan Pérez",
|
|
"userEmail": "juan@empresa.com",
|
|
"userRole": "engineer",
|
|
"constructoraId": "uuid-empresa-a",
|
|
"constructoraName": "Constructora ABC",
|
|
"projectId": "uuid-proyecto-1",
|
|
"projectName": "Fraccionamiento Los Pinos",
|
|
"action": "update",
|
|
"actionDescription": "Modificó presupuesto maestro de Etapa 1",
|
|
"module": "budgets",
|
|
"entityType": "budget",
|
|
"entityId": "uuid-budget-789",
|
|
"entityName": "Presupuesto Etapa 1",
|
|
"changes": [
|
|
{
|
|
"field": "totalAmount",
|
|
"oldValue": 10000000,
|
|
"newValue": 10500000,
|
|
"dataType": "number"
|
|
},
|
|
{
|
|
"field": "notes",
|
|
"oldValue": "Presupuesto inicial",
|
|
"newValue": "Presupuesto ajustado por cambio de alcance",
|
|
"dataType": "string"
|
|
}
|
|
],
|
|
"ipAddress": "192.168.1.50",
|
|
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
|
|
"sessionId": "uuid-session-abc",
|
|
"requestId": "uuid-request-xyz",
|
|
"severity": "critical",
|
|
"category": "business_critical",
|
|
"success": true,
|
|
"retentionPeriod": 3650,
|
|
"expiresAt": "2035-11-20T14:30:25.123Z"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🔍 Consultas y Filtros de Auditoría
|
|
|
|
### Filtros Disponibles
|
|
|
|
```typescript
|
|
interface AuditLogFilters {
|
|
// Rango de fechas
|
|
startDate?: Date;
|
|
endDate?: Date;
|
|
|
|
// Usuario
|
|
userId?: string;
|
|
userEmail?: string;
|
|
userRole?: ConstructionRole;
|
|
|
|
// Acción
|
|
action?: AuditAction | AuditAction[];
|
|
module?: string | string[];
|
|
entityType?: string;
|
|
entityId?: string;
|
|
|
|
// Severidad y categoría
|
|
severity?: AuditSeverity | AuditSeverity[];
|
|
category?: AuditCategory | AuditCategory[];
|
|
|
|
// Éxito
|
|
success?: boolean; // true = solo exitosos, false = solo fallidos
|
|
|
|
// Búsqueda de texto libre
|
|
search?: string; // Busca en actionDescription, entityName, userName
|
|
|
|
// Proyecto/Empresa
|
|
constructoraId?: string;
|
|
projectId?: string;
|
|
|
|
// IP Address
|
|
ipAddress?: string;
|
|
|
|
// Paginación
|
|
page?: number;
|
|
limit?: number; // Max 100
|
|
sortBy?: 'timestamp' | 'severity';
|
|
sortOrder?: 'asc' | 'desc';
|
|
}
|
|
```
|
|
|
|
### Queries Comunes
|
|
|
|
#### 1. Todos los cambios a un proyecto específico
|
|
|
|
```typescript
|
|
const logs = await getAuditLogs({
|
|
projectId: 'uuid-proyecto-1',
|
|
startDate: new Date('2025-11-01'),
|
|
endDate: new Date('2025-11-30'),
|
|
sortBy: 'timestamp',
|
|
sortOrder: 'desc'
|
|
});
|
|
```
|
|
|
|
#### 2. Todas las aprobaciones financieras >$100K
|
|
|
|
```typescript
|
|
const logs = await getAuditLogs({
|
|
action: 'approve',
|
|
module: ['estimations', 'purchases'],
|
|
severity: 'critical',
|
|
success: true
|
|
});
|
|
```
|
|
|
|
#### 3. Intentos de login fallidos (últimas 24 horas)
|
|
|
|
```typescript
|
|
const logs = await getAuditLogs({
|
|
action: 'login_failed',
|
|
startDate: subHours(new Date(), 24),
|
|
sortBy: 'timestamp',
|
|
sortOrder: 'desc'
|
|
});
|
|
```
|
|
|
|
#### 4. Todas las acciones de un usuario específico
|
|
|
|
```typescript
|
|
const logs = await getAuditLogs({
|
|
userEmail: 'juan@empresa.com',
|
|
startDate: new Date('2025-11-01'),
|
|
endDate: new Date('2025-11-30')
|
|
});
|
|
```
|
|
|
|
#### 5. Eventos críticos (alertas de seguridad)
|
|
|
|
```typescript
|
|
const logs = await getAuditLogs({
|
|
severity: 'critical',
|
|
category: ['authentication', 'user_management'],
|
|
success: false // Solo eventos fallidos
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 🔔 Alertas Automáticas
|
|
|
|
### Reglas de Alertas
|
|
|
|
| Evento | Condición | Destinatarios | Canal |
|
|
|--------|-----------|---------------|-------|
|
|
| **5 logins fallidos en 10 min** | Mismo usuario o IP | Admin de TI | Email + SMS |
|
|
| **Acceso denegado repetido** | >10 intentos en 1 hora | Admin de TI | Email |
|
|
| **Aprobación >$100K** | Cualquier estimación/OC | Director + CFO | Email |
|
|
| **Cambio de rol a Director** | Cualquier cambio | Super Admin | Email |
|
|
| **Eliminación de registro** | Cualquier entidad crítica | Admin | Email |
|
|
| **Cambio de configuración** | Sistema o seguridad | Admin de TI | Email |
|
|
| **Backup fallido** | Cualquier fallo | Admin de TI + Director | Email + SMS |
|
|
| **Acceso fuera de horario** | Login 22:00-06:00 | Admin de TI | Email (diario consolidado) |
|
|
|
|
### Ejemplo de Alerta
|
|
|
|
**Asunto:** 🚨 Alerta de Seguridad: 5 Intentos de Login Fallidos
|
|
|
|
```
|
|
Estimado Administrador,
|
|
|
|
Se han detectado 5 intentos fallidos de login en los últimos 10 minutos:
|
|
|
|
Usuario: admin@empresa.com
|
|
IP: 203.0.113.45
|
|
Última intento: 2025-11-20 14:35:12
|
|
Ubicación: Culiacán, Sinaloa, México
|
|
|
|
Acciones tomadas:
|
|
- Cuenta bloqueada temporalmente (30 minutos)
|
|
- IP agregada a lista de vigilancia
|
|
|
|
Detalles completos:
|
|
https://app.ejemplo.com/admin/audit-logs?userId=uuid-123&action=login_failed
|
|
|
|
---
|
|
Sistema de Auditoría Automática
|
|
Constructora ABC
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Reportes de Auditoría
|
|
|
|
### 1. Reporte de Actividad de Usuario
|
|
|
|
```
|
|
Reporte de Actividad: juan@empresa.com
|
|
Periodo: 01-30 Noviembre 2025
|
|
|
|
┌─────────────────────────┬───────┬────────────────────────────┐
|
|
│ Acción │ Count │ Último evento │
|
|
├─────────────────────────┼───────┼────────────────────────────┤
|
|
│ Login │ 42 │ 2025-11-30 17:45 │
|
|
│ Logout │ 40 │ 2025-11-30 18:30 │
|
|
│ Crear proyecto │ 3 │ 2025-11-25 10:15 │
|
|
│ Actualizar presupuesto │ 18 │ 2025-11-29 14:20 │
|
|
│ Aprobar estimación │ 5 │ 2025-11-28 16:00 │
|
|
│ Modificar contrato │ 2 │ 2025-11-22 11:30 │
|
|
└─────────────────────────┴───────┴────────────────────────────┘
|
|
|
|
Eventos críticos: 5 aprobaciones de estimaciones (total $8.5M)
|
|
Eventos fallidos: 2 (acceso denegado a módulo Finanzas)
|
|
|
|
Proyectos modificados:
|
|
- Fraccionamiento Los Pinos (15 acciones)
|
|
- Torre Residencial Aura (8 acciones)
|
|
```
|
|
|
|
### 2. Reporte de Cumplimiento (Compliance)
|
|
|
|
```
|
|
Reporte de Auditoría para Cumplimiento ISO 27001
|
|
Constructora ABC S.A. de C.V.
|
|
Periodo: Q4 2025 (Oct-Nov-Dic)
|
|
|
|
1. AUTENTICACIÓN Y CONTROL DE ACCESO
|
|
- Total logins: 2,450 ✅
|
|
- Logins fallidos: 45 (1.8%) ✅
|
|
- Cuentas bloqueadas: 3 ✅
|
|
- Cambios de contraseña: 120 ✅
|
|
- Sesiones concurrentes promedio: 35 ✅
|
|
|
|
2. GESTIÓN DE USUARIOS
|
|
- Usuarios creados: 12 ✅
|
|
- Usuarios suspendidos: 2 ✅
|
|
- Usuarios eliminados: 0 ✅
|
|
- Cambios de rol: 5 (todos auditados) ✅
|
|
- Permisos modificados: 8 (todos auditados) ✅
|
|
|
|
3. OPERACIONES CRÍTICAS
|
|
- Aprobaciones financieras >$100K: 25 (todas auditadas) ✅
|
|
- Modificaciones de presupuestos: 45 (todas auditadas) ✅
|
|
- Eliminaciones de registros: 3 (todas auditadas) ✅
|
|
- Cambios de configuración: 2 (ambos auditados) ✅
|
|
|
|
4. RESPALDO Y RECUPERACIÓN
|
|
- Backups exitosos: 90/90 (100%) ✅
|
|
- Backups fallidos: 0 ✅
|
|
- Restauraciones: 0 ✅
|
|
|
|
5. INCIDENTES DE SEGURIDAD
|
|
- Accesos no autorizados: 0 ✅
|
|
- Brechas de datos: 0 ✅
|
|
- Alertas de seguridad: 15 (todas investigadas) ✅
|
|
|
|
CONCLUSIÓN: Sistema cumple 100% con requisitos ISO 27001
|
|
```
|
|
|
|
### 3. Timeline de Proyecto (Forense)
|
|
|
|
```
|
|
Timeline: Proyecto Fraccionamiento Los Pinos
|
|
Periodo: 01-30 Noviembre 2025
|
|
|
|
2025-11-01 09:00 | Director | Creó proyecto "Fraccionamiento Los Pinos"
|
|
2025-11-01 09:15 | Director | Asignó Ingeniero: Juan Pérez
|
|
2025-11-02 10:30 | Ingeniero | Creó presupuesto maestro: $50M
|
|
2025-11-05 14:20 | Ingeniero | Modificó presupuesto: $50M → $52M
|
|
2025-11-08 16:45 | Finanzas | Aprobó presupuesto ajustado
|
|
2025-11-10 11:00 | Compras | Creó orden de compra #1: $1.2M
|
|
2025-11-10 15:30 | Finanzas | Aprobó OC #1
|
|
2025-11-15 09:45 | Residente | Capturó avance Etapa 1: 15%
|
|
2025-11-20 10:00 | Ingeniero | Aprobó avance 15%
|
|
2025-11-25 14:00 | Finanzas | Creó estimación #1: $7.5M
|
|
2025-11-26 16:30 | Director | Aprobó estimación #1
|
|
2025-11-28 11:00 | Finanzas | Registró pago: $7.5M
|
|
2025-11-30 17:00 | Ingeniero | Cambió estado: "Ejecución" → "Entregado"
|
|
|
|
Total eventos: 145
|
|
Usuarios involucrados: 5 (Director, Ingeniero, Finanzas, Compras, Residente)
|
|
```
|
|
|
|
---
|
|
|
|
## 📋 Casos de Uso
|
|
|
|
### Caso 1: Investigación de Error en Presupuesto
|
|
|
|
**Contexto:** Director detecta que presupuesto de Obra A cambió de $10M a $15M sin autorización.
|
|
|
|
**Flujo:**
|
|
1. Director va a "Auditoría" → "Consultar Logs"
|
|
2. Filtra:
|
|
- Entidad: Presupuesto Obra A
|
|
- Acción: Update
|
|
- Fecha: Últimos 30 días
|
|
3. Sistema muestra:
|
|
```
|
|
2025-11-15 14:30 | Ingeniero Juan | UPDATE budget
|
|
Campo: totalAmount
|
|
Cambio: $10,000,000 → $15,000,000
|
|
IP: 192.168.1.50
|
|
Sesión: uuid-session-abc
|
|
```
|
|
4. Director click en evento → Ve detalles completos:
|
|
- Usuario: juan@empresa.com
|
|
- Razón: "Ajuste por cambio de alcance aprobado en minuta 25/10/2025"
|
|
- Archivos adjuntos: minuta-2025-10-25.pdf
|
|
5. Director valida que cambio es legítimo (hay minuta)
|
|
6. Cierra investigación
|
|
|
|
**Resultado:** Trazabilidad completa del cambio, investigación en 5 minutos.
|
|
|
|
### Caso 2: Detección de Fraude (Intento)
|
|
|
|
**Contexto:** Alerta automática: "Usuario `compras@empresa.com` aprobó OC #455 de $500K fuera de horario (23:45)"
|
|
|
|
**Flujo:**
|
|
1. Admin de TI recibe alerta por email a las 23:46
|
|
2. Admin accede a sistema → "Auditoría" → Busca evento
|
|
3. Ve detalles:
|
|
```
|
|
2025-11-20 23:45 | Comprador Pedro | APPROVE purchase_order
|
|
OC #455: $500,000 (Proveedor: ABC Materiales S.A.)
|
|
IP: 203.0.113.99 (externa, no es IP de oficina)
|
|
Ubicación: Guadalajara, Jalisco (oficina está en Culiacán)
|
|
```
|
|
4. Admin llama a Pedro (Comprador):
|
|
- Pedro: "No estoy trabajando, estoy en casa"
|
|
- Admin: "¿Aprobaste OC #455?"
|
|
- Pedro: "No, yo no aprobé nada"
|
|
5. **Admin identifica:** Sesión comprometida
|
|
6. Acciones inmediatas:
|
|
- Bloquea cuenta de Pedro
|
|
- Revierte aprobación de OC #455
|
|
- Fuerza logout de todas las sesiones activas
|
|
- Cambia contraseña de Pedro
|
|
- Bloquea IP 203.0.113.99
|
|
7. Contacta a Pedro para reactivar cuenta con nueva contraseña
|
|
|
|
**Resultado:** Fraude detectado y bloqueado en 15 minutos. Pérdida evitada: $500K.
|
|
|
|
### Caso 3: Auditoría Externa (ISO 27001)
|
|
|
|
**Contexto:** Auditor externo solicita evidencia de controles de acceso.
|
|
|
|
**Flujo:**
|
|
1. Auditor solicita: "Todos los cambios de rol en 2025"
|
|
2. Admin va a "Reportes" → "Reporte de Auditoría de Cumplimiento"
|
|
3. Selecciona:
|
|
- Tipo: Cambios de Rol
|
|
- Periodo: 2025-01-01 a 2025-12-31
|
|
4. Sistema genera reporte PDF:
|
|
```
|
|
Reporte de Cambios de Rol - 2025
|
|
Constructora ABC S.A. de C.V.
|
|
|
|
Total cambios: 12
|
|
|
|
# Fecha Usuario Rol Anterior Rol Nuevo Autorizado Por
|
|
1 2025-02-15 juan@empresa.com engineer director Super Admin
|
|
2 2025-03-20 maria@empresa.com resident engineer Director
|
|
...
|
|
|
|
Conclusión: Todos los cambios fueron autorizados por Director o Super Admin.
|
|
Cumplimiento: 100%
|
|
```
|
|
5. Admin exporta reporte y entrega a auditor
|
|
6. Auditor valida que todos los cambios tienen autorización
|
|
|
|
**Resultado:** Auditoría externa aprobada en 1 día (vs 1 semana manual).
|
|
|
|
---
|
|
|
|
## ✅ Criterios de Aceptación
|
|
|
|
### AC1: Registro Automático de Eventos
|
|
|
|
**DADO** un usuario que aprueba una estimación de $100K
|
|
**CUANDO** completa la aprobación
|
|
**ENTONCES**
|
|
- ✅ Sistema registra evento automáticamente (sin intervención del usuario)
|
|
- ✅ Log contiene: usuario, timestamp, acción, entidad, monto, IP, sesión
|
|
- ✅ Severidad = `critical` (por monto >$100K)
|
|
- ✅ Retención = 10 años
|
|
- ✅ Log es inmutable (no se puede editar ni borrar)
|
|
|
|
### AC2: Consulta con Filtros Múltiples
|
|
|
|
**DADO** un admin que busca "aprobaciones financieras de Juan en noviembre"
|
|
**CUANDO** aplica filtros:
|
|
```typescript
|
|
{
|
|
userEmail: 'juan@empresa.com',
|
|
action: 'approve',
|
|
module: ['estimations', 'purchases'],
|
|
startDate: '2025-11-01',
|
|
endDate: '2025-11-30'
|
|
}
|
|
```
|
|
**ENTONCES**
|
|
- ✅ Sistema retorna solo registros que cumplen TODOS los filtros
|
|
- ✅ Resultados ordenados por timestamp desc (más reciente primero)
|
|
- ✅ Query ejecuta en < 500ms
|
|
- ✅ Paginación funciona correctamente
|
|
|
|
### AC3: Alertas Automáticas
|
|
|
|
**DADO** 5 intentos de login fallidos en 10 minutos
|
|
**CUANDO** ocurre el 5to intento
|
|
**ENTONCES**
|
|
- ✅ Sistema envía alerta por email a Admin de TI
|
|
- ✅ Cuenta se bloquea automáticamente por 30 minutos
|
|
- ✅ IP se agrega a lista de vigilancia
|
|
- ✅ Alerta contiene: usuario, IP, ubicación, timestamp
|
|
|
|
### AC4: Trazabilidad de Cambios
|
|
|
|
**DADO** un presupuesto que cambió de $10M a $15M
|
|
**CUANDO** se consulta auditoría
|
|
**ENTONCES**
|
|
- ✅ Log muestra cambio detallado:
|
|
```json
|
|
{
|
|
"field": "totalAmount",
|
|
"oldValue": 10000000,
|
|
"newValue": 15000000
|
|
}
|
|
```
|
|
- ✅ Log muestra quién lo cambió, cuándo, desde dónde
|
|
- ✅ Si hay justificación, se incluye en `metadata`
|
|
|
|
### AC5: Retención Diferenciada
|
|
|
|
**DADO** logs de diferentes severidades
|
|
**CUANDO** se ejecuta proceso de limpieza automática
|
|
**ENTONCES**
|
|
- ✅ Logs `low` severity: eliminados tras 90 días
|
|
- ✅ Logs `medium` severity: eliminados tras 1 año
|
|
- ✅ Logs `high` severity: eliminados tras 5 años
|
|
- ✅ Logs `critical` severity: eliminados tras 10 años
|
|
- ✅ Proceso no elimina logs antes de `expiresAt`
|
|
|
|
---
|
|
|
|
## 🧪 Escenarios de Prueba
|
|
|
|
### Test 1: Logging Automático
|
|
|
|
```typescript
|
|
describe('RF-ADM-004: Audit Logging', () => {
|
|
it('should automatically log critical operations', async () => {
|
|
const engineer = await loginAs('engineer');
|
|
|
|
// Aprobar estimación
|
|
const response = await api.patch('/estimations/123/approve', {}, {
|
|
headers: { Authorization: engineer.token }
|
|
});
|
|
|
|
expect(response.status).toBe(200);
|
|
|
|
// Verificar log
|
|
const logs = await getAuditLogs({
|
|
action: 'approve',
|
|
entityId: '123',
|
|
userId: engineer.id
|
|
});
|
|
|
|
expect(logs).toHaveLength(1);
|
|
expect(logs[0]).toMatchObject({
|
|
userId: engineer.id,
|
|
action: 'approve',
|
|
module: 'estimations',
|
|
entityId: '123',
|
|
severity: 'critical',
|
|
success: true
|
|
});
|
|
});
|
|
});
|
|
```
|
|
|
|
### Test 2: Inmutabilidad de Logs
|
|
|
|
```typescript
|
|
describe('RF-ADM-004: Log Immutability', () => {
|
|
it('should not allow editing or deleting logs', async () => {
|
|
const log = await createAuditLog({
|
|
action: 'login',
|
|
userId: 'user-123'
|
|
});
|
|
|
|
// Intentar modificar
|
|
const updateResponse = await api.patch(`/audit-logs/${log.id}`, {
|
|
action: 'logout'
|
|
});
|
|
|
|
expect(updateResponse.status).toBe(403);
|
|
expect(updateResponse.data.error).toBe('Audit logs are immutable');
|
|
|
|
// Intentar eliminar
|
|
const deleteResponse = await api.delete(`/audit-logs/${log.id}`);
|
|
|
|
expect(deleteResponse.status).toBe(403);
|
|
expect(deleteResponse.data.error).toBe('Audit logs cannot be deleted');
|
|
});
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 🔗 Referencias
|
|
|
|
- **Especificación técnica:** [ET-ADM-003](../especificaciones/ET-ADM-003-audit-logging.md)
|
|
- **Historia de usuario:** [US-ADM-004](../historias-usuario/US-ADM-004-consultar-auditoria.md)
|
|
- **RF relacionados:** [RF-ADM-001](./RF-ADM-001-usuarios-roles.md), [RF-ADM-002](./RF-ADM-002-permisos-granulares.md)
|
|
- **Módulo:** [README.md](../README.md)
|
|
|
|
---
|
|
|
|
**Generado:** 2025-11-20
|
|
**Versión:** 1.0
|
|
**Autor:** Sistema de Documentación Técnica
|
|
**Estado:** ✅ Completo
|