📐 Documentación Visual — Log Management Dashboard
Proyecto: Panel de Administración y Gestión de Logs Multi-Aplicación Fecha: 2026-03-03 · Actualizado: 2026-03-14 (stack Laravel + Livewire 3) Skill: System Architect — C4 Model + Flujos Estado: FASE 4 Completada
1. C4 Level 1 — System Context
Cómo el sistema encaja en el mundo, interactuando con usuarios y sistemas externos.
2. C4 Level 2 — Container Diagram
Las aplicaciones y bases de datos que componen el sistema.
3. Flujo 1 — Archivado de un Log (Livewire Action)
Secuencia desde que el admin decide archivar hasta que el log desaparece de la vista activa.
4. Flujo 2 — Actualización en Tiempo Real (SSE + Livewire)
Cómo un nuevo log insertado por n8n llega al dashboard del administrador.
5. Flujo 3 — Autenticación Externa + Mock de Desarrollo
El panel no gestiona login. El usuario llega con sesión activa del sistema externo.
6. Diagrama de Base de Datos (Entity-Relationship)
Schema completo de PostgreSQL actualizado. La tabla
logses de solo lectura para el panel (la gestiona n8n).
Notas de diseño:
userscontiene los usuarios del panel (sincronizados o mockeados desde auth externa). Sin contraseña local.
logsusa DELETE físico en dos situaciones:
- Al archivar (acción del admin): se hace INSERT en
archived_logsy DELETE inmediato del log original dentro de la misma transacción.- Script de purga (tarea programada — diaria/semanal/mensual): elimina los logs con
resolved = truemás antiguos de N días que no fueron archivados. Se implementa como unphp artisan logs:purge --days=30registrado enroutes/console.phpcon->daily().
logs.resolved(boolean): estado que el admin puede activar sin archivar. El script de purga usa este flag +created_atcomo criterio de eliminación.No hay soft delete en
logs: la tabla puede recibir miles de logs de múltiples apps y debe mantenerse compacta. El histórico duradero vive enarchived_logs.
archived_logsalmacena una copia desnormalizada completa (severity,message,metadata,error_code_id, etc.) para que el histórico sea autónomo una vez que el log original se elimine.
archived_logs.url_tutorialydescriptionson editables solo desde la vista de Histórico.El enum de severidad se declara una vez y se reutiliza en
logsyarchived_logs:sqlCREATE TYPE severity AS ENUM ('critical', 'high', 'medium', 'low', 'other');En las migraciones Laravel, usar
$table->enum('severity', ['critical','high','medium','low','other'])o un cast personalizado conuse HasCasts+SeverityEnum::class.
Índices recomendados
Definir en las migraciones Laravel con
Schema::table('logs', ...)tras crear las columnas.
// logs — rendimiento de los listados principales
$table->index('error_code_id'); // búsquedas por catálogo
$table->index(['application_id', 'created_at']); // listado principal (desc)
$table->index(['severity', 'resolved']); // filtros combinados
$table->index('matched_archived_log_id'); // join de enlace a issue
// error_codes — integridad de catálogo
$table->unique(['code', 'application_id']); // unicidad de negocioMatching de logs con issues conocidos (asistido desde la vista de detalle)
El log insertado por n8n no tiene contexto para saber si ya existe un issue archivado similar; ese conocimiento lo tiene el administrador cuando abre la vista de detalle. Por tanto, el campo
matched_archived_log_idse rellena manualmente o con sugerencia asistida desdeLogDetail, no en el momento del INSERT.
Flujo en la vista de detalle (/logs/{id}):
- El admin abre un log activo.
- Si el log tiene
error_code_id, el componente Livewire consulta en segundo plano losarchived_logscon la mismaapplication_id+error_code_idy los presenta como sugerencias. - El admin selecciona el issue conocido (o ignora las sugerencias).
- El Livewire Action actualiza
logs.matched_archived_log_id.
// En el componente Livewire LogDetail
public function loadSuggestedMatches(): void
{
if ($this->log->error_code_id) {
$this->suggestedMatches = ArchivedLog::where('application_id', $this->log->application_id)
->where('error_code_id', $this->log->error_code_id)
->latest('archived_at')
->limit(5)
->get();
}
}
public function linkToArchivedLog(int $archivedLogId): void
{
$this->log->update(['matched_archived_log_id' => $archivedLogId]);
$this->dispatch('matchLinked');
}
matched_archived_log_idpuede seguir siendonullsi el admin no encuentra un issue relacionado. Es un campo informativo, no un requisito para archivar.
7. Mapa de Rutas — Laravel Web Routes
Navegación global:
x-nav(componente Blade) con enlaces a Dashboard / Logs / Histórico / Error Codes / Cerrar Sesión.