📚 Unidad ISS-04 · Seeders con Faker — capa 🧠 APRENDER
🛠 Construir este bloque → · ✅ Condiciones de cierre (GATE) · 📝 Evaluación
Capa Página Para qué 🧠 Aprender esta página comprender, explicar y relacionar 🛠 Construir Seeders con Faker ejecutar, programar y verificar ✅ GATE Cierre de la unidad condición para pasar al bloque siguiente
Mapa de correspondencias. Cada fila enlaza el mismo tema en las dos capas de la unidad; los enlaces apuntan a secciones reales del material (anclas de MkDocs, sin acentos).
| Tema | 🧠 Aprender (esta página) | 🛠 Construir (ISS técnico) |
|---|---|---|
| Ruta y ficha de la unidad | Ruta de aprendizaje · Ficha del ISS | Contenido de la unidad |
| Mapas y estructura | Mapa mental · Mapa del backend · Árbol de archivos | Contenido de la unidad |
| Recorrido y comandos | Comandos explicados · Recorrido paso a paso | Contenido de la unidad |
| Diagnóstico | Diagnóstico | Criterios de aceptación |
| Evaluación y cierre | Criterios · Evaluación · GATE | Condiciones de cierre · Cierre |
🖥 Presentación del ISS
Presentación de la unidad. Diapositivas de ISS-04 — Seeders con Faker (8 diapositivas). Se visualiza aquí, dentro del sitio; no hace falta descargar nada para estudiarla.
🎬 Video explicativo
Recorrido audiovisual de la unidad. Este video explica, bloque por bloque, los seeders del ISS-04: por qué quedan fuera del recorrido HTTP, las guardas de
seedClients, Faker ybulkCreate,resolveSeedCounts,runAllSeeders, el archivo realclients.seeder.tsy el GATE.
8:20 min · narración en español · subtítulos activables desde el reproductor.
ISS-04 — Cuaderno de aprendizaje visual
Tema
Seeders con Faker: generar datos falsos por feature con @faker-js/faker y ejecutarlos desde un orquestador externo (SeedersRunner) que recibe la cantidad por entidad.
Fuente técnica autoritativa
| Archivo fuente | ../manual/05-ISS-04-seeders-faker.md |
| Estado | Solo lectura — este cuaderno no modifica el ISS |
| Alcance | Seeder del feature clients (clients.seeder.ts), conteos por entidad (counts.ts), orquestador externo (index.ts) y el script npm run db:seed |
El ISS manda; el cuaderno explica. Todo el contenido técnico del ISS (comandos, rutas, versiones y criterios) aparece aquí íntegro y verbatim más abajo, en la sección Recorrido del ISS, paso a paso. Lo único que añade este cuaderno es el por qué.
Pregunta que responde: ¿de dónde sale cada dato técnico de este cuaderno?
Regla del ISS
Objetivo: datos falsos por feature (Faker) y un orquestador externo que ejecuta todos los seeders enviando la cantidad por entidad. Bloqueado por: ISS-03-A (modelo); recomendado tras ISS-03-E — ambos en ISS-03.
La condición que el propio ISS exige para darse por terminado es doble: el script npm run db:seed debe funcionar y la cantidad debe poder variarse sin tocar el código, ya sea por CLI (npm run db:seed -- --clients=20) o por variable de entorno (SEED_CLIENTS=5). Los seeders escriben con el modelo directamente, fuera del recorrido HTTP.
Pregunta que responde: ¿qué tiene que pasar para poder dar este ISS por bueno?
Cómo leer este cuaderno
Cada concepto se presenta tres veces, desde tres ángulos distintos:
CONCEPTO
│
┌───────────┼───────────┐
▼ ▼ ▼
EXPLICACIÓN CÓDIGO VISUAL
│ │ │
¿qué es? ¿dónde está? ¿cómo lo
¿por qué? ¿qué hace? visualizo?
¿para qué? ¿cómo opera? ¿con qué
se relaciona?
Pregunta que responde: ¿cómo está organizado este cuaderno y por qué se enseña todo tres veces?
El recorrido de lectura es siempre el mismo:
Pregunta que responde: ¿en qué orden recorro cada concepto dentro del cuaderno?
Y cada cuaderno contiene los mismos seis componentes:
| Componente | Dónde vive | Para qué sirve |
|---|---|---|
| Texto | todas las secciones | entender el por qué |
| Código | Recorrido del ISS |
ver el qué exacto (verbatim del ISS) |
| Diagramas | Mapa mental, Mapa del backend, Flujos |
ver el cómo se conecta |
| Preguntas | Evaluación |
comprobar que entendiste |
| Evaluación | Evaluación |
practicar y autoevaluarte |
| GATE | GATE |
saber si puedes pasar al siguiente ISS |
Ruta de aprendizaje
Esta ruta es específica de ISS-04: primero el seeder del feature, después el orquestador, y al final el script y la variación de cantidad.
Instalar @faker-js/faker (dev)
↓
Escribir clients.seeder.ts (seedClients)
↓
Escribir counts.ts (resolveSeedCounts)
↓
Escribir index.ts (runAllSeeders)
↓
Parchear package.json (db:seed)
↓
Ejecutar y variar la cantidad
↓
Verificar (GATE)
Pregunta que responde: ¿cuál es el camino concreto que sigo para completar este ISS?
Índice
- Ficha del ISS
- Mapa mental del ISS
- Mapa del backend
- Árbol de archivos
- Anatomía del código
- Flujos
- Comandos explicados
- Recorrido del ISS, paso a paso
- Diagnóstico
- Conexión con el resto del curso
- Criterios de aceptación
- Evaluación
- Glosario
- GATE
Ficha del ISS
| Campo | Valor |
|---|---|
| ISS | ISS-04 |
| Título | Seeders con Faker (feature + runner) |
| Objetivo | Datos falsos por feature (Faker) y un orquestador externo que ejecuta todos los seeders enviando la cantidad por entidad |
| Fase | Fase I — Business |
| Tecnología principal | @faker-js/faker ^10.6.0 + TypeScript + Sequelize |
| Depende de | ISS-03 — Feature Client (CRUD por capas) (ISS-03-A modelo; recomendado tras ISS-03-E) |
| Habilita | ISS-06 — Feature ProductType |
| Archivos creados | src/features/business/clients/clients.seeder.ts, src/database/seeders/counts.ts, src/database/seeders/index.ts |
| Archivos parcheados | package.json (script db:seed) |
| Componentes incorporados | Seeder del feature clients + SeedCounts/resolveSeedCounts + SeedersRunner (runAllSeeders) |
| Verificación principal | npm run db:seed inserta filas; --clients=20 y SEED_CLIENTS=5 cambian la cantidad |
| Resultado esperado | Datos falsos de clients en la BD, con conteo configurable por default, env o CLI |
| GATE | db:seed idempotente y variedad de cantidad comprobada; npm run dev arranca sin error |
Qué implementamos AHORA
- Un seeder por feature:
clients.seeder.tsexportaseedClients(count)y usa Faker para construir filas falsas. - Un orquestador externo (
src/database/seeders/index.ts,runAllSeeders) que vive fuera del feature, prueba la conexión, hacesyncy llama a los seeders. - Un archivo de conteos (
counts.ts) conSeedCounts,DEFAULT_SEED_COUNTSyresolveSeedCounts. - El script
db:seedenpackage.json, con prioridad CLI > env > default. - Idempotencia: si ya hay filas en
clients, el seeder se omite.
Qué todavía NO implementamos
| No se implementa aquí | Llega en |
|---|---|
| Documentación OpenAPI / Swagger UI | ISS-05 |
Segunda feature (product-types) y sus seeders |
ISS-06 |
products y asociaciones |
ISS-07 |
sales y product-sales (seeders con reglas de negocio replicadas) |
ISS-08 |
Capa de seguridad (JWT, bcrypt, AppError) |
ISS-09 |
Seeders de users, roles, resources y pivotes |
ISS-10 … ISS-12 |
Ojo con la trampa habitual: los seeders no son parte del recorrido
HTTP → Controller → Service → Repository. Se ejecutan por consola y escriben con el modelo; por eso no usan DTOs ni services.
Mapa mental del ISS
mindmap
root((ISS-04<br/>Seeders Faker))
Objetivo
Datos falsos por feature
Orquestador externo
Seeder del feature
clients.seeder.ts
seedClients count
Idempotente
Conteos
SeedCounts
default 10
env SEED_CLIENTS
CLI clients N
Runner
database seeders index.ts
testConnection
sync
runAllSeeders
Script
db seed
GATE
Ejecutar y variar cantidad
Pregunta que responde: ¿de qué trata este ISS y qué piezas lo componen?
Mapa del backend
Esta representación responde siempre a la misma pregunta: ¿en qué parte del backend estamos?
IMPLEMENTADO HASTA ESTE ISS
───────────────────────────
HTTP → Express App ✅
↓
Routes → Controller → Service → Repository → Model → DTO ✅ (feature clients, ISS-03)
↓
Sequelize → BD ✅
🆕 Seeders (fuera del recorrido HTTP) ✅ (ISS-04)
├── features/business/clients/clients.seeder.ts (seedClients)
├── database/seeders/counts.ts (resolveSeedCounts)
└── database/seeders/index.ts (runAllSeeders)
OBJETIVO DE ARQUITECTURA
────────────────────────
🎯 + documentación OpenAPI y Swagger UI (ISS-05)
🎯 + feature product-types (ISS-06)
🎯 + feature products y asociaciones (ISS-07)
🎯 + sales y product-sales (ISS-08)
🎯 + capa de seguridad, RBAC y sesión (ISS-09 … ISS-15)
⬜ Nada del stack de autenticación está construido todavía
Pregunta que responde: ¿qué capas del backend existen ya y cuáles siguen siendo objetivo?
Los seeders se añaden al lado de la cadena de capas, no dentro de ella: son la vía de datos por consola, paralela a la vía HTTP.
Árbol de archivos
Leyenda: ★ = creado o trabajado en este ISS · △ = existente parcheado en este ISS.
Estructura antes
src/
├── config/
├── database/
│ ├── db.ts (sequelize, testConnection)
│ └── seeders/ ← todavía no existe
├── features/
│ └── business/
│ └── clients/ (feature completo de ISS-03)
│ ├── client.model.ts
│ ├── clients.controller.ts
│ ├── clients.repository.ts
│ ├── clients.routes.ts
│ ├── clients.service.ts
│ └── dto/
├── routes/
├── shared/
└── server.ts
package.json
Pregunta que responde: ¿qué archivos existían ya antes de empezar este ISS?
Archivos creados / modificados en este ISS
★ src/features/business/clients/clients.seeder.ts seeder del feature
★ src/database/seeders/counts.ts conteos por entidad
★ src/database/seeders/index.ts SeedersRunner
△ package.json script db:seed
Pregunta que responde: ¿qué toca exactamente este ISS y con qué rol?
Estructura después
src/
├── config/
├── database/
│ ├── db.ts
│ └── seeders/ ★ (nuevo)
│ ├── counts.ts ★
│ └── index.ts ★
├── features/
│ └── business/
│ └── clients/
│ ├── client.model.ts
│ ├── clients.controller.ts
│ ├── clients.repository.ts
│ ├── clients.routes.ts
│ ├── clients.service.ts
│ ├── clients.seeder.ts ★
│ └── dto/
├── routes/
├── shared/
└── server.ts
package.json △ (script db:seed añadido)
Pregunta que responde: ¿cómo queda el proyecto después de este ISS?
Anatomía del código
Archivo: src/features/business/clients/clients.seeder.ts
Propósito
Generar filas falsas de Client con Faker. Es la pieza que vive dentro del feature y exporta seedClients(count: number): Promise<number>.
Explicación
- Criterios de entrada — si
count <= 0, imprime un aviso y devuelve0sin tocar la BD. - Idempotencia — consulta
Client.count(); si ya hay registros, se omite y devuelve0. La primera línea de defensa contra duplicar datos. - Generación con Faker —
faker.person.fullName(),faker.location.streetAddress()yfaker.phone.number({ style: "national" })construyen cada fila; elemailañade un sufijo alfanumérico de 6 caracteres para reducir colisiones. - Escritura masiva —
Client.bulkCreate(rows), nocreate()fila a fila: una sola sentencia para N filas. - Contrato de retorno — devuelve el número de registros insertados (o
0si se omitió).
Se conecta con
- Entrada: la llama
runAllSeeders(ensrc/database/seeders/index.ts) concounts.clients. - Salida: usa el modelo
Client(y por debajo Sequelize) directamente; no pasa por DTOs ni service.
Archivo: src/database/seeders/counts.ts
Propósito
Centralizar cuántos registros genera cada entidad, con una prioridad clara: CLI > env > default.
Explicación
- Tipo
SeedCounts— declara las claves por entidad (clients: number) y deja comentadas las futuras (users,roles,products). DEFAULT_SEED_COUNTS— el valor por defecto (clients: 10).resolveSeedCounts(argv)— parte del default, lo pisa conprocess.env.SEED_CLIENTSsi existe y no está vacío, y luego recorreargvbuscando argumentos con forma--clave=valor.- Validación implícita — un argumento CLI solo se aplica si
key in counts, es decir, si la entidad ya existe en el objeto.
Se conecta con
- Entrada: la llaman
runAllSeeders()(sin argumentos, leeprocess.argv.slice(2)por defecto). - Salida: devuelve un
SeedCountslisto para pasar a cada seeder.
Archivo: src/database/seeders/index.ts
Propósito
Ser el orquestador externo: importa los seeders de los features y los ejecuta en orden, precargando la configuración y la conexión.
Explicación
- Carga de entorno —
dotenv.config()antes de tocar la BD, para que las credenciales estén disponibles. - Import con efecto secundario — importa
client.modelpara garantizar que el modelo esté registrado en Sequelize antes delsync. runAllSeeders()— resuelve los conteos, los imprime, llama atestConnection()(y lanza si no hay conexión), ejecutasequelize.sync({ force: false, alter: true })y luego llama a los seeders en ordenpadres → hijos.- Ejecución directa — el bloque
if (require.main === module)permite ejecutarlo conts-node, cierra Sequelize y sale con código0o1.
Se conecta con
- Entrada: lo dispara el script
db:seeddepackage.json(ts-node -- src/database/seeders/index.ts). - Salida: usa
sequelize,testConnectionyseedClients.
Flujos
sequenceDiagram
autonumber
participant Dev as "Desarrollador"
participant Npm as "npm run db:seed"
participant Runner as "runAllSeeders"
participant DB as "Sequelize + BD"
participant Seeder as "seedClients"
Dev->>Npm: ejecuta el script
Npm->>Runner: ts-node src/database/seeders/index.ts
Runner->>Runner: resolveSeedCounts()
Runner->>DB: testConnection()
DB-->>Runner: true
Runner->>DB: sync force false alter true
Runner->>Seeder: seedClients(counts.clients)
Seeder->>DB: Client.count()
DB-->>Seeder: 0
Seeder->>DB: Client.bulkCreate(rows)
Seeder-->>Runner: count insertado
Runner-->>Dev: SeedersRunner finalizado
Pregunta que responde: ¿qué ocurre paso a paso cuando ejecuto
npm run db:seed?
Comandos explicados
npm install -D @faker-js/faker@^10.6.0
COMANDO
↓
npm install -D @faker-js/faker@^10.6.0
↓
QUÉ HACE
Instala Faker como dependencia de desarrollo.
↓
POR QUÉ SE NECESITA
Es la librería que genera nombres, direcciones y teléfonos falsos.
Va en -D porque solo la usan los scripts de seed, no la API en
producción.
↓
QUÉ CREA O MODIFICA
package.json (devDependencies) y package-lock.json.
↓
RESULTADO ESPERADO
La versión ^10.6.0 registrada en devDependencies.
↓
CÓMO VERIFICARLO
npm ls @faker-js/faker (o revisar package.json).
npm run db:seed
COMANDO
↓
npm run db:seed
↓
QUÉ HACE
Ejecuta src/database/seeders/index.ts con ts-node.
↓
POR QUÉ SE NECESITA
Es la vía por consola para poblar la BD con datos falsos.
↓
QUÉ CREA O MODIFICA
Filas nuevas en las tablas (clients) si están vacías.
↓
RESULTADO ESPERADO
Mensajes de conteos y "clients: insertados N registro(s) falsos".
↓
CÓMO VERIFICARLO
Volver a ejecutarlo: debe responder "ya hay N registro(s), se omite".
npm run db:seed -- --clients=20
COMANDO
↓
npm run db:seed -- --clients=20
↓
QUÉ HACE
Pasa el argumento --clients=20 al script (el `--` separa los args de npm
de los args del script).
↓
POR QUÉ SE NECESITA
Demuestra que la cantidad se configura por CLI sin editar código.
↓
QUÉ CREA O MODIFICA
Filas nuevas según el conteo recibido (si la tabla estaba vacía).
↓
RESULTADO ESPERADO
Conteo clients = 20 en el log del runner.
↓
CÓMO VERIFICARLO
Ver "📊 Conteos: { clients: 20 }" en la salida.
SEED_CLIENTS=5 npm run db:seed
COMANDO
↓
SEED_CLIENTS=5 npm run db:seed
↓
QUÉ HACE
Define la variable de entorno SEED_CLIENTS solo para ese proceso.
↓
POR QUÉ SE NECESITA
Demuestra la segunda vía de configuración (env) del resolver.
↓
QUÉ CREA O MODIFICA
Filas nuevas según el conteo por entorno (si la tabla estaba vacía).
↓
RESULTADO ESPERADO
Conteo clients = 5 en el log del runner.
↓
CÓMO VERIFICARLO
Ver "📊 Conteos: { clients: 5 }" en la salida.
npm run dev
COMANDO
↓
npm run dev
↓
QUÉ HACE
Arranca el servidor Express en modo desarrollo.
↓
POR QUÉ SE NECESITA
Es el cierre del ISS: comprobar que los cambios no rompieron la App.
↓
QUÉ CREA O MODIFICA
Nada persistente: solo levanta el proceso del servidor.
↓
RESULTADO ESPERADO
El servidor arranca sin error.
↓
CÓMO VERIFICARLO
Que la consola no muestre excepciones; detenerlo con Ctrl+C.
Recorrido del ISS, paso a paso
A partir de aquí viene el contenido técnico completo del ISS, verbatim: su objetivo, sus criterios y sus bloques de código. Se reproduce sin resumir y sin reformatear; solo se han degradado los encabezados un nivel para que aniden bajo esta sección, y se han reescrito los enlaces relativos hacia ../manual/.
Fase I: Business — ISS-04 — Seeders con Faker (feature + runner)
Contexto mínimo (autosuficiente). Si abres este archivo aislado —o lo llevas a otra IA—, esto es lo que hay que saber antes de ejecutarlo. - Proyecto:
app-storelab-express-ii— Express 5 + TypeScript + Sequelize, arquitectura por features, Fase I solo Business (sin auth ni roles). - Recorrido obligatorio de una petición:HTTP → Controller → Service → Repository → Model → Sequelize → BD. Ninguna capa se salta a la siguiente. - Diseño de datos (columnas, tipos, FKRESTRICT, índices, transacciones):../bd-storelab.md, Fase I — Business. - Capas, convenciones y reglas transversales:00-contexto.md.
Este ISS Título Seeders con Faker (feature + runner) Feature / tabla clients(seeder)API npm run db:seedDepende de ISS-03 — Feature Client (CRUD por capas) Habilita ISS-06 — Feature ProductType
Contenido de este ISS
- 9.1 Seeder dentro del feature Client
- 9.2 SeedersRunner + conteos por entidad (
database/seeders)
Objetivo: datos falsos por feature (Faker) y un orquestador externo que ejecuta todos los seeders enviando la cantidad por entidad.
Bloqueado por: ISS-03-A (modelo); recomendado tras ISS-03-E — ambos en ISS-03.
Criterios de aceptación (ISS-04) — consolidados
- [ ] 9.1 Existe
features/business/clients/clients.seeder.tscon@faker-js/faker, recibecount, es idempotente - [ ] 9.2 Existe
database/seeders/index.ts(SeedersRunner) que llama seeders de features - [ ] 9.2 Existe
database/seeders/counts.tscon cantidad por entidad (default / env / CLI) - [ ] Script
npm run db:seedfunciona - [ ] Se puede variar cantidad:
npm run db:seed -- --clients=20oSEED_CLIENTS=5
Diseño
| Pieza | Ubicación | Rol |
|---|---|---|
| Seeder del feature | src/features/business/clients/clients.seeder.ts |
Genera filas falsas de Client |
| Conteos | src/database/seeders/counts.ts |
clients: N (y futuras entidades) |
| Runner | src/database/seeders/index.ts |
Importa seeders de features y los ejecuta en orden |
Los seeders son scripts, no la API. Viven fuera del recorrido
HTTP → Controller → Service → Repository: se ejecutan por consola (npm run db:seed) y escriben con el modelo directamente. Por eso no usan los DTOs ni el service, y cuando necesitan una regla del dominio la replican y la documentan (ej.product-sales.seeder.tsrecalculasubtotal/totalcon la misma fórmula querecalculateSaleTotals). Así el código de la API no arrastra dependencias de scripts.
9.1 Seeder dentro del feature Client
Criterios
- [ ]
seedClients(count: number)exportado desde el feature - [ ] Usa
@faker-js/faker - [ ] Si ya hay filas, no duplica
: > src/features/business/clients/clients.seeder.ts
cat >> src/features/business/clients/clients.seeder.ts << 'EOF'
import { faker } from "@faker-js/faker";
import { Client } from "./client.model";
/**
* Seeder del feature Client (datos falsos con @faker-js/faker).
* Se invoca desde `src/database/seeders` (SeedersRunner), no desde la App.
*
* Idempotente: si ya hay filas, no vuelve a insertar.
*/
export async function seedClients(count: number): Promise<number> {
if (count <= 0) {
console.log("⏭️ clients: count=0, se omite");
return 0;
}
const existing = await Client.count();
if (existing > 0) {
console.log(`⏭️ clients: ya hay ${existing} registro(s), se omite seeder`);
return 0;
}
const rows = Array.from({ length: count }, (_, i) => ({
name: faker.person.fullName(),
address: faker.location.streetAddress(),
phone: faker.phone.number({ style: "national" }),
email: `client.${i}.${faker.string.alphanumeric(6)}@example.com`.toLowerCase(),
password: "Password123!",
status: "active" as const,
}));
await Client.bulkCreate(rows);
console.log(`✅ clients: insertados ${count} registro(s) falsos`);
return count;
}
EOF
9.2 SeedersRunner + conteos por entidad (database/seeders)
Criterios
- [ ] Runner fuera del feature en
src/database/seeders/ - [ ] Cantidad configurable por feature (
clients, …)
9.2.1 Conteos
: > src/database/seeders/counts.ts
cat >> src/database/seeders/counts.ts << 'EOF'
/**
* Cantidad de registros por feature/entidad.
* Prioridad: CLI (--clients=N) > env (SEED_CLIENTS) > default de este archivo.
*
* Cuando agregues features, suma aquí la clave y léela en el runner.
*/
export type SeedCounts = {
clients: number;
// users?: number;
// roles?: number;
// products?: number;
};
export const DEFAULT_SEED_COUNTS: SeedCounts = {
clients: 10,
};
export function resolveSeedCounts(argv: string[] = process.argv.slice(2)): SeedCounts {
const counts: SeedCounts = { ...DEFAULT_SEED_COUNTS };
const envClients = process.env.SEED_CLIENTS;
if (envClients !== undefined && envClients !== "") {
counts.clients = Number(envClients);
}
for (const arg of argv) {
const m = arg.match(/^--([a-zA-Z_]+)=(\d+)$/);
if (!m) continue;
const key = m[1] as keyof SeedCounts;
const value = Number(m[2]);
if (key in counts) {
counts[key] = value;
}
}
return counts;
}
EOF
9.2.2 Runner
: > src/database/seeders/index.ts
cat >> src/database/seeders/index.ts << 'EOF'
import dotenv from "dotenv";
import { sequelize, testConnection } from "../db";
import "../../features/business/clients/client.model";
import { seedClients } from "../../features/business/clients/client.seeder";
import { resolveSeedCounts } from "./counts";
dotenv.config();
/**
* SeedersRunner — ejecuta TODOS los seeders de features.
*
* Ubicación: `src/database/seeders/` (orquestación fuera de cada feature).
* Cada feature exporta su seeder (ej. `features/business/clients/clients.seeder.ts`).
*
* Uso:
* npm run db:seed
* npm run db:seed -- --clients=20
* SEED_CLIENTS=5 npm run db:seed
*/
export async function runAllSeeders(): Promise<void> {
const counts = resolveSeedCounts();
console.log("🌱 Iniciando SeedersRunner...");
console.log("📊 Conteos:", counts);
const ok = await testConnection();
if (!ok) {
throw new Error("No hay conexión a la base de datos");
}
await sequelize.sync({ force: false, alter: true });
// Orden: business (padres → hijos)
await seedClients(counts.clients);
console.log("🌱 SeedersRunner finalizado");
}
if (require.main === module) {
runAllSeeders()
.then(async () => {
await sequelize.close();
process.exit(0);
})
.catch(async (err) => {
console.error("❌ Error en seeders:", err);
await sequelize.close();
process.exit(1);
});
}
EOF
PARCHE — package.json ya existe.
Dentro de "scripts", debajo de "dev": "...", añadir la coma al final de dev (si falta) y la clave:
Fragmento esperado:
"scripts": {
"build": "tsc",
"dev": "nodemon --watch src --ext ts --exec ts-node -- src/server.ts",
"db:seed": "ts-node -- src/database/seeders/index.ts"
}
Verificación ISS-04
Al agregar otra entidad (patrón):
- Archivo nuevo
features/.../<plural>.seeder.tscon: >+cat >>. - PARCHE
counts.ts: dentro deSeedCounts/ defaults, añadir clave (ej.products: 10). - PARCHE
database/seeders/index.ts: debajo deawait seedClients(...), añadir la llamada al nuevo seeder.
Cierre del ISS
El servidor debe arrancar sin error. Detenerlo con Ctrl+C antes de continuar.
Diagnóstico
| Síntoma | Causa probable | Solución |
|---|---|---|
Cannot find module '@faker-js/faker' |
Faker no instalado o instalado solo en otro directorio | npm install -D @faker-js/faker@^10.6.0 |
| El seeder imprime «ya hay N registro(s), se omite» | La tabla clients no está vacía (idempotencia) |
Es el comportamiento esperado; vaciar la tabla o usar otra base si quieres ver la inserción |
No hay conexión a la base de datos |
Credenciales o motor de BD caídos | Revisar .env y que el motor acepte conexiones (ISS-02) |
El conteo no cambia con --clients=20 |
El argumento no llegó al script (falta el -- de npm) |
Usar npm run db:seed -- --clients=20 |
SEED_CLIENTS=5 no tiene efecto |
Se ejecutó sin la variable o el runner leyó otro valor | Revisar que la variable se exporte para ese proceso |
| Error al importar el modelo en el runner | Modelo no registrado antes del sync |
El runner importa client.model a propósito; no borres ese import |
Pregunta que responde: si algo falla al sembrar los datos, ¿por dónde empiezo a mirar?
Conexión con el resto del curso
- Lo habilita: ISS-03 — Feature Client. Sin el modelo
Clientno hay nada que sembrar. - Lo usa: ISS-06 — Feature ProductType y siguientes, que añaden claves a
counts.tsy llamadas nuevas en el runner. - Patrón que reutiliza: el registry externo. El mismo patrón (
counts+indexfuera del feature) reaparecerá en ISS-05 para Swagger (src/swagger/index.ts). - Regla transversal: los seeders replican y documentan las reglas de negocio que necesiten, en lugar de importar services, para que los scripts no arrastren dependencias de la API.
Pregunta que responde: ¿con qué piezas anteriores y posteriores del curso se conecta este ISS?
Criterios de aceptación
Los del ISS, textuales:
- [ ] 9.1 Existe
features/business/clients/clients.seeder.tscon@faker-js/faker, recibecount, es idempotente - [ ] 9.2 Existe
database/seeders/index.ts(SeedersRunner) que llama seeders de features - [ ] 9.2 Existe
database/seeders/counts.tscon cantidad por entidad (default / env / CLI) - [ ] Script
npm run db:seedfunciona - [ ] Se puede variar cantidad:
npm run db:seed -- --clients=20oSEED_CLIENTS=5
Criterios internos de cada bloque (también del ISS):
- [ ]
seedClients(count: number)exportado desde el feature - [ ] Usa
@faker-js/faker - [ ] Si ya hay filas, no duplica
- [ ] Runner fuera del feature en
src/database/seeders/ - [ ] Cantidad configurable por feature (
clients, …)
Evaluación
Preguntas de comprensión
-
¿Por qué los seeders viven en
database/seeders/y no dentro del recorrido de capas? Porque son scripts de consola, no peticiones HTTP. Se ejecutan connpm run db:seedy escriben directamente con el modelo; usar el service o los DTOs acoplaría la API a los scripts. ElSeedersRunnerse coloca fuera de los features para orquestar a todos sin que ninguno dependa de otro. -
¿Qué significa que
seedClientssea idempotente y cómo lo logra? Significa que ejecutarlo varias veces no duplica datos. Lo logra consultando primeroClient.count(): si ya hay filas, imprime un aviso y devuelve0sin insertar. -
¿Cuál es la prioridad de configuración de la cantidad y por qué ese orden? CLI > env > default. El argumento explícito (
--clients=20) es la intención más inmediata y concreta; la variable de entorno sirve para entornos (por ejemplo CI); y el default (10) garantiza que el comando funcione sin configuración. -
¿Qué hace
sequelize.sync({ force: false, alter: true })en el runner y por qué es importante? Sincroniza los modelos con la BD sin borrar (force: false) y ajustando la estructura (alter: true). Es importante para que las tablas existan antes de insertar filas, incluso en una base recién creada. -
¿Por qué el runner comprueba
testConnection()antes de sembrar? Para fallar con un mensaje claro («No hay conexión a la base de datos») en lugar de dejar que el error salga disfrazado como un fallo de Faker o debulkCreate. Diagnóstico temprano. -
¿Qué pasaría si el runner no importara
client.model? El modelo podría no estar registrado en Sequelize al ejecutarsync, y la tablaclientsno se crearía o el seeder fallaría al usarlo. Ese import con efecto secundario es deliberado. -
El comando
npm run db:seed -- --clients=20lleva--dos veces. ¿Por qué? El primer--es el que npm usa para separar sus propias banderas de las del script; lo que va después llega aprocess.argvy lo interpretaresolveSeedCounts.
Ejercicios
Ejercicio 1 — Traza el resolver.
Con DEFAULT_SEED_COUNTS = { clients: 10 }, ejecuta mentalmente resolveSeedCounts(["--clients=7", "--products=3"]). ¿Qué devuelve y por qué se ignora --products?
Respuesta razonada
Devuelve `{ clients: 7 }`. El default es `10`, no hay `SEED_CLIENTS`, y el bucle aplica `--clients=7` porque `clients in counts`. `--products=3` **se ignora** porque la clave `products` todavía no existe en `SeedCounts` (está comentada); el resolver solo acepta claves ya declaradas. Ese detalle evita que un typo en CLI pase desapercibido.Ejercicio 2 — Sembrar dos veces.
Explica qué imprime el segundo npm run db:seed consecutivo y en qué línea del seeder se decide.
Respuesta razonada
El segundo arranque vuelve a resolver conteos, prueba conexión y hace `sync`, pero al llegar a `seedClients` la consulta `Client.count()` devuelve un número mayor que 0, así que imprime «clients: ya hay N registro(s), se omite seeder» y devuelve `0`. No hay inserción. La decisión está en el bloque `if (existing > 0)` del seeder.Ejercicio 3 — Añadir una entidad (diseño). Siguiendo el patrón del ISS, enumera los tres pasos que tendrías que dar para sembrar una entidad nueva, sin escribir el código.
Respuesta razonada
1. Crear el archivo del seeder dentro del feature (`features/.../Glosario
| Término | Significado |
|---|---|
| Seeder | Script que puebla la BD con datos (en este ISS, falsos). |
| Faker | Librería @faker-js/faker que genera datos aleatorios realistas. |
| SeedersRunner | Orquestador externo (runAllSeeders) que ejecuta todos los seeders. |
| Idempotencia | Propiedad de una operación repetible que no cambia el resultado al repetirse. |
bulkCreate |
Inserción masiva de varias filas en una sola operación de Sequelize. |
count |
Número de registros; base de la comprobación de idempotencia. |
| CLI > env > default | Orden de prioridad con que se resuelve la cantidad a sembrar. |
GATE
Para cerrar el ISS-04, ejecuta en este orden:
Resultado esperado: el runner imprime los conteos y el resultado de cada seeder; la primera ejecución inserta y las siguientes respetan la idempotencia y la cantidad indicada.
Y el cierre del ISS, comprobar que la App sigue en pie:
Resultado esperado: el servidor arranca sin error. Detenerlo con Ctrl+C antes de continuar.
Checklist de cierre:
- [ ]
clients.seeder.tscon Faker,counte idempotencia - [ ]
database/seeders/index.ts(SeedersRunner) llama a los seeders de features - [ ]
database/seeders/counts.tscon default / env / CLI - [ ]
npm run db:seedfunciona - [ ]
npm run db:seed -- --clients=20ySEED_CLIENTS=5 npm run db:seedcambian la cantidad - [ ]
npm run devarranca sin error
Con todos en verde, el ISS-04 está cumplido y puedes pasar al ISS-05 — Swagger / OpenAPI, donde el mismo patrón de registry externo se usa para montar la documentación.
Navegación de la ruta: ← ISS-03 · 🛠 Construir · ↑ Ruta Express · → ISS-04 · 🛠 Construir