Buscar en la documentación

Seeders

Datos iniciales, usuarios de demostración e idempotencia.

5 min de lecturaVer en GitHub

Los datos iniciales se cargan solos al levantar el stack: el servicio init ejecuta las migraciones con --seed en cada arranque. Por eso todos los seeders son idempotentes y no destructivos:

  • Agregan lo que falta, identificándolo por su clave natural (code en catálogos, roles y permisos; email en usuarios).
  • Nunca pisan lo que ya existe. Si un administrador ajusta, por ejemplo, el tiempo sugerido de una prioridad o quita un permiso a un rol, volver a sembrar no lo revierte. Los cambios intencionales a los datos base se hacen con una migración.
  • Solo insertan las filas que faltan (InsertsMissingRows): primero consultan qué códigos existen y luego insertan los demás. No usan INSERT IGNORE, porque MySQL gasta un valor del autoincremental en cada intento aunque la fila ya exista. Los catálogos usan TINYINT (máximo 255), así que después de unas decenas de arranques el seeder fallaría y la API no volvería a levantar. Una prueba verifica que volver a sembrar no gasta ningún valor.
  • En las pruebas, los seeders corren una sola vez por ejecución y cada prueba trabaja en una transacción que se revierte.
SeederQué cargaEntorno
IncidentCatalogSeederPrioridades, estados, transiciones y tipos de actividadTodos
AccessControlSeederRoles (con su nivel), permisos y la matriz inicial. La matriz solo se siembra para un rol o un permiso que se crea en esa ejecución (ADR-0054)Todos
MfaPolicySeederPolítica de MFA por rol: obligatorio, con un ingreso de graciaTodos
AdminActionTypeSeederCatálogo de acciones administrativasTodos
SystemEventTypeSeederCatálogo de eventos del sistema, con categoría y severidadTodos
NotificationTypeSeederCatálogo de tipos de notificación, con su pestañaTodos
DemoUserSeederUsuarios de demostraciónTodos menos producción
AccountSetSeederCuentas por rol de evaluación y propias, desde el entorno (cuentas)Todos, si sus variables están definidas
IncidentVolumeSeederIncidentes de demostración en volumenTodos; en producción solo con SEED_INCIDENTS_IN_PRODUCTION=true

Catálogo de widgets

DashboardWidgetSeeder carga los 10 widgets del dashboard con sus topes, su tamaño original y el permiso que exige cada uno (ver diccionario). Como los demás catálogos, agrega los que faltan por su code y nunca pisa los ajustes de los existentes. El sort_order va de diez en diez para poder intercalar widgets nuevos.

Usuarios de demostración

CorreoRol
superadmin@trazo.testSuper admin
admin@trazo.testAdministrador
supervisor@trazo.testSupervisor
agente1@trazo.test, agente2@trazo.test, agente3@trazo.testAgente
solicitante1@trazo.test, solicitante2@trazo.test, solicitante3@trazo.testSolicitante

La contraseña de todos es Cometa.Demo.2026 (variable DEMO_USER_PASSWORD), que cumple la política de contraseñas: 12 o más caracteres, sin repeticiones, secuencias ni la marca del producto. Si un usuario ya existe, el seeder no cambia su contraseña.

Incidentes de demostración

IncidentVolumeSeeder carga 600 incidentes por defecto (la prueba pide al menos 500). El volumen se cambia con la variable SEED_INCIDENTS, y en producción solo se cargan si SEED_INCIDENTS_IN_PRODUCTION=true: así el sitio de evaluación arranca con datos, repartidos entre las cuentas por rol. Si no hay personas activas que los atiendan y asignen, se omiten con un aviso (ADR-0089).

  • Idempotente: completa hasta llegar al volumen pedido. Si ya hay 600 o más, no hace nada.
  • Datos coherentes y en español:
    • Flujo parejo, como una mesa de ayuda real: los incidentes llegan a lo largo de los últimos 60 días y su estado depende de la edad. Lo que todavía está dentro de su tiempo de resolución sigue abierto. Lo más viejo ya se atendió (resuelto, cerrado o cancelado), salvo un 2 % que quedó atascado y vencido.
    • Por eso la tendencia del dashboard muestra creados y resueltos parecidos cada día (en 30 días, unos 280 creados y 215 resueltos), y no un pico artificial.
    • Con 600 incidentes quedan unos 50 pendientes, de los que cerca del 40 % está vencido.
    • Prioridades repartidas con pesos realistas; el vencimiento va del 80 % al 160 % del tiempo de resolución de la prioridad.
    • Lo resuelto y lo cerrado tiene fecha de resolución, nunca en el futuro.
    • Las asignaciones van solo a personas que atienden incidentes.
  • Siempre los mismos datos: usa una semilla fija, así cada máquina obtiene el mismo resultado.
  • Historial completo y coherente (IncidentStory): cada incidente cuenta cómo llegó a su estado, igual que si se hubiera trabajado desde la aplicación.
    • Primero “Creado”, por quien lo creó.
    • Luego la asignación, cuando tiene responsable: la hace quien supervisa o la toma la propia persona.
    • Después los cambios de estado, siguiendo solo las transiciones permitidas. Por ejemplo, Abierto → En progreso → En espera → En progreso → Resuelto → Cerrado, o una cancelación desde Abierto, En progreso o En espera.
    • Quien atiende cambia el estado mientras trabaja; cerrar y cancelar lo hace quien supervisa.
    • Pasar a Resuelto y a Cancelado lleva una nota de ejemplo (cómo se resolvió, por qué se canceló), como exige la aplicación.
    • Las fechas van en orden: “Resuelto” cae justo en la fecha de resolución, “Cerrado” llega hasta dos días después y nada queda en el futuro. La fecha de última modificación del incidente es la de su último paso.
    • Los cambios se guardan con la misma forma que usa la aplicación (código y nombre del estado; id público y nombre de la persona), así el detalle los muestra igual que los reales. No llevan IP ni navegador, porque no vienen de una petición.
    • Con 600 incidentes quedan unas 3.100 filas de historial: 600 creaciones, unas 580 asignaciones y unos 1.900 cambios de estado.
  • Rápido: inserta por lotes de 1.000 sin Eloquent. Los 600 de siempre tardan menos de un segundo; 100.000 incidentes, con sus unas 520.000 filas de historial, alrededor de un minuto.
  • Cada incidente recibe su código TZ-26-0142 con el mismo contador de la aplicación (IncidentCodes::assignPending), por año de creación.

En las pruebas automáticas el volumen es 0: cada prueba crea los incidentes que necesita. Solo las pruebas de los datos de demostración siembran 300 o 500, para revisarlos.

Dónde está en el código