Esta es la última lección del curso, y no es un resumen perezoso. Un resumen te recordaría los nombres de las cosas; lo que necesitas ahora es otra cosa: criterio. Saber usar Express, Mongoose o BullMQ es una habilidad que se adquiere en semanas. Saber cuándo usar cada uno, qué se rompe cuando el sistema crece, qué comprobar antes de dejar algo en manos de usuarios reales y cómo justificar una decisión ante un equipo, eso es lo que separa a alguien que "sabe Node" de alguien en quien se confía un servicio en producción.

Esta lección tiene cinco partes: el mapa del viaje, la lista de comprobación de puesta en producción, el marco para tomar decisiones técnicas, lo que este curso no ha cubierto, y cómo seguir aprendiendo. Al final, una última mirada a Escena Viva y una propuesta concreta para quien quiera continuar por su cuenta.

Contenido

  1. El mapa del viaje: qué construiste y qué demostró
  2. La lista de comprobación de puesta en producción
  3. Cómo se toma una decisión técnica
  4. Deuda técnica: cuándo asumirla y cuándo pagarla
  5. Lo que este curso no ha cubierto y hacia dónde seguir
  6. Cómo seguir aprendiendo
  7. Una última mirada a Escena Viva
  8. Una propuesta de continuación

  1. El mapa del viaje: qué construiste y qué demostró

Cada módulo enseñó algo y ese algo tuvo que demostrarse en una pieza real de Escena Viva. Esta tabla es el curso entero en una pantalla:

Módulo Lo que aprendiste La pieza de Escena Viva que lo demostró
M1 Node, nvm, JavaScript moderno, ESM y CommonJS El catálogo de eventos en un array y el primer script que listaba evt-001, evt-002 y evt-003
M2 Arquitectura, bucle de eventos, promesas, async/await, EventEmitter El emisor de eventos de venta y por qué un cálculo síncrono largo congelaba todas las peticiones
M3 fs.promises, path, streams, pipeline, Buffers El almacén de sesiones en JSON, resolverDentroDe contra el recorrido de directorios y la exportación de ventas por streams
M4 node:http a mano, cabeceras, estados, ETag/304, fetch El primer servidor de la API de aforo, sin framework, con caché por ETag
M5 npm, npm ci, scripts, publicación, npm audit El paquete de utilidades de códigos EV-<año>-<6 dígitos>
M6 Express 5, crearAplicacion(), routers, middleware, zod, errores centralizados La API de eventos y sesiones con validación y { error: { codigo, mensaje, estado, detalles } }
M7 MongoDB/Mongoose, PostgreSQL/Sequelize, repositorios, índices, transacciones El aforo de 3000 plazas con 1811 vendidas y la transacción que impide la sobreventa
M8 bcrypt, JWT + refresco rotatorio, autenticar/exigirRol, política pura, OWASP El registro de Lucía y Marc, los roles asistente/organizador/administrador y las entradas que solo ve su dueño
M9 Mocha, Chai, Sinon, supertest, fábricas, cobertura, depuración La batería que impide vender la butaca 3001 y que ningún cambio reintroduzca el fallo
M10 cluster, worker threads, Redis, BullMQ, rendimiento, REST avanzado, GraphQL El envío de entradas en cola, la caché del catálogo, la idempotencia del pago y el p99 bajo carga
M11 Config con zod, pino, prom-client, sondas, PM2, Docker, PaaS, CI/CD El despliegue completo con docker compose, /salud/listo y la tubería que publica sola
M12 Cuatro productos satélite completos Soporte en directo, tienda de merchandising, magazine y herramienta interna

Lee la última columna de arriba abajo. No es una lista de ejercicios: es la historia de una empresa que empieza con un array en un fichero y termina con una plataforma operada de verdad. Esa continuidad es la lección más difícil de transmitir y la más valiosa que te llevas.

  1. La lista de comprobación de puesta en producción

