# Sistema de Logs

## Qué hace

Cada vez que un usuario autenticado realiza una acción en el sistema, queda un registro. Hay dos tablas:

- **`core_activity_logs`** — todo lo que hace un usuario: navegación, acciones Livewire, cambios en modelos (auditoría).
- **`core_system_logs`** — eventos del sistema: queries lentas, errores de BD, cualquier evento que el código registre explícitamente.

La pantalla `/Logs` (menú Admin) permite consultar ambas tablas con filtros y limpiar registros viejos.

---

## Configuración (Settings → Logging)

Los toggles viven en **Settings → sección Logging**. Todos están activos por defecto excepto "Log page reads".

| Campo | Default | Qué controla |
|---|---|---|
| **Enable Logging** | on | Interruptor maestro. Si está off, ningún log se guarda. |
| **Log navigation (nav)** | on | Registra acciones HTTP (mutaciones) y acciones Livewire. |
| **Log page reads (GET)** | **off** | Si está off (recomendado), los GET puros no se guardan. Solo mutaciones y Livewire. |
| **Log informational (info)** | on | Eventos informativos del código (`CoreLogger::info`). |
| **Log warnings (warning)** | on | Situaciones inesperadas no críticas (`CoreLogger::warning`). |
| **Log errors (error)** | on | Fallos, errores de BD y excepciones (`CoreLogger::error`). |

> Los logs de **auditoría** (`type = audit`) se guardan siempre, sin importar la configuración. Son los cambios en modelos (crear/editar/borrar registros) y no tienen toggle porque son datos críticos para soporte.

---

## Tipos de log (`type`)

| Tipo | Tabla | Quién lo genera | Se puede desactivar |
|---|---|---|---|
| `nav` | activity | Middleware `LogActivity` — cada request HTTP o acción Livewire | Sí (`log_nav`) |
| `audit` | activity | Trait `WithAuditLog` en modelos — al crear/editar/borrar un registro | **No** |
| `info` | activity + system | `CoreLogger::info(...)` desde código | Sí (`log_info`) |
| `warning` | system | `CoreLogger::warning(...)` — ej. query lenta >2s | Sí (`log_warning`) |
| `error` | system | `CoreLogger::error(...)`, excepciones de BD | Sí (`log_error`) |

---

## Qué SÍ aparece en el log de actividad

### Requests HTTP normales (no Livewire)
- `POST`, `PATCH`, `PUT`, `DELETE` → siempre se guardan cuando `log_nav = on`
- `GET` → solo si además `log_nav_reads = on` (por defecto **off**)

### Acciones Livewire
Livewire envía todos sus requests como `POST /livewire/update`. El logger parsea el body para extraer qué métodos del componente se llamaron.

Se registra si el componente llama un método real del usuario, por ejemplo:
- `save()`, `store()`, `delete()`, `update()`, `toggleActive()`, `openModal()`, etc.

El campo `message` en el log muestra: `nombre-componente@nombreMetodo`.

---

## Qué NO aparece en el log (casos Livewire)

Esto es importante para soporte: hay interacciones Livewire que **no generan entrada en el log**, aunque el usuario sí las ejecutó.

### 1. Sincronización de propiedades puras (`$set`, `wire:model`)
Cuando el usuario escribe en un input con `wire:model.live` o cambia un select, Livewire envía un request con `$set` como método. Estos se ignoran porque son solo actualizaciones de estado, no acciones del usuario.

```
// Esto NO se loguea:
wire:model.live="search"   →  llamada $set('search', 'valor')
wire:model.live="page"     →  llamada $set('page', 2)
```

**Regla:** cualquier método que empiece con `$` se descarta.

### 2. `$refresh` y `$wire`
Métodos internos de Livewire (`$refresh`, `$wire.entangle`, etc.) también empiezan con `$`, así que se descartan igual que el punto anterior.

