Recorrido por los Datos Seed
Después de correr php artisan db:seed, tu base de datos local tiene justo lo suficiente para iniciar sesión y ver el portal de partners — y casi nada más. Este documento te dice exactamente qué hay, qué falta y cómo llenar los huecos para que efectivamente puedas ejercitar la aplicación.
Si te saltas este documento, vas a pasar una hora preguntándote por qué cada página orientada al cliente está vacía.
1. Por qué importan los datos seed
Para probar Mi Plante localmente, necesitas:
- Un Persona + User + Cliente con un cupo aprobado (para que puedas completar el checkout sin pasar por el pipeline de 7 pasos que requiere credenciales de APIs externas).
- Una Empresa con al menos una Sucursal para que las ventas tengan dónde estar asociadas.
- Productos, Precios, Marcas, Líneas para que el marketplace tenga algo que mostrar.
- Constantes de configuración del
.env(que se cargan automáticamente — no se necesitan filas en BD).
Listo para usar, los seeders te dan algo de esto. Lo más importante: no te dan ningún Cliente ni ningún Producto. Así que puedes iniciar sesión en el portal de partners pero no navegar un marketplace con contenido.
Esta es una de las tareas con mayor apalancamiento para un dev nuevo: extender los seeders para que el entorno local sea realmente útil.
2. Qué corre con php artisan db:seed
El punto de entrada es database/seeders/DatabaseSeeder.php:
public function run(): void{ $this->call(LineaSeeder::class); $this->call(EmpresaSeeder::class); $this->call(MarcaSeeder::class);
// Producto::factory(50)->withExistingRandomEmpresa()->withExistingRandomLinea()->create(); // Precio::factory(70)->withExistingRandomProduct()->create(); // PrecioImagene::factory(100)->withExistingRandomPrice()->create();}Corren tres seeders. Tres líneas más están comentadas. Las líneas comentadas son cómo se sembrarían productos / precios / imágenes vía factories, pero las factories pueden existir o no o estar incompletas — están comentadas por una razón.
Recorramos lo que produce cada seeder.
2.1 LineaSeeder
Archivo: database/seeders/LineaSeeder.php
Crea el árbol de categorías — filas en lineas en dos niveles:
- Nivel 1 (categorías padre): Electrodomésticos, Viajes, Seguros, Hogar, Salud y Belleza, Deportes, Material de construcción, Educación, Movilidad, Tecnología (10 padres).
- Nivel 2 (sub-categorías): Línea Blanca, Línea Marrón, Muebles, Colchones, Motos, Computadores, etc. (~52 hijos en total).
Cada línea de nivel 2 tiene:
nombre— nombre de visualización (español)descripcion— descripción cortaslug— slug de URLplazo_minimoyplazo_maximo— el rango permitido de cuotas para esa categoría (ej. Línea Blanca: 11-60, Pólizas: 11-11, Motos: 11-72, Pregrados: 6-12)
Después del seeding: ~62 filas en lineas (10 padres + 52 hijos). Estas alimentan los filtros de categoría del marketplace.
2.2 EmpresaSeeder
Archivo: database/seeders/EmpresaSeeder.php
Este seeder crea:
- Tres Usuarios admin en el guard
app(portal de partners), asociados a: - Una Empresa MASTER (la propia compañía Mi Plante).
Específicamente:
| Usuario # | Nombres | Apellidos | Contraseña | Rol | DNI | |
|---|---|---|---|---|---|---|
| 1 | Admin | Master | testadmin@example.com | Test1234. | administrador | 99999999 |
| 2 | Admin | Comercial | testadmincomercial@example.com | Test1234. | administrador_comercial | 33333333 |
| 3 | Admin | Financiero | testfinanciero@example.com | Test1234. | administrador_financiero | 22222222 |
La Empresa:
| Campo | Valor |
|---|---|
nombre | Mi Plante |
razon_social | Mi Plante S.A.S. |
identificacion | 123456789 |
tipo_identificacion | NIT |
tipo | EmpresaType::MASTER |
estado | activo |
canal_venta | online |
| Líneas asociadas | IDs 1, 2, 3 (Electrodomésticos, Viajes, Seguros — depende del orden del LineaSeeder) |
Los tres usuarios están asociados a esta empresa vía user_empresa.
Nota: este seeder es lo que hace que funcione el login con testadmin@example.com. También crea filas de Persona para cada usuario.
2.3 MarcaSeeder
Archivo: database/seeders/MarcaSeeder.php
Crea 10 Marcas usando una factory + secuencia:
| Marca | Slug |
|---|---|
| Apple | apple |
| Samsung | samsung |
| Nike | nike |
| Adidas | adidas |
| Sony | sony |
| LG | lg |
| Lenovo | lenovo |
| HP | hp |
| Xiaomi | xiaomi |
| Puma | puma |
Cada una tiene un path de logo bajo marcas/. Los archivos de logo reales (apple.webp, samsung.jpg, etc.) pueden o no existir en storage/app/public/marcas/ — revisa php artisan storage:link y mira qué hay ahí.
Las Marcas son usadas por el marketplace como filtros de marca y por la subida de catálogo (mapeando producto → marca).
3. Qué FALTA en los seeds
Esta es la parte importante. Los seeders actuales te dan infraestructura pero no contenido.
Seeds faltantes
| Entidad | Por qué importa | Qué falta |
|---|---|---|
| Cliente (perfil de cliente) | Requerido para probar flujos orientados al cliente. Sin uno, no puedes vivir el marketplace como cliente. | ClienteAdministradorSeeder existe en el codebase pero no se llama desde DatabaseSeeder::run(). Y no seedea usuarios cliente de prueba con un cupo — seedea admins por empresa no-MASTER (de las cuales no hay ninguna por defecto). |
| Usuario Cliente | Igual — no puedes iniciar sesión como Cliente si no existe ninguno. | Ninguno creado. Los únicos usuarios seedeados son admins del portal de partners. |
| Empresa(s) — aliado no-MASTER | Para probar flujos de aliado (gestión de catálogo, ventas, etc.) necesitas un aliado real, no solo MASTER. | Ninguna creada. |
| Sucursal | Cada Empresa necesita al menos una sucursal. Sin una sucursal, no puedes procesar flujos del lado del aliado. | Ninguna creada (ni siquiera para MASTER). |
| Empleado (empleado de aliado) | Para probar el flujo de venta en tienda (Persona A-1, Carlos), necesitas un empleado asociado a una sucursal. | Ninguno creado. |
| Productos | La home del marketplace renderiza vacía sin productos. | La llamada a la factory está comentada en DatabaseSeeder. |
| Precios | Un Producto sin una variante de Precio no se puede comprar. | Llamada a factory comentada. |
| PrecioImagene | Productos sin imágenes se ven rotos. | Llamada a factory comentada. |
| Seeds de Carrito / ListaDeseo | Útil para probar las UIs de carrito y wishlist sin agregar manualmente items cada sesión. | Ninguno creado. |
| Ventas / Cuotas de muestra | Necesarias para probar el historial de pedidos, los listados de cuotas, los reportes del lado del aliado. | Ninguno creado. |
| Ejemplos de Postulación | Para probar el flujo de postulación del aliado desde el lado de ops, necesitas postulaciones pendientes. | Ninguna creada. |
Datos de prueba para puede_intentar_firmar_pagare_en | Para ejercitar la lógica de reintento del pagaré, necesitas un Cliente en el estado “esperando reintento”. | Ninguno creado. |
En resumen: “Database seeders: Mínimo (3 admins, 1 empresa, sin productos) — Difícil de probar localmente”.
Implicación
Listo para usar, tu entorno local puede:
- ✅ Mostrar la página de inicio (mayormente vacía)
- ✅ Navegar el árbol de líneas (los filtros funcionan)
- ✅ Navegar marcas (existen 10 marcas)
- ✅ Iniciar sesión como
testadmin@example.comen el portal de partners - ✅ Correr la UI del portal de partners (con datos vacíos)
- ❌ Registrarse como cliente (funciona mecánicamente, pero la integración con EMCALI durante
completar-registrofallará sin credenciales ni mocks) - ❌ Ver ningún producto en el marketplace
- ❌ Agregar nada al carrito
- ❌ Probar el checkout
- ❌ Probar la aprobación de crédito
- ❌ Probar el flujo de ventas del lado del aliado
- ❌ Probar el cálculo de cuotas contra datos reales
Esta brecha es el mayor obstáculo individual para la productividad de un dev nuevo. Arreglarla debería ser uno de tus primeros PRs.
4. Referencia de credenciales de login
Leyendo los seeders, estas son las credenciales que funcionan para dev local.
Nota de seguridad: estas credenciales son intencionales para desarrollo local. Están seedeadas en una base de datos que solo debería existir en un laptop de dev. No reutilices estas contraseñas en ningún entorno de staging, prod o compartido. No commitees archivos
.envcon credenciales reales. Si accidentalmente aprovisionas un entorno no-local que corradb:seed, cambia todas las contraseñas inmediatamente.
Portal de partners (/aliados/login)
Guard: app. URL: http://localhost:8000/aliados/login.
| Usuario | Contraseña | Rol | Qué puedes hacer | |
|---|---|---|---|---|
| Admin Master | testadmin@example.com | Test1234. | administrador | Acceso administrativo total sobre la Empresa MASTER |
| Admin Comercial | testadmincomercial@example.com | Test1234. | administrador_comercial | Reportes comerciales y gestión de aliados |
| Admin Financiero | testfinanciero@example.com | Test1234. | administrador_financiero | Acceso a reportes financieros |
Portal de cliente (/login)
Guard: web. URL: http://localhost:8000/login.
No hay credenciales de cliente seedeadas. Tendrás que:
- Registrar un cliente nuevo vía
GET /registro(funciona sin APIs externas para el registro en sí). - Opcionalmente completar
/usuario/completar-registro(falla sin credenciales de EMCALI → lanzará una ValidationException sobre el lookup de EMCALI).
Para dev local, crear manualmente un registro de Cliente vía Tinker es el workaround práctico hasta que los seeders sean extendidos:
php artisan tinkeruse App\Models\Persona;use App\Models\User;use App\Models\Cliente;
$persona = Persona::create([ 'tipo_dni' => 'CC', 'dni' => '1234567890', 'expedido_en' => now(), 'lugar_expedicion' => 'Cali',]);
$user = User::create([ 'persona_id' => $persona->id, 'nombres' => 'Maria', 'apellidos' => 'Test', 'email' => 'maria@example.com', 'password' => bcrypt('Test1234.'), 'telefono' => '3001234567', 'fecha_nacimiento' => '1990-01-01', 'guard' => 'web',]);
$cliente = Cliente::create([ 'user_id' => $user->id, 'cupo_asignado' => 3000000, 'cupo_disponible' => 3000000, 'registro_completado_en' => now(), 'ciudad' => 'Cali', 'departamento' => 'Valle del Cauca', 'direccion' => 'Calle 1 #1-1', 'barrio' => 'San Fernando',]);Ahora puedes iniciar sesión como maria@example.com / Test1234. y comportarte como un Cliente con un cupo de 3M COP.
Advertencia: esto omite por completo el flujo de completar-registro. La fila de Cliente quedará en un estado un poco artificial (sin números de factura de EMCALI asociados, etc.). Está bien para pruebas de UI; no está bien para probar el pipeline de aprobación de crédito.
5. Cómo recrear la BD limpiamente
Si tu BD local entra en un estado raro:
# Borrar todo y reseedearphp artisan migrate:fresh --seed⚠ migrate:fresh dropea TODAS las tablas. Corre esto solo cuando estés seguro de que no tienes datos locales que quieras conservar.
Otros encantamientos útiles:
# Borrar pero no reseedearphp artisan migrate:fresh
# Re-correr solo los seeders (los datos se reinician, el esquema se preserva)# Nota: esto AGREGA — lanzará violaciones de unique constraint si las filas ya existenphp artisan db:seed
# Re-correr un seeder específicophp artisan db:seed --class=LineaSeederphp artisan db:seed --class=MarcaSeeder
# Rollback del último batch de migracionesphp artisan migrate:rollback
# Rollback completophp artisan migrate:resetPara la base de datos de testing:
php artisan migrate:fresh --env=testingEsto usa la conexión miplante_testing según phpunit.xml.
6. Crear tus propios datos de prueba
Más allá de Tinker (mostrado arriba), tres opciones:
6.1 Tinker (rápido y sucio)
Mejor para objetos puntuales que quieres inspeccionar o usar ahora mismo. Ver sección 4 para un ejemplo.
6.2 Modificar un seeder
Mejor cuando quieres que cada dev del equipo tenga el mismo estado de arranque.
Pasos:
- Edita
database/seeders/DatabaseSeeder.phpo uno de los seeders hijos. - Agrega las filas que quieras (o llama a una factory si existe alguna).
- Corre
php artisan migrate:fresh --seed. - Commitea el cambio del seeder en un PR.
Para factories: revisa database/factories/ — hay factories definidas para algunos modelos pero no todos. Agregar factories faltantes es una excelente primera contribución.
6.3 Vía la UI
Mejor cuando quieres probar el flujo real orientado al usuario.
Pasos:
- Registra un cliente vía
/registro. - Recorre el flujo hasta donde puedas sin APIs externas.
- Manualmente asigna
Cliente.registro_completado_enycupo_disponibleen Tinker o TablePlus para saltarte los pasos bloqueados por EMCALI/Bureau.
7. Escenarios de prueba que vas a querer
El conjunto mínimo de fixtures que deberías poder crear para ejercitar el sistema:
| Escenario | Setup |
|---|---|
| Un Cliente con cupo aprobado | Tinker: crea un Cliente con cupo_disponible > 0, registro_completado_en = now(), pagare_firmado_en = now(). |
| Un Cliente en mora | Tinker: crea como arriba, pero asigna cualquier flag de mora que el codebase use (revisa el modelo Cliente para el nombre actual del campo de mora). Luego intenta golpear /checkout y confirma que el middleware verificar_cliente_presenta_mora te bloquea. |
| Un Cliente en paso 4 de la aprobación de crédito | Asigna registro_completado_en pero deja pagare_firmado_en en null. Manualmente alterna el estado cacheado para simular que hizo OTP. (Esto es difícil de hacer de forma confiable sin mocks — márquelo para el PR de mock de integraciones.) |
| Una Venta en PENDIENTE | Crea vía Tinker con EstadoVenta::PENDIENTE. Corre el job ProcesarPagareDigital manualmente para disparar el landmine de cuota duplicada (L-10). |
| Un Aliado con 50+ productos | Requiere una Empresa no-MASTER + Sucursales + Productos seedeados. Actualmente imposible sin extender los seeders. |
| Una Postulación en estado pendiente | Actualmente imposible sin extender los seeders. Bloquéalo en la tarea de seeds. |
8. Referencia rápida de la estructura de base de datos
El diagrama ER completo está en docs/audit/01-er-diagram.md. Aquí están las tablas que más vas a inspeccionar en dev local:
Lado de cliente
| Tabla | Qué contiene | Columnas clave |
|---|---|---|
personas | Identidad legal | id, tipo_dni, dni, expedido_en, lugar_expedicion |
users | Identidad de auth (ambos guards) | id, persona_id, nombres, apellidos, email, telefono, guard, rol |
clientes | Perfil de crédito | id, user_id, cupo_asignado, cupo_disponible, cupo_vence_en, registro_completado_en, pagare_firmado_en, certicamara_uuid, puede_intentar_firmar_pagare_en |
carritos | Items del carrito | id, user_id, precio_id, cantidad |
lista_deseos | Wishlist | id, user_id, producto_id |
Lado de aliado
| Tabla | Qué contiene | Columnas clave |
|---|---|---|
empresas | Compañía partner | id, nombre, razon_social, identificacion, tipo (MASTER/CLIENTE), estado |
sucursales | Sucursales | id, empresa_id, direccion, ciudad |
user_empresa | Pivot User ↔ Empresa | user_id, empresa_id (asocia empleados a compañías) |
productos | Productos | id, empresa_id, linea_id, marca_id, nombre, descripcion |
precios | Variantes de precio | id, producto_id, precio, inventario |
precio_imagenes | Imágenes de producto | id, precio_id, url |
marcas | Marcas | id, nombre, slug, logo_photo_path |
lineas | Categorías | id, nombre, slug, linea_padre_id, plazo_minimo, plazo_maximo |
Ventas / facturación
| Tabla | Qué contiene | Columnas clave |
|---|---|---|
orden_compras | Orden de compra de nivel superior | id, user_id, total, estado (PENDIENTE/PROCESADA/CANCELADA/RECHAZADA/ABANDONADA), numero_cuotas |
ventas | Una por vendedor por orden | id, orden_compra_id, user_id, sucursal_id, total, subtotal, numero_cuotas, estado (PENDIENTE/APROBADA/ENTREGADA/LEGALIZADA/COMPLETADA/RECHAZADA/ABANDONADA/DEVUELTA) |
venta_detalles | Items de línea | id, venta_id, precio_id, cantidad, monto |
cuotas | Cuotas | id, venta_id, orden_compra_id (cuotas maestras), numero_cuota, monto, interes, monto_seguro_vida, monto_fianza, monto_pagado, estado, fecha_vencimiento |
⚠ Inconsistencia de nombres: la tabla que contiene cuotas es cuotas, pero algunas referencias más antiguas pueden llamarla cuentas. Siempre verifica vía php artisan migrate:status o revisa el nombre real del archivo de migración 2025_11_06_140606_create_cuotas_table.php.
Audit trail de aprobación de crédito
| Tabla | Qué contiene | Columnas clave |
|---|---|---|
aprobar_cupo_eventos | Cada paso del pipeline de crédito | id (UUID), cliente_id, process_type (LEGAL_CHECK/IDENTITY_VALIDATION/IV_OTP_GENERATION/IV_OTP_VERIFICATION/IV_QUESTIONS_GENERATION/IV_QUESTIONS_VERIFICATION/HDC_VALIDATION/CUPO_EXTENSION), event_type (START/FINISH_SUCCESS/FINISH_UNSUCCESS), payload (JSON), creado_en |
postulacion_afiliados | Postulaciones de aliado | id, nombre_empresa, nit, causal (cuando es rechazada), estado |
postulacion_aliados_lineas | Pivot Postulación de aliado ↔ líneas |
Logging
| Tabla | Qué contiene |
|---|---|
laravel_logs | Logs de Laravel del backend (además del logging a archivo) |
backend_request_logs | Audit log de requests del backend |
frontend_error_logs | Logs de error del frontend enviados vía /api/error-logs (L-26 — también loguea éxitos) |
Misc
| Tabla | Qué contiene |
|---|---|
descontable_descuento | Reglas de descuento |
beneficiarios | Registros de beneficiario (uno por Venta en teoría) |
cache, sessions, jobs, failed_jobs | Tablas estándar gestionadas por Laravel |
permissions, roles, etc. | Tablas de Spatie permission (Spatie está instalado pero no conectado a la autorización en runtime) |
9. Primera contribución sugerida: extender los seeders
Un excelente PR para hacer en tu primera semana:
- Conecta
ClienteAdministradorSeederapropiadamente enDatabaseSeeder::run()(y actualízalo para seedear usuarios de prueba del lado cliente, no solo admins por empresa). - Agrega un
ClienteSeederque cree 3-5 Clientes coincidiendo con las personas en02-who-are-the-users.md(María, Andrés, Luisa). Dale a cada uno un cupo sensato yregistro_completado_en. - Descomenta y arregla las llamadas a factories de Producto/Precio/PrecioImagene en
DatabaseSeeder::run(). Asegúrate de que las factories existan (database/factories/); si no, créalas. - Agrega un
AliadoSeederque cree 1-2 Empresas no-MASTER con Sucursales y Empleados, para que el lado del aliado tenga contenido real. - Agrega un
VentaSeederque cree 5-10 Ventas históricas en varios estados (PENDIENTE, APROBADA, ENTREGADA, RECHAZADA) para que la página de historial de pedidos realmente tenga filas. - Agrega un
PostulacionSeedercon 2-3 postulaciones pendientes para que la persona de ops Daniela pueda ver cómo se ve su flujo.
Este PR único desbloqueará el 80% del trabajo de features subsecuente.
Factories de referencia (ya parcialmente en su lugar): database/factories/MarcaFactory.php, posiblemente otras. Revisa vía:
ls database/factories/10. Orden de lectura a partir de aquí
Siguiente: docs/onboarding/03-development-setup/03-common-gotchas.md — las 15+ cosas no obvias sobre este codebase que te van a costar horas si no las lees primero. Ese documento más el 16-deep-validation-study.md de la auditoría son las dos lecturas que más tiempo te van a ahorrar en la semana 1.