Esto es lo que hay que revisar antes de que un usuario real toque el sistema. No es aspiracional: cada punto se puede comprobar hoy en tu proyecto.

Corrección

  • [ ] Las pruebas pasan en CI, no solo en tu máquina (M9, M11).
  • [ ] La cobertura es razonable donde importa: dominio, cálculo de importes, transiciones de estado, autorización. Un 90 % global con el cálculo de dinero sin probar es un número que miente.
  • [ ] Existe al menos una prueba de integración por flujo crítico: comprar una entrada, pagar un pedido, publicar un artículo.
  • [ ] Los casos límite están probados: carrito vacío, cero resultados, última unidad, fecha en el pasado.
  • [ ] El linter y el formateador se ejecutan en CI y bloquean el merge.

Seguridad

  • [ ] npm audit sin vulnerabilidades altas o críticas sin justificar (M5), y actualizaciones automatizadas.
  • [ ] Ningún secreto en el repositorio. Todos por variables de entorno, validadas con zod al arrancar (M11). Si alguna vez se filtró uno, se rota: borrarlo del código no lo borra del historial de git.
  • [ ] HTTPS obligatorio, con HSTS; cookies httpOnly, Secure y SameSite (M8).
  • [ ] helmet, cors con lista de orígenes explícita, límites de tamaño de cuerpo (M6).
  • [ ] Límite de frecuencia en autenticación, registro, recuperación de contraseña y endpoints caros (M6, M8).
  • [ ] Autorización probada, no supuesta: por cada endpoint que devuelve datos ajenos posibles, una prueba que confirme el 403 o el 404 (M8, 12-04).
  • [ ] Toda entrada validada con zod, incluidos los eventos de socket (12-01) y los parámetros de consulta.
  • [ ] Ficheros subidos validados por número mágico, renombrados por el servidor y servidos desde otro origen (M3, 12-03).
  • [ ] Salida escapada al mostrar; HTML de usuario saneado con lista blanca (12-03).

Fiabilidad

  • [ ] Apagado ordenado: SIGTERM deja de aceptar conexiones, termina las peticiones en curso, cierra sockets, colas y pool de base de datos, y sale (M11, 12-01).
  • [ ] Sondas /salud/vivo y /salud/listo diferenciadas: viva no es lo mismo que lista para recibir tráfico (M11).
  • [ ] Tiempo límite en toda llamada externa. AbortSignal.timeout en fetch (M4); tiempos de conexión y consulta en la base de datos. Una llamada sin tiempo límite es una fuga de recursos esperando a ocurrir.
  • [ ] Reintentos con retroceso exponencial y solo en operaciones idempotentes (M10).
  • [ ] Idempotencia donde el reintento es inevitable: pagos, webhooks, trabajos de cola (M10, 12-02).
  • [ ] Trabajos de cola con attempts, backoff y cola de fallidos revisada por alguien.
  • [ ] Migraciones aplicadas en un paso de release separado, nunca al arrancar cada réplica (M11).

Observabilidad

  • [ ] Registros estructurados con pino, con idPeticion en cada línea y un registrador hijo por petición (M11).
  • [ ] Nunca se registran contraseñas, tokens, tarjetas ni datos personales innecesarios.
  • [ ] Métricas con prom-client: latencia por ruta, tasa de error, profundidad de las colas, aciertos de caché (M11).
  • [ ] Panel con las cuatro señales de oro: latencia, tráfico, errores y saturación.
  • [ ] Alertas por síntoma, no por causa. Alerta por "el p99 de compra supera 2 s" o "hay pedidos en pendiente_pago de más de una hora", no por "la CPU está al 80 %". La CPU alta puede ser inofensiva; un cliente que no puede pagar, nunca lo es.
  • [ ] Cada alerta tiene un procedimiento asociado. Una alerta sin acción es ruido que enseña al equipo a ignorar alertas.

