Saltar a contenido

📚 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

⛶ Ver presentación completa ⬇ Archivo editable (.pptx)

12 diapositivas · se visualiza dentro del sitio (archivo editable .pptx como opción secundaria).

Presentación 2 — Database Infrastructure Blueprint

⛶ Ver presentación completa ⬇ Archivo editable (.pptx)

13 diapositivas · se visualiza dentro del sitio (archivo editable .pptx como opción secundaria).


🎬 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 .env multi-motor, el módulo src/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 + carpeta seeders/. Bloqueado por: ISS-01. Criterio de cierre: npx tsc --noEmit OK.

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:

EXPLICACIÓN
    ↓
CÓDIGO
    ↓
VISUAL

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

  1. Tema
  2. Fuente técnica autoritativa
  3. Regla del ISS
  4. Cómo leer este cuaderno
  5. Ruta de aprendizaje
  6. Ficha del ISS
  7. Mapa mental del ISS
  8. Mapa del backend
  9. Árbol de archivos
  10. Anatomía del código
  11. Comandos explicados
  12. Flujos
  13. Diagnóstico
  14. Recorrido del ISS, paso a paso
  15. Criterios de aceptación
  16. Evaluación
  17. Conexión con el resto del curso
  18. Glosario
  19. 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 .env con PORT, la variable selectora DB_ENGINE y un bloque de configuración por motor.
  • El módulo src/database/db.ts, que construye un mapa dbConfigurations, resuelve el motor según DB_ENGINE y exporta sequelize, getDatabaseInfo y testConnection.
  • 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 .env y db.ts no significa tener datos. Aquí solo se prepara el canal; el modelo y su tabla nacerán en ISS-03, y el sync que 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 que App.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, porque db.ts lee 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.
  • .env no se versiona: contiene credenciales. En un proyecto real se sube un .env.example sin valores y se ignora el .env en git.

Se conecta con

  • Entrada: lo lee dotenv.config() en db.ts (y en config/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 (mysql y postgres en el ISS) cuyos valores tipan la forma de la conexión. Cada entrada lee sus variables con process.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. Si DB_ENGINE no existe, cae en MySQL.
  • Validación del motor — si DB_ENGINE apunta a un motor que no está en el mapa, lanza Error("Motor de base de datos no soportado: ..."). Fallar rápido es mejor que conectar a un motor equivocado.
  • new Sequelize(...) — construye la instancia con dialect, logging (activo solo en development) 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 a sequelize.authenticate(); devuelve true si conecta y false si 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 sequelize y dotenv; 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: oracledb suele 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, FK RESTRICT, í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 .env con DB_ENGINE y bloques de motores
  • [ ] 3.2 Existe src/database/db.ts exportando sequelize, getDatabaseInfo, testConnection
  • [ ] 3.3 Existe carpeta src/database/seeders/ sin lógica implementada aún
  • [ ] npx tsc --noEmit OK

3.1 Drivers Sequelize y .env

Criterios de este sub-ítem

  • [ ] sequelize, mysql2, pg, pg-hstore, tedious, oracledb instalados
  • [ ] .env con PORT, 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
test -f .env && grep DB_ENGINE .env
npm ls sequelize mysql2 --depth=0

3.2 Configuración Sequelize (database/db.ts)

Criterios de este sub-ítem

  • [ ] Archivo src/database/db.ts creado
  • [ ] 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
test -f src/database/db.ts && npx tsc --noEmit

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.ts ni runner
mkdir -p src/database/seeders
# opcional: touch src/database/seeders/.gitkeep
test -d src/database/seeders && echo OK

Verificación del ISS-02

npx tsc --noEmit
test -f src/database/db.ts && test -f .env && test -d src/database/seeders

Cierre del ISS

npm run dev

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 .env con DB_ENGINE y bloques de motores
  • [ ] 3.2 Existe src/database/db.ts exportando sequelize, getDatabaseInfo, testConnection
  • [ ] 3.3 Existe carpeta src/database/seeders/ sin lógica implementada aún
  • [ ] npx tsc --noEmit OK

Pregunta que responde: ¿qué debe cumplirse para dar por terminado el ISS-02?

Evaluación

Preguntas de comprensión

  1. ¿Por qué el ISS instala cuatro drivers (mysql2, pg, tedious, oracledb) si solo se usa uno a la vez? Porque DB_ENGINE selecciona 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.

  2. ¿Qué hace exactamente testConnection() y por qué devuelve un booleano en lugar de lanzar un error? Llama a sequelize.authenticate() dentro de un try/catch: registra el error y devuelve false si falla, true si conecta. Devolver un booleano deja que quien lo llama (el dbConnection() del App) decida cómo reaccionar —por ejemplo, abortar el arranque— sin obligarlo a envolver todo en otro try/catch.

  3. ¿Qué diferencia hay entre sequelize, getDatabaseInfo y testConnection? sequelize es la instancia con la que se ejecutan consultas y se definen modelos. getDatabaseInfo devuelve metadatos (motor, configuración y cadena de conexión). testConnection prueba si la conexión funciona. Los tres viven en db.ts y se exportan para distintos usos.

  4. ¿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, SeedersRunner y counts) es un tema propio que llega en ISS-04. Separar infraestructura de datos de la generación de datos evita mezclar dos responsabilidades.

  5. ¿Qué papel juega el pool de conexiones en la configuración de Sequelize? 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) e idle: 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.

  6. ¿Qué pasa si DB_ENGINE vale sqlite y por qué? El código hace dbConfigurations[selectedEngine]; al no existir esa clave, selectedConfig es undefined y se lanza Error("Motor de base de datos no soportado: sqlite"). El ISS solo define mysql y postgres, así que cualquier otro valor falla rápido y con un mensaje claro.

  7. ¿Por qué .env no 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.example sin valores reales y excluir .env en .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
npx tsc --noEmit
test -f src/database/db.ts && test -f .env && test -d src/database/seeders
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 el App con su método dbConnection() esperando esta pieza.
  • Habilita: ISS-03 — Feature Client (CRUD por capas), que ya puede importar sequelize para definir el primer modelo Client, 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 .env como única fuente de configuración de datos. El sync de dbConnection creará 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:

npx tsc --noEmit
test -f src/database/db.ts && test -f .env && test -d src/database/seeders

Resultado esperado: npx tsc --noEmit sin errores y los tres test en verde (código de salida 0).

Después arranca el servidor:

npm run dev

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, tedious y oracledb instalados
  • [ ] .env con PORT, DB_ENGINE y los bloques de los cuatro motores
  • [ ] src/database/db.ts exporta sequelize, getDatabaseInfo y testConnection
  • [ ] src/database/seeders/ existe sin lógica
  • [ ] npx tsc --noEmit OK
  • [ ] npm run dev arranca 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