resources/views/pages/frontend/docs/auditoria.md
Última modificación: 24 Oct, 2026

Auditoría Forense Asíncrona (MongoDB)

Para garantizar la inmutabilidad de los registros históricos y evitar la saturación de I/O en el motor relacional primario (MariaDB), Mañuti implementa un subsistema de auditoría no bloqueante sobre MongoDB 7.0, respaldado por colas en memoria con Redis y supervisado por Laravel Horizon.


1. Arquitectura de Desacoplamiento (Cero Bloqueo HTTP)

La persistencia de auditoría opera fuera del ciclo de vida síncrono de la petición del cliente. El servidor entrega la respuesta HTTP inmediatamente, delegando la serialización del payload a un worker en segundo plano:

flowchart TD
    CLIENTE["[Cliente HTTP]"]
    MIDDLEWARE["[AuditMiddleware]"]
    CONTROLADOR["[Controlador / Lógica]"]
    RESPUESTA["[HTTP 200/302 OK]<br/>(Respuesta Inmediata)"]
    REDIS["[Redis Queue: ProcessAuditLog]"]
    WORKER["[Worker Horizon Daemon]"]
    MONGO["[MongoDB: Colección 'auditoria']"]

    CLIENTE --> MIDDLEWARE
    MIDDLEWARE --> CONTROLADOR
    CONTROLADOR --> RESPUESTA
    
    MIDDLEWARE -->|"Captura $userBefore / $userAfter<br/>Captura Response Status<br/>Sanitiza Payload"| REDIS
    
    REDIS --> WORKER
    WORKER --> MONGO

2. Diccionario del Documento BSON (auditoria)

La colección reside en la base de datos no relacional configurada (DB_MONGO_DATABASE=auditoria_db) y mapeada mediante la clase App\Models\AuditLog que extiende de MongoDB\Laravel\Eloquent\Model.

Campo BSON Tipo de Dato Definición Técnica
_id ObjectId Identificador único hexadecimal nativo de MongoDB.
usuario_id Int64 / Null Puntero numérico hacia la tabla usuarios de MariaDB. Null para invitados.
usuario_nombre String Snapshot estático del identificador de usuario (usuario) en el instante del evento. Preserva la autoría si el registro relacional es anonimizado o borrado.
permiso String Identificador de la acción ejecutada (e.g., users.create, sistema_bloqueo_usuario, login_fallido).
url String URI absoluta solicitada, incluyendo parámetros de consulta (Query Strings).
metodo String Verbo de la petición HTTP (GET, POST, PUT, DELETE).
ip String Dirección IP del cliente, resuelta a través de proxies de confianza.
user_agent String Cadena completa del agente de navegación para análisis de contexto.
status Int32 Código de estado HTTP retornado por la respuesta (e.g., 200, 302, 403, 500).
payload Document (JSON) Conjunto de datos enviados en el request, sometido a sanitización recursiva.
created_at ISODate Marca de tiempo UTC indexada de alta precisión.

3. Sanitización de Datos Sensibles & Blindaje de Archivos

El middleware implementa la eliminación preventiva de secretos de autenticación e interrumpe la serialización accidental de binarios:

// app/Http/Middleware/AuditMiddleware.php
private function cleanPayload(array $data): array
{
    foreach ($data as $key => $value) {
        if ($value instanceof \Illuminate\Http\UploadedFile) {
            $data[$key] = [
                'filename'  => $value->getClientOriginalName(),
                'mime_type' => $value->getMimeType(),
                'size_kb'   => round($value->getSize() / 1024, 2),
                '_type'     => 'file_upload'
            ];
        } elseif (is_array($value)) {
            $data[$key] = $this->cleanPayload($value);
        }
    }
    return $data;
}
  • Campos depurados de raíz: password, password_confirmation, current_password, _token, _method.
  • Esto erradica la excepción crítica Serialization of 'Illuminate\Http\UploadedFile' is not allowed cuando los usuarios actualizan avatares o adjuntan documentos.

4. Estrategia de Invocación: Automática vs. Manual

Invocación Automática (Rutas Protegidas por RBAC)

El AuditMiddleware inspecciona las directivas asignadas a la ruta. Si detecta la presencia del middleware can:slug.permiso, consulta en memoria (o en caché de Redis) si dicho slug tiene activada la bandera auditable = 1 en MariaDB:

Route::middleware(['auth', 'no-cache', 'auditar'])->group(function () {
    Route::post('/usuarios', [UserController::class, 'store'])
        ->middleware('can:users.create');
});

Filtro de Reducción de Ruido: El middleware omite automáticamente peticiones GET dirigidas exclusivamente a renderizar formularios vacíos (.create, .edit), registrando únicamente transacciones de escritura o accesos a grillas de datos (.index, .show).

Invocación Manual (Rutas Públicas y Críticas)

Para flujos sin control de capacidades (e.g., accesos públicos), la acción se inyecta por parámetro de middleware:

Route::post('/login', [AuthController::class, 'login'])
    ->middleware('auditar:intento_login');

5. El Job Asíncrono de Procesamiento (ProcessAuditLog)

// app/Jobs/ProcessAuditLog.php
namespace App\Jobs;

use App\Models\AuditLog;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class ProcessAuditLog implements ShouldQueue
{
    use InteractsWithQueue, Queueable;

    public function __construct(public array $data) {}

    public function handle(): void
    {
        AuditLog::create($this->data);
    }

    public function tags(): array
    {
        return [
            'auditoria',
            'user:' . ($this->data['usuario_id'] ?? 'invitado'),
            'action:' . ($this->data['permiso'] ?? 'general')
        ];
    }
}

Los tags asignados permiten indexar y rastrear ejecuciones en vivo desde el panel de supervisión de Laravel Horizon.


Enlaces Relacionados

Edita este documento en >> auditoria.md
← Volver a la Landing Page