Operación

  • [ ] Migraciones reversibles o, al menos, compatibles hacia atrás durante un despliegue (añadir columna, desplegar, migrar datos, borrar columna en un despliegue posterior).
  • [ ] Copias de seguridad probadas. Una copia que nunca se ha restaurado no es una copia: es una esperanza. Restaura en un entorno aparte con calendario fijo.
  • [ ] Plan de reversión documentado y ensayado: cómo se vuelve a la versión anterior y qué pasa con los datos escritos por la nueva.
  • [ ] API documentada con OpenAPI y versionada (M10); los cambios incompatibles pasan por versión nueva.
  • [ ] README con: cómo levantar el entorno, qué variables hacen falta y a quién avisar si algo se rompe.

Si tu proyecto no supera esta lista, no significa que esté mal: significa que sabes exactamente qué te falta. Eso ya es una ventaja enorme.

  1. Cómo se toma una decisión técnica

Las decisiones que has visto en el curso no salieron de una preferencia personal. Siguieron —explícita o implícitamente— este marco:

flowchart TD
  R["1. Requisito<br/>que problema real resuelvo"]
  C["2. Restricciones<br/>equipo, plazo, presupuesto, volumen"]
  O["3. Opciones<br/>al menos dos reales"]
  T["4. Compromiso<br/>que gano y que pierdo con cada una"]
  D["5. Decision<br/>reversible o no reversible"]
  R --> C --> O --> T --> D
  D -->|"reversible"| P["decide rapido y prueba"]
  D -->|"no reversible"| L["decide despacio y documenta"]

El paso 5 es el que más gente se salta y el que más tiempo ahorra. Pregunta siempre: ¿cuánto cuesta deshacer esto?

  • Elegir una librería de validación: reversible en una tarde. Decide rápido.
  • Elegir el modelo de datos de los pedidos: casi irreversible una vez hay datos reales. Decide despacio.

Tres ejemplos del propio curso, con el marco aplicado:

Decisión Requisito y restricciones Opciones Compromiso Resultado
JSON en fichero frente a base de datos (M3 → M7) Al principio: un catálogo pequeño, sin concurrencia. Después: aforo compartido y ventas simultáneas Fichero JSON / MongoDB / PostgreSQL El fichero es simple pero no tiene transacciones ni consultas ni concurrencia Fichero mientras el requisito fue "guardar datos"; base de datos en cuanto apareció "no vender la misma butaca dos veces". La decisión no fue mala: caducó
Sesiones frente a JWT (M8) API consumida por front-end y móvil, varias réplicas sin estado compartido Sesión en servidor / JWT sin estado / JWT corto + refresco en cookie La sesión revoca al instante pero necesita almacén compartido; el JWT escala pero no se revoca hasta que caduca JWT de 15 min más refresco rotatorio: el compromiso explícito entre escalado y revocación. Ni dogma ni moda: una ventana de exposición acotada
REST frente a GraphQL (M10) Clientes distintos con necesidades de datos distintas; caché HTTP valiosa para el catálogo Solo REST / Solo GraphQL / Ambos GraphQL evita el exceso y el defecto de datos, pero complica la caché HTTP, el límite de frecuencia y el análisis de consultas REST para el núcleo y GraphQL para las vistas compuestas. Con DataLoader, porque sin él el problema N+1 llega solo
Caché en proceso frente a Redis (M10) Catálogo leído miles de veces, varias réplicas Map en memoria / Redis / ambos El Map es instantáneo y gratis, pero cada réplica tiene su copia y la invalidación no cruza procesos Redis, por la misma razón que el adaptador de sockets del 12-01: el estado local deja de ser válido en cuanto hay más de un proceso

Registrar las decisiones: los ADR. Un ADR (Architecture Decision Record) es un fichero corto en el repositorio, uno por decisión relevante:

# ADR 007: JWT de acceso corto con refresco rotatorio

