📚 Unidad ISS-02 · Infraestructura de base de datos — 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 Infraestructura de base de datos 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 |
🖥 Presentaciones del ISS
Dos presentaciones de la unidad. Material complementario de ISS-02 — Infraestructura de base de datos. Se conservan ambas porque su contenido y propósito son distintos.
Presentación 1 — Infraestructura de Base de Datos y ORM Sequelize
Presentación 2 — Database Infrastructure Blueprint
🎬 Video explicativo
Recorrido audiovisual de la unidad. Este video explica, bloque por bloque, la infraestructura de datos del ISS-02: los drivers de Sequelize, el
.envmulti-motor, el módulosrc/database/db.ts(imports, interfaz, mapa de configuraciones, instancia y pool, y sus funciones exportadas), los comandos, los flujos y el GATE.
14:54 min · narración en español · subtítulos activables desde el reproductor.
ISS-02 — Cuaderno de aprendizaje visual
Tema
Infraestructura de base de datos: instalar los drivers de Sequelize, declarar el .env multi-motor y crear el módulo src/database/db.ts que conecta, informa y prueba la base de datos.
Fuente técnica autoritativa
| Archivo fuente | ../manual/03-ISS-02-infraestructura-bd.md |
| Estado | Solo lectura — este cuaderno no modifica el ISS |
| Alcance | 223 líneas, 9 bloques de código, 1 lista de criterios consolidados (4 ítems) |
El archivo 03-ISS-02-infraestructura-bd.md es la fuente autoritativa y de solo lectura. Todo su contenido técnico —comandos, versiones, variables y archivos— aparece aquí íntegro y verbatim en la sección Recorrido del ISS, paso a paso. El ISS manda; el cuaderno explica el por qué.
Regla del ISS
Objetivo: drivers +
.env+ módulo Sequelize + carpetaseeders/. Bloqueado por: ISS-01. Criterio de cierre:npx tsc --noEmitOK.
La condición que el propio ISS exige es que la infraestructura de datos compile y quede lista para usarse: los drivers instalados, el .env con los bloques de los cuatro motores, src/database/db.ts exportando sequelize, getDatabaseInfo y testConnection, y la carpeta seeders/ reservada sin lógica. Nada de modelos ni consultas todavía: eso es ISS-03.
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: ¿desde qué tres ángulos voy a estudiar cada concepto de este ISS?
El recorrido de lectura es siempre el mismo:
Primero entiendes qué se construye y por qué; después ves el código exacto que lo construye (en el cuerpo incrustado del ISS); finalmente lo visualizas con diagramas y mapas. Los seis componentes del cuaderno son:
| Componente | Dónde vive | Para qué sirve |
|---|---|---|
| Texto | todas las secciones | entender el por qué de cada decisión |
| Código | Recorrido del ISS |
ver el qué exacto, sin resúmenes |
| Diagramas | Mapa mental, Mapa del backend, Árbol de archivos, Flujos |
ver cómo se conecta todo |
| Preguntas | Evaluación |
comprobar que entendiste |
| Evaluación | Evaluación |
practicar y autoevaluarte con respuestas razonadas |
| GATE | GATE |
saber si puedes pasar al siguiente ISS |
Pregunta que responde: ¿qué seis componentes tiene el cuaderno y en qué sección busco cada uno?
Ruta de aprendizaje
Esta ruta es específica de este ISS: sigue, en orden, lo que el ISS-02 construye de verdad.
Instalar drivers Sequelize (4 motores)
↓
Instalar @types/sequelize
↓
Crear .env con PORT + DB_ENGINE + bloques por motor
↓
Escribir src/database/db.ts (mapa de configuraciones)
↓
Exportar sequelize, getDatabaseInfo y testConnection
↓
Reservar la carpeta src/database/seeders/ (sin lógica)
↓
Verificar tipos (npx tsc --noEmit)
↓
Arrancar el servidor (npm run dev) → GATE
Pregunta que responde: ¿en qué orden debo ejecutar los pasos del ISS-02 para no dejarme ninguno?
Fíjate en lo que no aparece todavía: no hay modelos, ni asociaciones, ni seeders con datos, ni rutas. El ISS-02 solo prepara el canal hacia la base de datos.
Índice
- Tema
- Fuente técnica autoritativa
- Regla del ISS
- Cómo leer este cuaderno
- Ruta de aprendizaje
- Ficha del ISS
- Mapa mental del ISS
- Mapa del backend
- Árbol de archivos
- Anatomía del código
- Comandos explicados
- Flujos
- Diagnóstico
- Recorrido del ISS, paso a paso
- Criterios de aceptación
- Evaluación
- Conexión con el resto del curso
- Glosario
- GATE
Ficha del ISS
| Campo | Valor |
|---|---|
| ISS | ISS-02 |
| Título | Infraestructura de base de datos |
| Objetivo | Drivers + .env + módulo Sequelize + carpeta seeders/ |
| Fase | Fase I — Business |
| Tecnología principal | Sequelize 6 con drivers multi-motor (mysql2, pg, tedious, oracledb) |
| Depende de | ISS-01 — Esqueleto del proyecto |
| Habilita | ISS-03 — Feature Client (CRUD por capas) |
| Archivos creados | .env y src/database/db.ts |
| Archivos parcheados | package.json (dependencias de Sequelize y @types/sequelize) |
| Componentes incorporados | Drivers multi-motor, variables de entorno, mapa dbConfigurations, export sequelize, getDatabaseInfo, testConnection |
| Verificación principal | npx tsc --noEmit OK |
| Resultado esperado | db.ts importable con los tres exports; el servidor arranca e intenta conectar |
| GATE | npx tsc --noEmit OK y npm run dev sin error |
Qué implementamos AHORA
Este ISS monta la tubería hacia la base de datos:
- Los drivers de Sequelize para cuatro motores: MySQL (
mysql2), PostgreSQL (pg+pg-hstore), SQL Server (tedious) y Oracle (oracledb). - El archivo
.envconPORT, la variable selectoraDB_ENGINEy un bloque de configuración por motor. - El módulo
src/database/db.ts, que construye un mapadbConfigurations, resuelve el motor segúnDB_ENGINEy exportasequelize,getDatabaseInfoytestConnection. - La carpeta
src/database/seeders/reservada, sin lógica implementada.
En términos de arquitectura, esto añade Sequelize → BD (conexión, testConnection y sync) al esqueleto del ISS-01.
Qué todavía NO implementamos
Para que no confundas la infraestructura con el negocio:
| No se implementa aquí | Llega en |
|---|---|
Feature clients (model, repository, service, controller, routes, DTO) |
ISS-03 |
| Cualquier modelo o tabla real | ISS-03 en adelante |
Seeders con datos de prueba (SeedersRunner, counts, @faker-js/faker) |
ISS-04 |
| Asociaciones entre modelos y transacciones | ISS-07 / ISS-08 |
| Swagger de la API | ISS-05 |
| Autenticación y RBAC | ISS-09 … ISS-15 |
Ojo con la trampa habitual: tener
.envydb.tsno significa tener datos. Aquí solo se prepara el canal; el modelo y su tabla nacerán en ISS-03, y elsyncque crea físicamente las tablas se apoya en este módulo.
Mapa mental del ISS
mindmap
root((ISS-02))
Objetivo
Drivers
Archivo .env
Modulo Sequelize
Carpeta seeders
Drivers
sequelize
mysql2
pg
pg-hstore
tedious
oracledb
Archivo .env
PORT
DB_ENGINE
bloques por motor
db.ts
sequelize
getDatabaseInfo
testConnection
pool
Motores
mysql
postgres
mssql
oracle
Verificacion
npx tsc --noEmit
npm run dev
Pregunta que responde: ¿de qué trata el ISS-02 y qué piezas lo componen?
Mapa del backend
Esta representación responde siempre a la misma pregunta: ¿en qué parte del backend estamos? Con el ISS-02, el extremo de datos ya existe, aunque las capas de negocio sigan pendientes.
IMPLEMENTADO HASTA ESTE ISS
───────────────────────────
HTTP ✅
↓
Express App (esqueleto) ✅
↓
Sequelize ✅
├── sequelize (instancia configurada)
├── getDatabaseInfo (motor + config + connectionString)
├── testConnection (authenticate)
└── sync (vía dbConnection del App)
↓
Base de datos ✅ (conexión, testConnection y sync)
OBJETIVO DE ARQUITECTURA
────────────────────────
HTTP → Routes → Controller → Service → Repository → Model → Sequelize → BD
🎯 Routes (ISS-03)
🎯 Controller (ISS-03)
🎯 Service (ISS-03)
🎯 Repository (ISS-03)
🎯 Model (ISS-03)
✅ Sequelize
✅ Base de datos
Pregunta que responde: ¿qué capas del backend existen ya y cuáles siguen siendo objetivo de arquitectura?
El proyecto ya sabe conectarse a la base de datos, pero todavía no tiene nada que guardar: no hay modelos. La conexión y el sync están listos para que el primer feature (ISS-03) los use.
Árbol de archivos
Estructura antes
Al terminar ISS-01 el esqueleto estaba montado, pero sin acceso a datos:
app-storelab-express/
├── package.json
├── tsconfig.json
├── docs/
└── src/
├── server.ts
├── config/
│ └── index.ts
├── database/
│ └── seeders/ # carpeta vacía
├── routes/
├── shared/
│ ├── database/
│ ├── errors/
│ └── http/
└── features/
└── business/
└── clients/
Archivos creados / modificados en este ISS
★ .env # variables de entorno y bloques por motor
★ src/
└── database/
├── db.ts # ★ configuración de Sequelize
└── seeders/ # ya existía; se reafirma vacía (sin lógica)
△ package.json # npm install añade dependencies/devDependencies
Estructura después
app-storelab-express/
├── △ package.json
├── ★ .env
├── tsconfig.json
├── docs/
└── src/
├── server.ts
├── config/
│ └── index.ts
├── database/
│ ├── ★ db.ts
│ └── seeders/ # sin lógica (ISS-04)
├── routes/
├── shared/
│ ├── database/
│ ├── errors/
│ └── http/
└── features/
└── business/
└── clients/
Leyenda: ★ = archivo/carpeta creado o trabajado en este ISS · △ = archivo existente parcheado o modificado.
El único archivo de código nuevo es db.ts. El .env es configuración (y no debe versionarse con credenciales reales). package.json cambia solo porque npm install registra las nuevas dependencias.
Pregunta que responde: ¿qué archivos crea o modifica el ISS-02 y por qué el árbol apenas cambia?
Anatomía del código
El código completo y literal está en el Recorrido del ISS, paso a paso. Aquí se explica qué hace y por qué, sin repetirlo.
Archivo: .env
Propósito
Concentrar la configuración del entorno —puerto y credenciales de base de datos— fuera del código, para no incrustar secretos ni valores específicos de una máquina en el repositorio.
Explicación
PORT=4000— el puerto queApp.settings()usa si no se pasa uno por constructor.DB_ENGINE=mysql— la variable que decide qué motor se usa. Cambiarla es la única acción necesaria para migrar de motor, porquedb.tslee justamente esta clave.- Bloques por motor —
MYSQL_*,POSTGRES_*,MSSQL_*,ORACLE_*. Definir los cuatro desde el principio deja la infraestructura lista para cualquiera de ellos sin tocar el código. .envno se versiona: contiene credenciales. En un proyecto real se sube un.env.examplesin valores y se ignora el.enven git.
Se conecta con
- Entrada: lo lee
dotenv.config()endb.ts(y enconfig/index.ts). - Salida: alimenta
process.env.MYSQL_*,process.env.DB_ENGINE, etc.
Archivo: src/database/db.ts
Propósito
Es el único punto donde el proyecto construye la conexión a la base de datos, decide el motor y expone utilidades para consultar la configuración y probar la conexión.
Explicación
interface DatabaseConfig— tipa la forma de cada configuración (dialect,host,username,password,database,port). Tipar la config evita errores silenciosos al añadir un motor.dbConfigurations— un mapa indexado por motor (mysqlypostgresen el ISS) cuyos valores tipan la forma de la conexión. Cada entrada lee sus variables conprocess.env.*y un valor por defecto, de modo que el proyecto arranque aunque falte alguna variable.selectedEngine = process.env.DB_ENGINE || "mysql"— resuelve el motor activo. SiDB_ENGINEno existe, cae en MySQL.- Validación del motor — si
DB_ENGINEapunta a un motor que no está en el mapa, lanzaError("Motor de base de datos no soportado: ..."). Fallar rápido es mejor que conectar a un motor equivocado. new Sequelize(...)— construye la instancia condialect,logging(activo solo endevelopment) y un pool de conexiones (max: 5,min: 0,acquire: 30000,idle: 10000).getDatabaseInfo()— devuelve{ engine, config, connectionString }. La cadena de conexión sirve para mostrar a qué base te estás conectando sin exponer la contraseña completa.testConnection()— llama asequelize.authenticate(); devuelvetruesi conecta yfalsesi falla, registrando el error en consola. No lanza excepción: devuelve un booleano para que quien lo llama decida.
Se conecta con
- Entrada: lo importa
src/config/index.ts(getDatabaseInfo,testConnection,sequelize) y, en ISS-03+, los repositorios. - Salida: usa
sequelizeydotenv; habla con el motor de base de datos elegido.
Comandos explicados
Ningún comando va sin explicación. Cada grupo se copia idéntico al ISS y se desglosa con el esquema obligatorio.
Instalar los drivers (§3.1)
COMANDO
↓
npm install sequelize@^6.37.8 mysql2@^3.24.4 pg@^8.23.0 pg-hstore@^2.3.4 \
tedious@^20.0.0 oracledb@^7.0.1
npm install -D @types/sequelize@^6.12.0
↓
QUÉ HACE
Instala el ORM Sequelize y los cuatro drivers de motor, más los tipos de
Sequelize como dependencia de desarrollo.
↓
POR QUÉ SE NECESITA
Sequelize no habla con la base de datos por sí solo: necesita el driver del
motor. Instalar los cuatro permite cambiar DB_ENGINE sin reinstalar nada.
↓
QUÉ CREA O MODIFICA
node_modules/ y las dependencias en package.json.
↓
RESULTADO ESPERADO
Sequelize 6.37.x, mysql2 3.24.x, pg 8.23.x y @types/sequelize 6.12.x.
↓
CÓMO VERIFICARLO
npm ls sequelize mysql2 --depth=0
Detalle del ISS:
oracledbsuele requerir herramientas nativas del cliente Oracle. Si la instalación se queja, revisa tus prerrequisitos del sistema antes de seguir.
Crear el .env (§3.1)
COMANDO
↓
: > .env
cat >> .env << 'EOF'
...PORT, DB_ENGINE y los bloques MYSQL_ / POSTGRES_ / MSSQL_ / ORACLE_...
EOF
↓
QUÉ HACE
Vacía (o crea) .env y escribe dentro el puerto, la variable DB_ENGINE y las
credenciales de los cuatro motores.
↓
POR QUÉ SE NECESITA
db.ts lee estas variables para construir la configuración; sin .env, la
conexión usaría solo los valores por defecto.
↓
QUÉ CREA O MODIFICA
El archivo .env en la raíz del proyecto (contenido íntegro en el Recorrido
del ISS).
↓
RESULTADO ESPERADO
.env con PORT=4000 y DB_ENGINE=mysql.
↓
CÓMO VERIFICARLO
test -f .env && grep DB_ENGINE .env
Crear db.ts (§3.2)
COMANDO
↓
: > src/database/db.ts
cat >> src/database/db.ts << 'EOF'
...interface, dbConfigurations, sequelize, getDatabaseInfo, testConnection...
EOF
↓
QUÉ HACE
Crea el módulo de infraestructura que construye la instancia de Sequelize y
expone las tres utilidades.
↓
POR QUÉ SE NECESITA
Es el único lugar donde vive la configuración de la base de datos: cualquier
ISS posterior la importa desde aquí.
↓
QUÉ CREA O MODIFICA
src/database/db.ts (contenido íntegro en el Recorrido del ISS).
↓
RESULTADO ESPERADO
El archivo existe y exporta sequelize, getDatabaseInfo y testConnection.
↓
CÓMO VERIFICARLO
test -f src/database/db.ts && npx tsc --noEmit
Reservar la carpeta de seeders (§3.3)
COMANDO
↓
mkdir -p src/database/seeders
# opcional: touch src/database/seeders/.gitkeep
↓
QUÉ HACE
Garantiza que la carpeta seeders/ existe, sin crear ningún archivo con lógica.
↓
POR QUÉ SE NECESITA
El ISS-02 solo reserva la ubicación; la lógica de seeders llega en ISS-04.
Tener la carpeta fija dónde vivirán esos archivos.
↓
QUÉ CREA O MODIFICA
La carpeta src/database/seeders/ (y opcionalmente .gitkeep).
↓
RESULTADO ESPERADO
Carpeta presente y vacía.
↓
CÓMO VERIFICARLO
test -d src/database/seeders && echo OK
Verificar (§3, cierre)
COMANDO
↓
npx tsc --noEmit
test -f src/database/db.ts && test -f .env && test -d src/database/seeders
↓
QUÉ HACE
Comprueba los tipos sin emitir archivos y verifica que los tres artefactos
del ISS existen.
↓
POR QUÉ SE NECESITA
Es el criterio de cierre: el módulo debe compilar y los archivos deben estar.
↓
QUÉ CREA O MODIFICA
Nada.
↓
RESULTADO ESPERADO
Cero errores de TypeScript y código de salida 0 en los tres test.
↓
CÓMO VERIFICARLO
Que ambos comandos terminen en verde.
COMANDO
↓
npm run dev
↓
QUÉ HACE
Arranca el servidor, que ahora ejecuta dbConnection() e intenta conectar.
↓
POR QUÉ SE NECESITA
Verifica que la infraestructura funciona en tiempo de ejecución, no solo en tipos.
↓
QUÉ CREA O MODIFICA
Un proceso Node en primer plano (ningún archivo).
↓
RESULTADO ESPERADO
El servidor levanta; con la BD disponible, conecta y sincroniza.
↓
CÓMO VERIFICARLO
Ver el log de conexión; detenerlo con Ctrl+C.
Flujos
Cómo decide db.ts qué motor usar. Este es el corazón del ISS-02:
flowchart TD
A["process.env.DB_ENGINE"] --> B{"existe en dbConfigurations"}
B -->|"sí"| C["selectedConfig"]
B -->|"no"| D["throw Error: motor no soportado"]
C --> E["new Sequelize"]
E --> F["export sequelize"]
C --> G["getDatabaseInfo"]
C --> H["testConnection"]
H --> I["sequelize.authenticate"]
Pregunta que responde: ¿cómo decide el proyecto a qué motor de base de datos conectarse?
Y así se usa esa infraestructura durante el arranque del servidor: listen() llama a dbConnection(), que informa el motor, prueba la conexión y sincroniza:
sequenceDiagram
participant Srv as server.ts
participant App as App
participant DB as database/db.ts
participant Seq as Sequelize
participant My as Base de datos
Srv->>App: await app.listen
App->>DB: getDatabaseInfo
DB-->>App: engine + config + connectionString
App->>DB: testConnection
DB->>Seq: authenticate
Seq->>My: conexión
My-->>Seq: OK
Seq-->>DB: true
DB-->>App: true
App->>Seq: sync force/alter
Seq->>My: DDL
App-->>Srv: puerto abierto
Pregunta que responde: ¿qué ocurre entre que arranco el servidor y que la base de datos queda sincronizada?
Observa el orden otra vez: primero la base de datos, después el puerto. Es la regla de oro que ya viste en ISS-01 y que aquí por fin tiene trabajo real.
Diagnóstico
| Síntoma | Causa probable | Solución |
|---|---|---|
ECONNREFUSED al arrancar |
El motor de BD no está levantado o el host/puerto no coinciden | Arrancar el servicio y revisar MYSQL_HOST / MYSQL_PORT en .env |
Access denied for user |
Usuario o contraseña incorrectos en .env |
Corregir MYSQL_USER / MYSQL_PASSWORD |
Unknown database |
La base indicada en MYSQL_NAME no existe |
Crearla, o confiar en el sync según el motor |
Motor de base de datos no soportado |
DB_ENGINE no coincide con ninguna clave del mapa |
Usar mysql o postgres (los definidos en el ISS) |
Cannot find module 'sequelize' |
Falta npm install de §3.1 |
Ejecutar las líneas de instalación del ISS |
Los tipos fallan en db.ts |
Falta @types/sequelize |
npm install -D @types/sequelize@^6.12.0 |
La carpeta seeders/ aparece vacía |
Es lo esperado | La lógica llega en ISS-04; aquí solo se reserva |
Pregunta que responde: si la conexión a la base de datos falla, ¿por dónde empiezo a mirar?
Recorrido del ISS, paso a paso
A partir de aquí viene el contenido técnico completo del ISS, verbatim: sus objetivos, sus criterios, sus comandos y todos sus bloques de código (incluido el contenido íntegro del .env y de db.ts). 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 para que abran bien desde docs/aprendizaje/. No copies los fragmentos de aquí a mano: el generador inserta el cuerpo completo automáticamente.
Fase I: Business — ISS-02 — Infraestructura de base de datos
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 Infraestructura de base de datos Feature / tabla src/database/API — Depende de ISS-01 — Esqueleto del proyecto Habilita ISS-03 — Feature Client (CRUD por capas)
Contenido de este ISS
- 3.1 Drivers Sequelize y
.env - 3.2 Configuración Sequelize (
database/db.ts) - 3.3 Carpeta seeders (reservada)
Objetivo: drivers + .env + módulo Sequelize + carpeta seeders/.
Bloqueado por: ISS-01.
Criterios de aceptación (ISS-02) — consolidados
- [ ] 3.1 Paquetes Sequelize/drivers instalados; existe
.envconDB_ENGINEy bloques de motores - [ ] 3.2 Existe
src/database/db.tsexportandosequelize,getDatabaseInfo,testConnection - [ ] 3.3 Existe carpeta
src/database/seeders/sin lógica implementada aún - [ ]
npx tsc --noEmitOK
3.1 Drivers Sequelize y .env
Criterios de este sub-ítem
- [ ]
sequelize,mysql2,pg,pg-hstore,tedious,oracledbinstalados - [ ]
.envconPORT,DB_ENGINE, MySQL/Postgres/MSSQL/Oracle
npm install sequelize@^6.37.8 mysql2@^3.24.4 pg@^8.23.0 pg-hstore@^2.3.4 \
tedious@^20.0.0 oracledb@^7.0.1
npm install -D @types/sequelize@^6.12.0
: > .env
cat >> .env << 'EOF'
PORT=4000
# Variable para seleccionar el motor de base de datos
DB_ENGINE=mysql
# Configuración para MySQL
MYSQL_HOST=localhost
MYSQL_USER=admin
MYSQL_PASSWORD=MiNiCo57**
MYSQL_NAME=tecnogua
MYSQL_PORT=3306
# Configuración para PostgreSQL
POSTGRES_HOST=localhost
POSTGRES_USER=postgres
POSTGRES_PASSWORD=password
POSTGRES_NAME=almacen_2025_iisem_node
POSTGRES_PORT=5432
# Configuración para SQL Server
MSSQL_HOST=localhost
MSSQL_USER=sa
MSSQL_PASSWORD=password
MSSQL_NAME=almacen_2025_iisem_node
MSSQL_PORT=1433
# Configuración para Oracle
ORACLE_HOST=localhost
ORACLE_USER=ALMACENDB_ADMIN
ORACLE_PASSWORD=password
ORACLE_NAME=xe
ORACLE_PORT=1521
EOF
3.2 Configuración Sequelize (database/db.ts)
Criterios de este sub-ítem
- [ ] Archivo
src/database/db.tscreado - [ ] Exporta
sequelize,getDatabaseInfo,testConnection
: > src/database/db.ts
cat >> src/database/db.ts << 'EOF'
import { Sequelize } from "sequelize";
import dotenv from "dotenv";
dotenv.config();
interface DatabaseConfig {
dialect: string;
host: string;
username: string;
password: string;
database: string;
port: number;
}
const dbConfigurations: Record<string, DatabaseConfig> = {
mysql: {
dialect: "mysql",
host: process.env.MYSQL_HOST || "localhost",
username: process.env.MYSQL_USER || "root",
password: process.env.MYSQL_PASSWORD || "",
database: process.env.MYSQL_NAME || "test",
port: parseInt(process.env.MYSQL_PORT || "3306")
},
postgres: {
dialect: "postgres",
host: process.env.POSTGRES_HOST || "localhost",
username: process.env.POSTGRES_USER || "postgres",
password: process.env.POSTGRES_PASSWORD || "",
database: process.env.POSTGRES_NAME || "test",
port: parseInt(process.env.POSTGRES_PORT || "5432")
}
};
const selectedEngine = process.env.DB_ENGINE || "mysql";
const selectedConfig = dbConfigurations[selectedEngine];
if (!selectedConfig) {
throw new Error(`Motor de base de datos no soportado: ${selectedEngine}`);
}
console.log(`🔌 Conectando a base de datos: ${selectedEngine.toUpperCase()}`);
export const sequelize = new Sequelize(
selectedConfig.database,
selectedConfig.username,
selectedConfig.password,
{
host: selectedConfig.host,
port: selectedConfig.port,
dialect: selectedConfig.dialect as any,
logging: process.env.NODE_ENV === 'development' ? console.log : false,
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
}
}
);
export const getDatabaseInfo = () => {
return {
engine: selectedEngine,
config: selectedConfig,
connectionString: `${selectedConfig.dialect}://${selectedConfig.username}@${selectedConfig.host}:${selectedConfig.port}/${selectedConfig.database}`
};
};
export const testConnection = async (): Promise<boolean> => {
try {
await sequelize.authenticate();
console.log(`✅ Conexión exitosa a ${selectedEngine.toUpperCase()}`);
return true;
} catch (error) {
console.error(`❌ Error de conexión a ${selectedEngine.toUpperCase()}:`, error);
return false;
}
};
EOF
3.3 Carpeta seeders (reservada)
Criterios de este sub-ítem
- [ ]
src/database/seeders/existe (la lógica llega en ISS-04) - [ ]
src/database/seeders/existe sin*.seeder.tsni runner
Verificación del ISS-02
Cierre del ISS
El servidor debe arrancar sin error. Detenerlo con Ctrl+C antes de continuar.
Criterios de aceptación
Los del ISS, textuales:
- [ ] 3.1 Paquetes Sequelize/drivers instalados; existe
.envconDB_ENGINEy bloques de motores - [ ] 3.2 Existe
src/database/db.tsexportandosequelize,getDatabaseInfo,testConnection - [ ] 3.3 Existe carpeta
src/database/seeders/sin lógica implementada aún - [ ]
npx tsc --noEmitOK
Pregunta que responde: ¿qué debe cumplirse para dar por terminado el ISS-02?
Evaluación
Preguntas de comprensión
-
¿Por qué el ISS instala cuatro drivers (
mysql2,pg,tedious,oracledb) si solo se usa uno a la vez? PorqueDB_ENGINEselecciona el motor en tiempo de ejecución. Tener los cuatro drivers instalados permite cambiar de motor editando una sola variable, sin tocar código ni reinstalar dependencias. Es una decisión de portabilidad del laboratorio. -
¿Qué hace exactamente
testConnection()y por qué devuelve un booleano en lugar de lanzar un error? Llama asequelize.authenticate()dentro de untry/catch: registra el error y devuelvefalsesi falla,truesi conecta. Devolver un booleano deja que quien lo llama (eldbConnection()delApp) decida cómo reaccionar —por ejemplo, abortar el arranque— sin obligarlo a envolver todo en otrotry/catch. -
¿Qué diferencia hay entre
sequelize,getDatabaseInfoytestConnection?sequelizees la instancia con la que se ejecutan consultas y se definen modelos.getDatabaseInfodevuelve metadatos (motor, configuración y cadena de conexión).testConnectionprueba si la conexión funciona. Los tres viven endb.tsy se exportan para distintos usos. -
¿Por qué la carpeta
seeders/se crea vacía y no con la lógica directamente? Porque el ISS-02 solo reserva la ubicación; la lógica de seeders (con@faker-js/faker,SeedersRunnerycounts) es un tema propio que llega en ISS-04. Separar infraestructura de datos de la generación de datos evita mezclar dos responsabilidades. -
¿Qué papel juega el
poolde conexiones en la configuración deSequelize? Define cuántas conexiones mantiene abiertas el ORM:max: 5(máximo simultáneas),min: 0(ninguna en reposo),acquire: 30000(ms de espera para obtener una) eidle: 10000(ms antes de liberar una inactiva). Sin pool, cada consulta abriría y cerraría su propia conexión, con mucho más coste. -
¿Qué pasa si
DB_ENGINEvalesqlitey por qué? El código hacedbConfigurations[selectedEngine]; al no existir esa clave,selectedConfigesundefinedy se lanzaError("Motor de base de datos no soportado: sqlite"). El ISS solo definemysqlypostgres, así que cualquier otro valor falla rápido y con un mensaje claro. -
¿Por qué
.envno debería subirse al repositorio? Porque contiene credenciales (MYSQL_PASSWORD, etc.). Versionarlas expone la base de datos a cualquiera con acceso al repositorio. La práctica habitual es subir un.env.examplesin valores reales y excluir.enven.gitignore.
Ejercicios
Ejercicio 1 — Inspeccionar la configuración. Ejecuta los comandos de verificación del ISS y explica, en dos líneas, si la infraestructura está completa.
Respuesta razonada
El primer comando no debe imprimir nada (cero errores). El segundo devuelve éxito solo si existen `db.ts`, `.env` y la carpeta `seeders/`. Si ambos pasan, los criterios 3.1–3.3 y la comprobación de tipos están cubiertos.Ejercicio 2 — Cambiar de motor sin tocar código. Supón que quieres usar PostgreSQL en lugar de MySQL. ¿Qué cambiarías y qué NO necesitarías tocar?
Respuesta razonada
Solo cambias `DB_ENGINE=postgres` en el `.env` (y rellenas las variables `POSTGRES_*` con las credenciales correctas). **No** tocas `db.ts`: el módulo ya resuelve el motor leyendo `DB_ENGINE` y usa la entrada `postgres` del mapa `dbConfigurations`. Tampoco reinstalar: `pg` y `pg-hstore` ya están instalados gracias a la decisión multi-driver del ISS.Ejercicio 3 — Razonar sobre sync.
El dbConnection() del App llama a sequelize.sync({ force, alter: !force }). Explica, sin mirar código, qué hace cada combinación y por qué el force se controla con DB_SYNC_FORCE.
Respuesta razonada
Con `DB_SYNC_FORCE=true`, `force` es `true` y `alter` es `false`: Sequelize **recrea** las tablas desde cero (borra y vuelve a crear). En cualquier otro caso, `force` es `false` y `alter` es `true`: Sequelize **ajusta** las tablas existentes al modelo sin destruir datos. Controlarlo con una variable de entorno evita que un arranque normal borre datos por accidente: solo cuando se pone explícitamente `true` se acepta la recreación. En el laboratorio, con base de datos limpia, la recreación sirve para partir siempre de un esquema consistente.Conexión con el resto del curso
- Viene de: ISS-01 — Esqueleto del proyecto, que dejó creada la carpeta
database/y elAppcon su métododbConnection()esperando esta pieza. - Habilita: ISS-03 — Feature Client (CRUD por capas), que ya puede importar
sequelizepara definir el primer modeloClient, y cuyo repositorio conectará a la base de datos real. - Piezas reutilizadas por el resto del curso: el export
sequelize(todos los modelos lo usan),testConnection(verificación de arranque),getDatabaseInfo(logs de conexión) y el.envcomo única fuente de configuración de datos. ElsyncdedbConnectioncreará las tablas de cada feature conforme se añadan modelos.
Glosario
| Término | Significado en este ISS |
|---|---|
| Sequelize | ORM de Node para SQL; mapea modelos a tablas y gestiona la conexión. |
| Driver | Paquete que permite a Sequelize hablar con un motor concreto (mysql2, pg, tedious, oracledb). |
DB_ENGINE |
Variable del .env que selecciona el motor activo. |
dialect |
Nombre del motor en la configuración de Sequelize (mysql, postgres, …). |
sequelize |
Instancia configurada que se exporta desde db.ts. |
getDatabaseInfo |
Función que devuelve motor, configuración y cadena de conexión. |
testConnection |
Función que prueba la conexión con authenticate() y devuelve booleano. |
authenticate() |
Método de Sequelize que comprueba que la conexión funciona. |
sync |
Sincroniza el esquema de la base de datos con los modelos (force recrea, alter ajusta). |
| Pool | Conjunto de conexiones reutilizables que mantiene el ORM. |
connectionString |
Representación textual de a dónde conecta (sin exponer toda la contraseña). |
| Seeder | Archivo que inserta datos de prueba; la carpeta se reserva aquí y se usa en ISS-04. |
GATE
Para cerrar el ISS-02, verifica los tipos y la existencia de los tres artefactos:
Resultado esperado: npx tsc --noEmit sin errores y los tres test en verde (código de salida 0).
Después arranca el servidor:
Resultado esperado: el servidor levanta y dbConnection() informa el motor, prueba la conexión y sincroniza. Deténlo con Ctrl+C antes de continuar: el ISS-03 reutiliza el mismo puerto y la misma base de datos.
Checklist de cierre:
- [ ]
sequelize,mysql2,pg,pg-hstore,tediousyoracledbinstalados - [ ]
.envconPORT,DB_ENGINEy los bloques de los cuatro motores - [ ]
src/database/db.tsexportasequelize,getDatabaseInfoytestConnection - [ ]
src/database/seeders/existe sin lógica - [ ]
npx tsc --noEmitOK - [ ]
npm run devarranca e intenta conectar
Con todo en verde, el ISS-02 está cumplido y puedes pasar al
ISS-03 — Feature Client (CRUD por capas), donde nace el primer modelo, su tabla y el recorrido completo Routes → Controller → Service → Repository → Model.
Navegación de la ruta: ← ISS-01 · 🛠 Construir · ↑ Ruta Express · → ISS-02 · 🛠 Construir