### 3. Requests con solo propiedades, sin llamadas a métodos
Si Livewire despacha un request que no tiene ningún `call` en su payload (solo sincronización de propiedades), el logger retorna sin registrar nada. Esto pasa cuando se usa `wire:model` sin ningún método asociado.

### 4. Componentes sin nombre en el snapshot
Si por alguna razón el snapshot de Livewire no incluye `memo.name` (raro pero posible en componentes mal configurados), el log igual se guarda pero sin identificar el componente — el campo `module` queda `null`.

### 5. Usuarios no autenticados
El middleware solo registra si `auth()->check()` es verdadero. Cualquier acción de usuario invitado (login, install wizard, rutas públicas) **no se registra**.

### 6. Requests fallidos antes del middleware
Si Laravel no puede resolver el request (error 500 antes de que arranque el middleware, por ejemplo al iniciar la app), el log tampoco llega a escribirse.

---

## Auditoría de modelos (`type = audit`)

Los modelos con el trait `WithAuditLog` registran automáticamente cada create/update/delete en `core_activity_logs`.

**Modelos auditados actualmente:**
- `App\Models\User`
- `Transaction`, `Wallet`, `Bucket`, `CreditCard` (módulo SFM)

Cada entrada de auditoría guarda en `params`:
- **create** → todos los atributos del registro nuevo (excepto timestamps y campos excluidos)
- **update** → solo los campos que cambiaron, con valor anterior (`old`) y nuevo (`new`)
- **delete** → el ID del registro eliminado

Los campos marcados como `$auditSensitive` en el modelo se guardan como `[REDACTED]`. En `User`, `password` y `remember_token` están redactados.

Los campos marcados como `$auditExclude` se omiten completamente del log.

### Caso especial: `increment`/`decrement` en Wallet
El balance de `Wallet` se actualiza vía `increment`/`decrement` desde el `TransactionObserver`. Este mecanismo de Eloquent sincroniza el original antes de disparar eventos, así que `getDirty()` queda vacío y **el cambio de balance no genera entrada de auditoría separada**. El cambio queda trazado indirectamente por el log de auditoría de la `Transaction` que lo causó.

---

## Cómo agregar logs desde código

```php
use Modules\Core\Services\CoreLogger;

// Evento informativo (guarda en activity + system log)
CoreLogger::info('Exportación completada', ['rows' => 500], 'sfm');

// Advertencia (solo system log)
CoreLogger::warning('Saldo insuficiente detectado', ['wallet_id' => 3], 'sfm');

// Error (solo system log)
CoreLogger::error('Fallo al procesar ciclo', ['exception' => $e->getMessage()], 'scheduler');
```

El tercer parámetro es el `channel` — sirve para filtrar en la vista de System Logs. Usar el alias del módulo (`core`, `sfm`, `tm`) o algo descriptivo (`scheduler`, `database`).

---

## Cómo agregar auditoría a un modelo nuevo

```php
use App\Traits\WithAuditLog;

class MiModelo extends Model
{
    use WithAuditLog;

    // Opcional: campos que se guardan como [REDACTED]
    protected array $auditSensitive = ['campo_secreto'];

    // Opcional: campos que se omiten del log completamente
    protected array $auditExclude = ['campo_interno'];
}
```

El módulo se detecta automáticamente desde el namespace del modelo (`Modules\Sfm\...` → `sfm`). Si el modelo está en `App\Models`, aparece como `app`.

---

## Limpieza de logs

En la pantalla `/Logs`, la sección **Cleanup** (visible solo con permiso `log.delete`) permite borrar registros por tabla, tipo y antigüedad. El campo "Older than (days) = 0" borra todo sin filtro de fecha.

Para automatizar la limpieza, se puede llamar desde un scheduled command:

```php
// Borrar activity logs de tipo nav con más de 30 días
\Modules\Core\Models\ActivityLog::where('type', 'nav')
    ->where('created_at', '<=', now()->subDays(30))
    ->delete();
```