Fecha: 2026-03-14
Estado: aceptada

## Contexto
La API sirve a un front-end web y a una aplicación móvil, y se despliega
con varias réplicas sin estado compartido. Necesitamos autenticación que
escale y que permita revocar el acceso de una cuenta comprometida.

## Decisión
Token de acceso JWT de 15 minutos + token de refresco rotatorio en cookie
httpOnly, con familias revocables.

## Consecuencias
- Positivas: sin almacén de sesiones en la ruta caliente; escala horizontalmente.
- Negativas: un acceso robado sigue siendo válido hasta 15 minutos.
- Mitigación: revocación de familia al detectar reutilización de refresco.

## Alternativas descartadas
- Sesión en Redis: revocación inmediata, pero una consulta por petición
  y un punto de fallo más en la ruta crítica.
- JWT de larga duración: descartado, no hay forma sensata de revocar.

Lo valioso de un ADR no es el formato: es que dentro de dos años alguien —probablemente tú— leerá "¿por qué demonios está esto así?" y encontrará la respuesta. Sin ADR, las decisiones se reabren cada seis meses con menos información que la primera vez.

  1. Deuda técnica: cuándo asumirla y cuándo pagarla

Deuda técnica no significa código malo. Significa una decisión que acelera hoy a cambio de un coste futuro, igual que un préstamo. Como un préstamo, puede ser una excelente idea o una ruina, y la diferencia está en si es consciente y si se paga.

Deuda razonable Deuda peligrosa
Guardar en JSON mientras validas si el producto interesa No tener pruebas en el cálculo de importes
Un TODO con fecha y responsable para paginar un listado que hoy tiene 40 filas Autorización a medias "que ya arreglaremos"
Aplazar GraphQL hasta tener un segundo cliente Secretos en el código "solo en desarrollo"
Copiar y pegar una función dos veces antes de decidir la abstracción Migraciones irreversibles sin copia de seguridad
Cachear con TTL antes de construir la invalidación fina Dependencias sin actualizar durante años

La regla práctica: la deuda en seguridad, en datos y en dinero no se asume. Todo lo demás es negociable si se anota. Y se anota en un sitio con fecha y dueño, porque un TODO sin dueño es una decoración.

La señal de que la deuda te está ahogando es siempre la misma: cada cambio pequeño tarda cada vez más y rompe cosas cada vez más lejanas. Cuando notas eso, la prioridad ya no es la siguiente funcionalidad.

  1. Lo que este curso no ha cubierto y hacia dónde seguir

Honestidad ante todo: este curso te ha dado una base sólida y completa para construir servicios reales con Node. No te ha dado —ni podía— todo. Esto es lo que queda fuera, por qué importa y cuándo tocarlo:

Tema Qué es Por qué importa Cuándo abordarlo
TypeScript JavaScript con tipos estáticos comprobados al compilar El paso siguiente más recomendable. En un proyecto como los de este módulo, los tipos convierten en errores de compilación media docena de fallos que hoy solo verías en producción: un precioCentimos que llega como cadena, una transición de estado inexistente, un campo renombrado a medias. Además es el estándar de facto del ecosistema profesional Ya. Empieza con // @ts-check y JSDoc sobre tu código actual, y migra fichero a fichero
ESM Los módulos import/export como destino del ecosistema Este curso usó CommonJS por pragmatismo (la mayoría del código existente lo usa), pero las librerías nuevas publican solo ESM y Node ya lo soporta sin fricción Al empezar un proyecto nuevo, nace en ESM
Microservicios Dividir el sistema en servicios desplegables por separado Resuelve problemas organizativos (equipos independientes) a cambio de costes técnicos enormes: red poco fiable, transacciones distribuidas, trazabilidad, despliegue coordinado Solo cuando el monolito modular duela por razones de equipo, no de moda. Un monolito bien estructurado sirve a la mayoría de productos durante años
Serverless Funciones que se ejecutan bajo demanda sin servidor propio Excelente para cargas esporádicas y picos; malo para conexiones persistentes (adiós Socket.IO), arranques en frío y pools de base de datos Para trabajos por eventos, webhooks y tareas puntuales
Arquitectura hexagonal y DDD Separar el dominio de la infraestructura; modelar el lenguaje del negocio Ya lo has probado sin nombrarlo: repositorios, política pura, funciones de dominio sin Express. El siguiente paso es hacerlo sistemático Cuando el dominio sea complejo de verdad y varias personas lo mantengan
WebAssembly Ejecutar código compilado (Rust, C) dentro de Node Para cálculo intensivo donde JavaScript no llega: imagen, criptografía, compresión Cuando midas y el cuello de botella sea CPU en tu propio código
Deno y Bun Ejecutores alternativos: seguridad por permisos, TypeScript nativo, arranque rápido Empujan al ecosistema y conviene conocerlos; Node sigue siendo la apuesta segura en producción Curiosidad activa, no migración urgente
Escalado de bases de datos Réplicas de lectura, particionado, agrupación de conexiones, planes de consulta El primer límite real de casi todos los sistemas no es Node: es la base de datos En cuanto tengas volumen. Empieza por EXPLAIN y por el pool
Colas y mensajería distribuida Kafka, RabbitMQ, NATS, patrones de entrega y orden BullMQ te llevó lejos; los sistemas de eventos entre servicios juegan en otra liga Cuando haya varios servicios que deban reaccionar a los mismos hechos
Kubernetes Orquestación de contenedores a escala Docker te dio el contenedor; K8s lo opera, lo escala y lo recupera. Potente y caro en complejidad Cuando el PaaS se quede corto o lo exija la empresa
Accesibilidad y front-end Interfaces usables por todo el mundo Ninguno de estos cuatro proyectos existe sin interfaz, y una API impecable con una interfaz inutilizable no sirve a nadie En paralelo, siempre

Si tuvieras que elegir uno solo: TypeScript. El retorno por hora invertida es el más alto de la lista, y hace mejores todos los demás pasos.

  1. Cómo seguir aprendiendo

Cuatro hábitos que distinguen a quien sigue creciendo de quien se estanca:

Lee la documentación oficial, no la tercera respuesta de un buscador. La documentación de Node es excelente y contiene detalles que ningún tutorial menciona: el comportamiento exacto de pipeline ante errores, las garantías de cluster, las opciones de crypto.timingSafeEqual. Media hora en la documentación oficial rinde más que tres horas de fragmentos sueltos.

Lee el código fuente de lo que usas. Ya lo tienes en node_modules. Cuando algo se comporte de forma rara —Express 5 y sus errores asíncronos, cómo BullMQ implementa jobId, cómo Socket.IO decide el transporte— ábrelo y míralo. Descubrirás que las librerías que te intimidan son código normal escrito por gente normal. Es el salto de "usuario de la herramienta" a "ingeniero".

Sigue las notas de versión de Node. Las versiones LTS (Long Term Support, soporte a largo plazo) son las pares (20, 22, 24…) y reciben mantenimiento unos 30 meses: son las que se usan en producción. Las impares son de vida corta y sirven para probar novedades. Cada versión trae cosas que sustituyen dependencias: el fetch global, el ejecutor de pruebas integrado, el cargador de .env, node --watch. Menos dependencias es menos superficie de ataque y menos mantenimiento.

Contribuye y construye. Empieza por lo pequeño en proyectos libres: una errata en la documentación, una prueba que falta, un caso límite. Aprenderás tanto del proceso de revisión como del código. Y, sobre todo, construye algo tuyo de principio a fin, con usuarios reales aunque sean cinco. Ninguna lección enseña lo que enseña un despliegue que se rompió un domingo y tuviste que arreglar.

  1. Una última mirada a Escena Viva

Merece la pena mirar atrás el sistema completo.

Empezó siendo un array de tres eventos en un fichero JavaScript y un console.log. Hoy, sobre el papel de este curso, Escena Viva es:

  • Una API REST versionada y documentada con OpenAPI, con validación en la frontera, errores homogéneos { error: { codigo, mensaje, estado, detalles } } y paginación por cursor; más una capa GraphQL con DataLoader para las vistas compuestas.
  • Un catálogo de 3 eventos y 7 sesiones sobre tres salas, con un aforo de 3000 plazas y 1811 entradas vendidas que nunca se sobrevenden, gracias a transacciones con bloqueo.
  • Autenticación con contraseñas cifradas con bcrypt, JWT de acceso corto, refresco rotatorio en cookie httpOnly con revocación por familias, y una política de autorización pura sobre tres roles.
  • Tiempo real: soporte en directo con Socket.IO, salas por conversación, confirmaciones, presencia y adaptador de Redis para funcionar con varias réplicas.
  • Comercio: tienda de merchandising con variantes y stock, precios congelados en el pedido, importes calculados en el servidor en céntimos, pasarela de pago con webhooks firmados e idempotentes y una máquina de estados que rechaza lo imposible.
  • Contenido: magazine con flujo editorial, publicación programada, Markdown saneado con lista blanca, imágenes validadas por número mágico y procesadas en cola a varios tamaños.
  • Colaboración interna: espacios por sala y evento, permisos por pertenencia empujados a la consulta, bloqueo optimista con 412, actividad inmutable y notificaciones agrupadas.
  • Infraestructura: colas BullMQ con consumidor aparte, caché en Redis con invalidación, pool de worker threads, registros estructurados con pino e idPeticion, métricas con prom-client, sondas de salud, Docker multietapa, docker compose con api, consumidor, postgres, mongo y redis, y una tubería de CI/CD que prueba, audita, construye y despliega sola.
  • Y una batería de pruebas que impide que nada de lo anterior se rompa en silencio.

Ninguna de esas piezas es exótica. Todas son las que sostienen productos reales que usas a diario. La diferencia entre este sistema y uno de verdad no es de naturaleza: es de escala, de dinero y de años de retoques. Pero las ideas son las mismas, y ahora las tienes.

  1. Una propuesta de continuación

Si quieres seguir solo, aquí van cuatro ampliaciones bien delimitadas. Cada una cabe en un fin de semana o dos y toca cosas nuevas de verdad:

  1. Migrar un proyecto a TypeScript. Elige el más pequeño (la herramienta de tareas o la tienda). Empieza por tsconfig.json con strict: true, activa allowJs, y convierte primero el dominio (funciones puras), luego los repositorios, luego los controladores. Escribe tipos para el objeto de configuración y para el formato de error. Anota cuántos fallos reales te encuentra el compilador: te sorprenderá.

  2. Sustituir el envío de correo simulado por uno real y observable. Integra un proveedor de correo, añade reintentos, gestiona rebotes por webhook, y monta un panel con dos métricas: correos enviados y correos fallidos por tipo. Es pequeño y toca colas, webhooks, idempotencia y observabilidad a la vez.

  3. Añadir un panel de administración con estadísticas en vivo. Métricas de ocupación por sala y evento con agregaciones (M7), servidas por SSE —no WebSocket: el flujo es de un solo sentido, y aplicar aquí la elección del 12-01 al revés es un ejercicio de criterio excelente— y cacheadas en Redis con invalidación por venta.

  4. Cerrar la lista de comprobación del punto 2 sobre tu propio proyecto. Sin código nuevo, o casi. Audítalo punto por punto, escribe lo que falta, y arregla los tres más graves. Es la ampliación menos vistosa y la que más te va a enseñar.

Errores Comunes y Consejos

  • Confundir "funciona" con "está listo". Que la funcionalidad responda es el principio del trabajo, no el final. La lista del punto 2 es la diferencia.
  • Elegir tecnología por popularidad. La pregunta no es qué es moderno, sino qué problema tienes y qué cuesta deshacer la elección.
  • Optimizar sin medir. Todo lo del M10 empieza con un número: p99, perfil, flamegraph. Sin medición, optimizar es superstición.
  • Añadir complejidad "por si acaso". Microservicios, colas distribuidas o caché en cinco niveles antes de tener el problema es deuda técnica pagada por adelantado y sin haber recibido el préstamo.
  • Copiar de una respuesta de internet sin entenderla —o de un asistente de IA—. Si no puedes explicar por qué funciona, no puedes arreglarlo cuando falle. Y fallará.
  • No documentar las decisiones. El coste no lo pagas hoy, lo paga tu yo de dentro de dos años.
  • Consejo final: el mejor código que escribirás es el que otra persona entiende sin preguntarte nada. Nombres claros, funciones cortas, dependencias inyectadas y errores explícitos ganan siempre a la genialidad compacta.

Ejercicios

Estos ejercicios son de síntesis: no hay una respuesta correcta única, y el valor está en el proceso.

  1. Auditoría de tu propio proyecto. Coge el proyecto del módulo 12 que más te haya interesado y recórrelo entero con la lista de comprobación del punto 2. Marca cada punto como cumplido, parcial o ausente. Después ordena lo ausente por riesgo (probabilidad × impacto) y escribe un plan de tres acciones concretas.

  2. Escribe un ADR de una decisión del curso. Elige una: MongoDB frente a PostgreSQL para el magazine, posiciones fraccionarias frente a LexoRank, WebSocket frente a SSE para el soporte, o confirmar el pago por webhook en vez de por retorno del navegador. Redáctalo con el formato del punto 3, incluyendo alternativas descartadas y consecuencias negativas asumidas.

  3. Planifica una de las cuatro ampliaciones. Elige una del punto 8 y escribe su plan: alcance, lo que queda explícitamente fuera, riesgos, orden de trabajo y cómo sabrás que está terminada.

Soluciones

1. Auditoría — cómo se ve una hecha bien

No basta con una lista de casillas. Un resultado útil de esta auditoría es una tabla de riesgo priorizado:

Punto ausente Probabilidad de que ocurra Impacto si ocurre Riesgo Acción
Sin prueba de autorización en el listado de tareas Alta (cualquier refactor lo rompe) Alto (filtración entre espacios) Crítico Añadir prueba de listado por cada endpoint, hoy
Copias de seguridad nunca restauradas Media Muy alto (pérdida total) Crítico Restauración de prueba mensual en entorno aparte
Sin tiempo límite en la llamada a la pasarela Media Medio (peticiones colgadas) Alto AbortSignal.timeout(8000) y reintento idempotente
Sin alertas por síntoma Alta Medio (te enteras por el cliente) Alto Alerta de pedidos en pendiente_pago > 1 h
Sin OpenAPI publicado Alta Bajo Medio Generar desde los esquemas zod

Las tres acciones del plan: (a) pruebas de autorización en todos los listados; (b) restauración de copia probada con calendario; (c) tiempos límite y alerta de síntoma en el flujo de pago. Fíjate en que ninguna es una funcionalidad nueva y las tres reducen riesgo real.

2. ADR — ejemplo resuelto

# ADR 012: Confirmar el pago por webhook y no por el retorno del navegador

Fecha: 2026-08-15
Estado: aceptada

## Contexto
Tras pagar, el navegador vuelve a nuestra página de éxito. La tentación es
marcar el pedido como pagado en ese momento, porque es simple y el usuario
ve el resultado al instante.

## Decisión
El pedido pasa a 'pagado' únicamente al recibir el webhook firmado
payment_intent.succeeded. La página de éxito solo consulta GET /pedidos/:id.

## Consecuencias
- Positivas: el estado es correcto aunque el usuario cierre el navegador;
  la fuente de verdad es quien realmente cobró; resistente a manipulación.
- Negativas: el usuario puede ver 'pendiente_pago' unos segundos; hay que
  implementar verificación de firma, idempotencia y sondeo en el cliente.
- Mitigación: sondeo corto o aviso por Socket.IO al confirmarse el pedido.

## Alternativas descartadas
- Confirmar en el retorno del navegador: un cierre de pestaña deja el pedido
  cobrado y sin confirmar. Y el retorno es manipulable por el cliente.
- Consultar a la pasarela cada N segundos desde el servidor: funciona, pero
  desperdicia llamadas y añade latencia frente a un webhook que ya existe.

3. Plan de ampliación — ejemplo con la migración a TypeScript

  • Alcance: src/dominio, src/servicios y src/repositorios de la herramienta de tareas, con strict: true.
  • Fuera de alcance: controladores y pruebas (segunda fase); no se cambia ninguna funcionalidad.
  • Riesgos: tipos de Sequelize costosos de escribir; tentación de usar any y perder todo el beneficio.
  • Orden: (1) tsconfig.json con allowJs y checkJs; (2) tipos del dominio (Tarea, Espacio, Pertenencia, estados como uniones literales); (3) funciones puras; (4) repositorios con tipos de retorno explícitos; (5) construcción en CI.
  • Terminado cuando: tsc --noEmit pasa sin errores, no queda ningún any explícito en el dominio, todas las pruebas siguen verdes y CI compila antes de probar.

Nota la elección de orden: se empieza por el dominio porque es donde los tipos aportan más y donde menos infraestructura hay que tipar. Empezar por los controladores es el error habitual y el que hace abandonar la migración.

Conclusión

Aquí termina el curso.

Empezaste instalando Node y ejecutando un fichero con tres eventos dentro de un array. Terminas con una plataforma completa —catálogo, aforo sin sobreventa, autenticación con refresco rotatorio, tiempo real, comercio con pagos, contenido, colaboración interna, colas, caché, pruebas, contenedores y despliegue automático— y, más importante, con los criterios para decidir qué construir, qué no construir y qué comprobar antes de que alguien dependa de ello.

Si hay una idea que conviene que se quede por encima de todas las demás, es esta: las herramientas cambian y los criterios permanecen. Express dará paso a otro framework, Mongoose y Sequelize a otros ORM, y alguna de las librerías de este curso habrá quedado obsoleta antes de lo que parece. Lo que no caduca es saber por qué el precio se congela en el pedido, por qué el estado local deja de valer en cuanto hay dos procesos, por qué la autorización se empuja a la consulta, por qué un reintento exige idempotencia y por qué una copia de seguridad que no se ha restaurado no es una copia de seguridad. Eso lo has aprendido construyendo, que es la única forma en que se aprende de verdad.

Ya no necesitas este curso. Necesitas un problema que te importe y tiempo para equivocarte con él. Escribe código, ponlo delante de usuarios, obsérvalo fallar, arréglalo y vuelve a empezar. Ese bucle —el mismo que has recorrido doce veces con Escena Viva— es todo el oficio.

Buen viaje.

Curso de Node.js: De Principiante a Avanzado

Módulo 1: Introducción a Node.js

Módulo 2: Conceptos Básicos

Módulo 3: Sistema de Archivos y E/S

Módulo 4: HTTP y Servidores Web

Módulo 5: NPM y Gestión de Paquetes

Módulo 6: Framework Express.js

Módulo 7: Bases de Datos y ORMs

Módulo 8: Autenticación y Autorización

Módulo 9: Pruebas y Depuración

Módulo 10: Temas Avanzados

Módulo 11: Despliegue y DevOps

Módulo 12: Proyectos del Mundo Real

© Copyright 2026. Todos los derechos reservados