Objetivos de aprendizaje

Plan de estudio Full Stack

Para conseguir trabajo en Costa Rica

15Capas
2Partes
~12–16Meses (full)
0%Tu progreso

Contenido

El plan está organizado por capas, en orden. Cada capa es un bloque de estudio; andá una por una sin saltarte el orden.

PARTE 1

Base y empleabilidad

Objetivo
Tener el stack completo para aplicar a posiciones junior/mid en empresas nearshore de Costa Rica.
Tiempo estimado
9 a 11 meses (4–6 h/día) · 14 a 18 meses (2–3 h/día)
  1. Capa 1HTML + CSS3 semanas
  2. Capa 2TypeScript3 semanas
  3. Capa 3React5 semanas
  4. Capa 4Node.js2 semanas
  5. Capa 5Express.js3 semanas
  6. Capa 6NestJS4 semanas
  7. Capa 7Autenticación2 semanas
  8. Capa 8PostgreSQL + Prisma4 semanas
  9. Capa 9DevOps básico3 semanas
  10. Capa 10Buenas prácticas y testing baseEn paralelo
PARTE 2

Nivel medio-avanzado

Objetivo
Diferenciarte de otros candidatos con el mismo stack base, pasar entrevistas técnicas de mayor nivel y crecer a posiciones mid/senior.
Cuándo empezar
Después de terminar la Parte 1 y tener al menos un proyecto deployed.
Tiempo estimado
3 a 5 meses adicionales (4–6 h/día)
  1. Capa 11Redis2 semanas
  2. Capa 12Testing en React2 semanas
  3. Capa 13SQL avanzado y rendimiento2 semanas
  4. Capa 14Subida de archivos a la nube1.5 semanas
  5. Capa 15Patrones de API y system design básico2 semanas

Resumen del plan completo

ParteCapasDuración estimadaObjetivo
Parte 1 — Base1 al 109–11 meses (full)Primer empleo junior/mid
Parte 2 — Avanzado11 al 153–5 meses adicionalesDiferenciarte, crecer a mid/senior
Total15 capas~12–16 meses (full)Stack completo y competitivo

Dedicación parcial (2–3 h/día): multiplicar por 1.5x cada estimado.

Capa 01Parte 1 · Base y empleabilidad

HTML + CSS

Base visual de todo lo que vas a construir. Ya tenés conocimientos, pero hay que reforzar los puntos que más se evalúan en entrevistas. La meta de esta capa es que puedas armar cualquier interfaz, que se vea bien en cualquier pantalla y que sea accesible.

Tecnologías
  • HTML5
  • CSS3
  • Tailwind CSS
Duración estimada
3 semanas
Temas
3
Objetivos
35
Tu progreso

HTML

8 objetivos
  • Aprender las etiquetas semánticas (header, main, nav, section, article, aside, footer) para estructurar la página con sentido, de modo que el navegador, los lectores de pantalla y Google entiendan qué representa cada parte del contenido.
  • Dominar los formularios completos (input, select, textarea, checkbox, radio, label, fieldset) para capturar datos del usuario de forma ordenada y funcional, que es la base de casi cualquier app real.
  • Manejar los atributos importantes (id, class, data-*, aria-label, aria-hidden, role) para identificar elementos, guardar datos en el HTML y dar información de accesibilidad cuando el texto visible no alcanza.
  • Construir tablas correctamente (table, thead, tbody, tfoot, tr, td, th, colspan, rowspan) para presentar datos tabulares de forma clara y semánticamente correcta, sin abusar de ellas para maquetar.
  • Configurar los meta tags (charset, viewport, description, og tags básicos) para que la página se renderice bien en móvil, se entienda en buscadores y se vea decente cuando alguien la comparte en redes.
  • Aplicar accesibilidad básica (alt en imágenes, contraste, orden de tabindex) para que personas con discapacidad puedan usar tu sitio, algo que además exigen muchas empresas con clientes en EEUU.
  • Usar los elementos multimedia (img, video, audio, iframe, source) para incrustar imágenes, video, audio y contenido externo de la forma correcta según cada caso.
  • Entender la diferencia entre elementos en bloque e inline para predecir cómo se acomodan los elementos en la página y dejar de pelear con el layout sin saber por qué se mueve todo.

CSS

13 objetivos
  • Dominar el box model completo (margin, padding, border, box-sizing: border-box) para entender cómo se calcula el tamaño real de cada elemento y controlar los espaciados sin sorpresas.
  • Aprender Flexbox (display: flex, flex-direction, justify-content, align-items, align-self, flex-wrap, gap, flex-grow, flex-shrink, flex-basis) para alinear y distribuir elementos en una dimensión, que es la herramienta que más vas a usar en el día a día.
  • Aprender Grid (display: grid, grid-template-columns, grid-template-rows, grid-column, grid-row, grid-area, grid-template-areas, gap) para armar layouts en dos dimensiones (filas y columnas) y maquetar páginas completas con orden.
  • Manejar el posicionamiento (static, relative, absolute, fixed, sticky, z-index) para colocar elementos exactamente donde los necesitás, como menús fijos, modales o badges sobre una imagen.
  • Aplicar responsive design (media queries, min-width, max-width, mobile-first) para que tu sitio se vea bien en celular, tablet y escritorio, partiendo siempre desde la pantalla más pequeña.
  • Entender las unidades (px, em, rem, %, vw, vh, fr) para elegir la medida correcta en cada caso y lograr diseños que escalan bien según el contexto.
  • Usar variables CSS (--color-primario: #333, var(--color-primario)) para centralizar valores repetidos como colores y tamaños, y poder cambiar todo el tema desde un solo lugar.
  • Aplicar pseudoclases (:hover, :focus, :active, :nth-child, :first-child, :last-child, :not()) para dar estilos según el estado o la posición de un elemento sin necesidad de JavaScript.
  • Usar pseudoelementos (::before, ::after, ::placeholder) para agregar contenido decorativo o detalles visuales sin ensuciar el HTML.
  • Aprender transiciones (transition, transition-property, transition-duration, ease) para animar cambios de estado de forma suave y que la interfaz se sienta más pulida.
  • Aprender animaciones (@keyframes, animation-name, animation-duration, animation-iteration-count) para crear movimientos más complejos como loaders o efectos de entrada.
  • Entender la especificidad y el cascade de CSS para saber por qué un estilo gana sobre otro y dejar de recurrir a !important cada vez que algo no se aplica.
  • Conocer el reset CSS y la normalización para arrancar tus proyectos desde una base pareja entre navegadores, sin estilos por defecto que te estorben.

Tailwind CSS

14 objetivos
  • Instalar Tailwind con Vite o CDN para empezar a usarlo en un proyecto real y entender cómo se integra al flujo de trabajo moderno.
  • Aprender las clases de spacing (p-4, m-2, px-6, py-3, gap-4, space-y-2) para manejar márgenes, padding y separación entre elementos directamente desde el HTML, sin escribir CSS aparte.
  • Manejar las clases de tipografía (text-sm, text-lg, font-bold, font-medium, text-center, leading-relaxed) para controlar tamaño, peso, alineación e interlineado del texto rápidamente.
  • Usar las clases de color (text-gray-700, bg-blue-500, border-red-300) para aplicar la paleta de forma consistente usando la escala predefinida de Tailwind.
  • Aplicar Flexbox con Tailwind (flex, items-center, justify-between, flex-col, flex-wrap) para alinear elementos sin salir del HTML, reutilizando lo que ya sabés de Flexbox.
  • Aplicar Grid con Tailwind (grid, grid-cols-3, col-span-2) para armar layouts de columnas de forma rápida con clases utilitarias.
  • Usar los prefijos responsive (sm:, md:, lg:, xl:, 2xl:) para adaptar el diseño a distintos tamaños de pantalla directamente en la clase.
  • Manejar los estados (hover:, focus:, active:, disabled:) para cambiar estilos según la interacción del usuario sin escribir pseudoclases a mano.
  • Implementar dark mode (dark:) para ofrecer un tema oscuro, algo cada vez más esperado en interfaces modernas.
  • Controlar tamaños (w-full, h-screen, max-w-md, min-h-0) para definir ancho y alto de los elementos de forma precisa y responsive.
  • Aplicar bordes (border, border-2, rounded, rounded-lg, rounded-full) para agregar contornos y esquinas redondeadas a tus componentes.
  • Aplicar sombras (shadow, shadow-md, shadow-lg) para dar profundidad y jerarquía visual a tarjetas, botones y modales.
  • Crear componentes reutilizables con @apply en CSS para agrupar combinaciones de clases repetidas y mantener el código más limpio.
  • Configurar tailwind.config.js (colores personalizados, fuentes) para extender Tailwind con la identidad visual de cada proyecto.

Capa 02Parte 1 · Base y empleabilidad

TypeScript

Aprendelo antes de React. Cada hora invertida aquí te ahorra diez horas de bugs después, porque le pone tipos a tu código y te avisa de los errores antes de ejecutarlo.

Tecnologías
  • TypeScript
Duración estimada
3 semanas
Temas
5
Objetivos
36
Tu progreso

Fundamentos

6 objetivos
  • Aprender los tipos primitivos (string, number, boolean, null, undefined, symbol, bigint) para describir los datos más básicos y que el editor te avise cuando algo no calza.
  • Entender el tipo any y por qué evitarlo, y usar unknown como alternativa segura para manejar valores de tipo desconocido sin perder el control que da TypeScript.
  • Usar void para tipar funciones que no retornan nada, dejando claro que su utilidad es el efecto que producen y no un valor.
  • Usar never para funciones que nunca terminan o que siempre lanzan error, marcando casos que en teoría no deberían ocurrir.
  • Aprovechar la inferencia de tipos para saber cuándo TypeScript los deduce solo y escribir menos anotaciones sin perder seguridad.
  • Escribir anotaciones explícitas (let nombre: string = "Juan") para declarar el tipo a mano cuando hace falta claridad o cuando la inferencia no alcanza.

Estructuras de tipos

9 objetivos
  • Aprender a usar interfaces para definir la forma de un objeto y garantizar que siempre tenga las propiedades esperadas.
  • Usar type aliases (type Usuario = { nombre: string; edad: number }) para nombrar tipos y reutilizarlos en todo el código.
  • Entender la diferencia entre interface y type para saber cuál conviene en cada situación.
  • Aplicar union types (string | number) para permitir que un valor sea de uno u otro tipo según el caso.
  • Aplicar intersection types (TipoA & TipoB) para combinar varios tipos en uno solo que tenga todas sus propiedades.
  • Usar literal types ("activo" | "inactivo") para restringir un valor a un conjunto exacto de opciones permitidas.
  • Marcar optional properties (email?: string) para indicar que una propiedad puede o no estar presente.
  • Usar readonly (readonly id: number) para proteger propiedades que no deben cambiar una vez asignadas.
  • Aprender index signatures ([key: string]: any) para tipar objetos con claves dinámicas que no conocés de antemano.

Generics

5 objetivos
  • Crear funciones genéricas (function identidad<T>(arg: T): T) para escribir lógica reutilizable que funcione con cualquier tipo manteniendo la seguridad de tipos.
  • Definir interfaces genéricas (interface Respuesta<T> { data: T; ok: boolean }) para modelar estructuras flexibles, como respuestas de API que envuelven distintos tipos de datos.
  • Aplicar restricciones (<T extends object>) para limitar qué tipos se pueden usar en un genérico y evitar usos inválidos.
  • Conocer los tipos genéricos comunes (Array<T>, Promise<T>, Record<K, V>) porque aparecen constantemente al trabajar con listas, asincronía y mapas de datos.
  • Usar los utility types (Partial<T>, Required<T>, Pick<T, K>, Omit<T, K>, Readonly<T>, ReturnType<T>, Parameters<T>) para transformar tipos existentes sin reescribirlos y ahorrarte código repetido.

Funciones y async

7 objetivos
  • Aprender a tipar parámetros y retorno (function suma(a: number, b: number): number) para dejar claro qué recibe y qué devuelve cada función.
  • Tipar arrow functions para mantener la seguridad de tipos también en el estilo de funciones más usado en JavaScript moderno.
  • Usar parámetros opcionales y con valor por defecto para dar flexibilidad a tus funciones sin romper a quien las llama.
  • Manejar parámetros rest (...args: string[]) para recibir una cantidad variable de argumentos de forma tipada.
  • Conocer los overloads básicos para describir funciones que se comportan distinto según los argumentos que reciben.
  • Combinar async/await con tipos (Promise<string>, async function obtener(): Promise<Usuario>) para manejar operaciones asíncronas sabiendo exactamente qué tipo de dato vas a recibir.
  • Aplicar manejo de errores tipado con try/catch para capturar fallos de forma controlada en código asíncrono.

Patrones avanzados importantes

9 objetivos
  • Usar type guards (typeof, instanceof, funciones con is) para que TypeScript entienda con qué tipo estás trabajando dentro de un bloque condicional y te deje acceder a sus propiedades con seguridad.
  • Aplicar optional chaining (usuario?.direccion?.ciudad) para acceder a propiedades anidadas sin que truene la app cuando algo en la cadena no existe.
  • Usar nullish coalescing (nombre ?? "Sin nombre") para dar un valor por defecto solo cuando el original es null o undefined.
  • Conocer el non-null assertion (elemento!.value) para decirle a TypeScript que algo no es nulo, usándolo poco porque desactiva una protección.
  • Usar enums (enum Estado { Activo, Inactivo }) para nombrar conjuntos de valores relacionados y hacer el código más legible.
  • Aplicar tuplas ([string, number]) para tipar arrays de longitud y tipos fijos en cada posición.
  • Usar as const para objetos inmutables y lograr que TypeScript infiera los valores más específicos posibles.
  • Manejar módulos (import/export con tipos) para organizar el código en archivos y compartir tipos entre ellos.
  • Configurar tsconfig.json (strict, target, module, outDir) para definir qué tan estricto es el compilador y cómo se genera el código final.

Capa 03Parte 1 · Base y empleabilidad

React

El framework de UI más pedido en Costa Rica. Aprendelo con TypeScript desde el primer día para escribir componentes seguros y profesionales.

Tecnologías
  • React
Duración estimada
5 semanas
Temas
9
Objetivos
46
Tu progreso

JSX y renderizado

7 objetivos
  • Entender qué es JSX y cómo lo transforma Babel/Vite para saber que ese "HTML dentro de JavaScript" en realidad se convierte en llamadas a funciones.
  • Aprender las reglas de JSX (un solo elemento raíz, className en vez de class) para escribir componentes sin los errores típicos del principio.
  • Usar expresiones en JSX ({variable}, {condicion && <div/>}, operador ternario) para insertar datos y lógica directamente en la interfaz.
  • Renderizar listas con .map() y la prop key para mostrar colecciones de datos y ayudar a React a actualizar la lista de forma eficiente.
  • Aplicar renderizado condicional (&&, ternario, early return) para mostrar u ocultar partes de la UI según el estado.
  • Usar fragmentos (<> y </>) para agrupar varios elementos sin agregar un nodo extra innecesario al DOM.
  • Conocer dangerouslySetInnerHTML y cuándo NO usarlo para entender el riesgo de inyectar HTML directo y evitar vulnerabilidades.

Componentes

7 objetivos
  • Crear componentes funcionales con TypeScript para construir piezas reutilizables de UI con tipos seguros.
  • Tipar props con interfaces, usar props opcionales y valores por defecto para definir con claridad qué datos recibe cada componente.
  • Usar la prop children y ReactNode para crear componentes contenedores que envuelven contenido arbitrario.
  • Aplicar composición de componentes para armar interfaces complejas combinando piezas pequeñas y simples.
  • Entender componentes controlados vs no controlados para decidir si React o el DOM maneja el estado de un input.
  • Aprender a levantar el estado (lifting state up) para compartir datos entre componentes hermanos a través de un padre común.
  • Aplicar separación de responsabilidades para mantener cada componente enfocado en una sola cosa y fácil de mantener.

Hooks esenciales

8 objetivos
  • Dominar useState (estado local, actualización funcional, estado inicial lazy) para guardar y actualizar datos que cambian dentro de un componente.
  • Dominar useEffect (efectos secundarios, dependencias, cleanup function) para ejecutar código fuera del renderizado, como llamadas a API o suscripciones, y limpiarlo cuando toca.
  • Usar useRef (referencias al DOM, valores mutables sin re-render) para acceder a elementos del DOM o guardar valores que no deben disparar un nuevo renderizado.
  • Usar useContext para consumir datos compartidos sin pasarlos manualmente por props en cada nivel.
  • Aplicar useMemo para memorizar valores costosos y no recalcularlos en cada render innecesariamente.
  • Aplicar useCallback para memorizar funciones y evitar re-renders innecesarios en componentes hijos.
  • Usar useReducer para manejar estado complejo con lógica de reducer, cuando useState se queda corto.
  • Aprender las reglas de los hooks para usarlos correctamente y evitar bugs difíciles de rastrear.

Hooks personalizados

3 objetivos
  • Crear hooks personalizados (useLocalStorage, useFetch, useDebounce) para encapsular lógica reutilizable y compartirla entre componentes.
  • Saber cuándo extraer lógica a un hook para mantener los componentes limpios y enfocados en la UI.
  • Aplicar composición de hooks para construir hooks más complejos a partir de otros más simples.

Formularios

4 objetivos
  • Crear formularios controlados con useState para manejar los valores de los inputs desde el estado de React.
  • Usar React Hook Form (register, handleSubmit, formState, errors) para manejar formularios de forma más eficiente y con menos re-renders.
  • Validar con Zod + zodResolver para definir reglas de validación claras y reutilizar esos esquemas como tipos.
  • Manejar campos dinámicos y arrays en formularios para casos donde el usuario agrega o quita campos sobre la marcha.

Manejo de datos y estado global

4 objetivos
  • Hacer fetch con useEffect + estados de carga y error para traer datos del servidor manejando bien los estados intermedios.
  • Usar React Query / TanStack Query (useQuery, useMutation, queryClient) para manejar datos del servidor con caché, reintentos y sincronización automática, ahorrándote un montón de código manual.
  • Usar Zustand (crear store, acceder y modificar estado, slices) para manejar estado global de forma simple cuando varios componentes necesitan los mismos datos.
  • Usar Context API (createContext, useContext, Provider) para compartir estado a lo largo del árbol de componentes sin librerías externas.

Navegación

5 objetivos
  • Aprender React Router v6 (BrowserRouter, Routes, Route, Link, NavLink) para construir apps de varias páginas sin recargar el navegador.
  • Crear rutas dinámicas (/usuario/:id) para mostrar contenido distinto según el parámetro de la URL.
  • Usar useParams, useNavigate, useLocation, useSearchParams para leer la URL y navegar mediante código.
  • Implementar rutas protegidas con un componente wrapper para restringir el acceso a páginas que requieren estar logueado.
  • Aplicar rutas anidadas y layouts compartidos para reutilizar estructura común entre varias pantallas.

Rendimiento

4 objetivos
  • Usar React.memo para evitar re-renders innecesarios de componentes cuyas props no cambiaron.
  • Aplicar lazy loading con React.lazy y Suspense para cargar componentes solo cuando se necesitan y reducir el peso inicial.
  • Aplicar code splitting por rutas para dividir el código y que cada página cargue solo lo suyo.
  • Aprender virtualización de listas largas para renderizar solo los elementos visibles y mantener fluido el scroll en listas enormes.

Ecosistema y herramientas

4 objetivos
  • Usar Vite (crear proyecto, scripts, variables de entorno con VITE_) para arrancar y desarrollar proyectos React de forma rápida y moderna.
  • Configurar ESLint + Prettier para React y TypeScript para mantener un código consistente y libre de errores comunes.
  • Usar Axios (interceptors, instancias, manejo de errores global) para hacer peticiones HTTP de forma organizada y centralizar la lógica de red.
  • Usar Zod (schemas, parse, safeParse, inferir tipos con z.infer) para validar datos en tiempo de ejecución y derivar tipos a partir de los esquemas.

Capa 04Parte 1 · Base y empleabilidad

Node.js

El runtime. Entendé cómo funciona por debajo antes de usar frameworks, así sabés qué está pasando de verdad cuando tu servidor responde.

Tecnologías
  • Node.js
Duración estimada
2 semanas
Temas
1
Objetivos
12
Tu progreso

Core de Node.js

12 objetivos
  • Entender qué es V8 y el event loop (call stack, callback queue, microtask queue) para comprender cómo Node ejecuta código asíncrono sin trabarse, tema que además preguntan mucho en entrevistas.
  • Entender el non-blocking I/O para saber por qué Node es tan eficiente en aplicaciones con mucha entrada/salida, como APIs que consultan bases de datos.
  • Diferenciar CommonJS de ESModules (require vs import/export) para entender los dos sistemas de módulos y no confundirte al mezclar código de distintas fuentes.
  • Conocer el package.json (scripts, dependencias, devDependencias, engines) para configurar y documentar tu proyecto, sus dependencias y cómo se ejecuta.
  • Manejar npm (instalar, actualizar, desinstalar, package-lock.json) para gestionar las librerías de tu proyecto y mantener versiones consistentes entre máquinas.
  • Conocer los módulos nativos importantes para resolver tareas comunes sin instalar nada extra:
    • fs (readFile, writeFile, readdir, stat, unlink, versiones sync y async) para leer y escribir archivos en el sistema.
    • path (join, resolve, dirname, basename, extname) para construir rutas de archivos que funcionen en cualquier sistema operativo.
    • os (platform, cpus, homedir) para obtener información del sistema donde corre tu app.
    • http para crear un servidor básico sin frameworks y entender qué hacen Express o Nest por debajo.
    • events (EventEmitter, on, emit) para trabajar con el patrón de eventos en el que se basa buena parte de Node.
    • process (env, argv, exit, cwd) para acceder a variables de entorno, argumentos y controlar el proceso.
  • Entender los streams (Readable, Writable, Transform, pipe) para procesar datos por partes sin cargar todo en memoria, ideal para archivos grandes.
  • Saber qué son los buffers y cuándo se usan para manejar datos binarios crudos como imágenes o archivos.
  • Comparar async/await vs callbacks vs Promises para entender la evolución del manejo de asincronía y por qué hoy se prefiere async/await.
  • Aplicar manejo de errores (try/catch, errores en Promises no capturadas) para evitar que un fallo no controlado tumbe todo el proceso.
  • Usar variables de entorno con dotenv para mantener configuración y secretos fuera del código.
  • Hacer debugging (console.log, node --inspect, breakpoints) para encontrar y resolver errores de forma más eficiente que adivinando.

Capa 05Parte 1 · Base y empleabilidad

Express.js

El framework minimalista. Aprendelo antes de NestJS — te enseña qué hace un servidor HTTP de verdad, sin tanta magia de por medio.

Tecnologías
  • Express
Duración estimada
3 semanas
Temas
6
Objetivos
32
Tu progreso

Fundamentos

5 objetivos
  • Aprender a crear un servidor (express(), app.listen()) para levantar tu primera API y entender el punto de partida de toda app backend.
  • Manejar los métodos HTTP (app.get(), app.post(), app.put(), app.patch(), app.delete()) para responder a las distintas acciones que pide el cliente según la convención REST.
  • Conocer el objeto req (req.params, req.query, req.body, req.headers, req.cookies, req.ip) para leer toda la información que llega en una petición.
  • Conocer el objeto res (res.json(), res.send(), res.status(), res.redirect(), res.cookie()) para construir y enviar la respuesta al cliente.
  • Dominar los códigos de estado HTTP (200, 201, 400, 401, 403, 404, 409, 422, 500) para comunicar correctamente si una petición salió bien o qué tipo de error ocurrió.

Middlewares

8 objetivos
  • Entender qué es un middleware y cómo funciona la cadena (req, res, next) para comprender el corazón de Express y cómo se procesan las peticiones paso a paso.
  • Usar middlewares globales (app.use()) para aplicar lógica a todas las rutas, como logging o seguridad.
  • Aplicar middlewares de ruta específica para ejecutar lógica solo en ciertos endpoints.
  • Usar express.json() y express.urlencoded() para parsear el body de las peticiones y poder leer los datos que envía el cliente.
  • Usar express.static() para servir archivos estáticos como imágenes, CSS o un frontend ya compilado.
  • Configurar CORS con el paquete cors para permitir que tu frontend en otro dominio pueda consumir la API sin que el navegador lo bloquee.
  • Agregar logging con morgan para ver en consola qué peticiones llegan a tu servidor.
  • Crear middlewares propios (logger, verificador de token, rate limiter simple) para resolver necesidades específicas de tu aplicación.

Rutas y organización

5 objetivos
  • Usar express.Router() para modularizar rutas y no tener todo el código en un solo archivo gigante.
  • Aplicar una estructura de carpetas (routes/, controllers/, middlewares/, services/) para separar responsabilidades y mantener el proyecto ordenado y escalable.
  • Usar parámetros de ruta (/usuarios/:id) para identificar recursos específicos dentro de la URL.
  • Manejar query strings (/usuarios?page=1&limit=10) para recibir filtros, paginación y opciones desde la URL.
  • Agrupar rutas con prefijos (/api/v1/) para organizar tu API y dejar lista la base para versionarla.

Manejo de errores

5 objetivos
  • Crear un middleware de error (función con cuatro parámetros (err, req, res, next)) para centralizar el manejo de fallos en un solo lugar.
  • Usar next(error) para pasar errores al manejador central en vez de responder a mano en cada ruta.
  • Diferenciar errores operacionales de errores de programación para tratarlos distinto: unos se esperan, otros son bugs.
  • Devolver respuestas de error consistentes con estructura JSON para que el frontend siempre sepa cómo interpretar un fallo.
  • Manejar rutas no encontradas (404) para responder con claridad cuando alguien pide algo que no existe.

Variables de entorno y configuración

4 objetivos
  • Usar dotenv para cargar el archivo .env en desarrollo y mantener la configuración separada del código.
  • Crear un .env.example como documentación para que cualquiera sepa qué variables necesita el proyecto sin exponer las reales.
  • Separar la configuración en un archivo config.js para centralizar valores y leerlos de forma ordenada.
  • Definir variables para PORT, DATABASE_URL, JWT_SECRET, NODE_ENV para configurar el puerto, la base de datos, los secretos y el entorno de ejecución.

Herramientas útiles

5 objetivos
  • Validar con express-validator o joi para asegurarte de que los datos que llegan cumplen las reglas antes de procesarlos.
  • Subir archivos con multer para manejar la carga de imágenes o documentos desde el cliente.
  • Aplicar rate limiting con express-rate-limit para limitar cuántas peticiones puede hacer un cliente y protegerte de abusos.
  • Usar Helmet.js para configurar headers de seguridad y reducir vulnerabilidades comunes con poca configuración.
  • Usar compression para comprimir las respuestas y que tu API responda más liviano y rápido.

Capa 06Parte 1 · Base y empleabilidad

NestJS

El framework enterprise. Arquitectura similar a Spring Boot — si ya lo tocaste, vas a reconocer los patrones. Es lo que usan muchas empresas grandes en CR.

Tecnologías
  • NestJS
Duración estimada
4 semanas
Temas
9
Objetivos
41
Tu progreso

Conceptos fundamentales

4 objetivos
  • Entender la arquitectura modular (módulos, controladores, servicios, providers) para organizar aplicaciones grandes de forma ordenada y mantenible.
  • Comprender qué son los decoradores y cómo funcionan en TypeScript, porque son la base de toda la sintaxis de Nest.
  • Entender la inyección de dependencias (@Injectable(), constructores, tokens) para que Nest cree y conecte tus clases automáticamente, haciendo el código más desacoplado y testeable.
  • Conocer el ciclo de vida de una petición en Nest para saber por dónde pasa una request (middleware, guards, interceptors, pipes) y dónde meter cada lógica.

Módulos

5 objetivos
  • Crear módulos (@Module({ imports, controllers, providers, exports })) para agrupar funcionalidades relacionadas en bloques independientes.
  • Entender el módulo raíz AppModule como el punto de entrada que arma toda la aplicación.
  • Crear módulos de características (UsuariosModule, AuthModule) para dividir la app por dominios de negocio.
  • Usar módulos globales (@Global()) para exponer providers a toda la app sin tener que importarlos en cada módulo.
  • Configurar el módulo de configuración (ConfigModule.forRoot()) para cargar y gestionar las variables de entorno de forma centralizada.

Controladores

5 objetivos
  • Usar @Controller('usuarios') para definir el prefijo de ruta de un grupo de endpoints.
  • Manejar los métodos (@Get(), @Post(), @Put(), @Patch(), @Delete()) para mapear cada acción HTTP a un método del controlador.
  • Usar los decoradores de parámetros (@Param('id'), @Body(), @Query(), @Headers(), @Req(), @Res()) para extraer datos de la petición de forma declarativa.
  • Definir códigos de respuesta con @HttpCode(201) para devolver el estado HTTP correcto según la operación.
  • Usar @Redirect() para redirigir al cliente a otra URL cuando corresponde.

Servicios y lógica de negocio

4 objetivos
  • Aplicar @Injectable() y el patrón de servicio para encapsular la lógica de negocio fuera de los controladores.
  • Separar la lógica del controlador al servicio para que el controlador solo reciba la petición y delegue, manteniendo todo más limpio y testeable.
  • Crear repositorios (servicios que hablan con la base de datos) para aislar el acceso a datos del resto de la lógica.
  • Inyectar servicios en otros servicios para reutilizar lógica y mantener responsabilidades bien separadas.

DTOs y validación

5 objetivos
  • Crear Data Transfer Objects (clases que definen la forma del body) para tipar y documentar exactamente qué datos espera cada endpoint.
  • Usar class-validator (@IsString(), @IsEmail(), @IsNotEmpty(), @Min(), @Max(), @IsOptional()) para validar automáticamente los datos que llegan.
  • Usar class-transformer (@Exclude(), @Expose(), @Transform()) para transformar datos de entrada y salida, como ocultar campos sensibles en la respuesta.
  • Configurar un ValidationPipe global para validar todos los DTOs automáticamente sin repetir código en cada controlador.
  • Usar respuestas tipadas con clases de respuesta para controlar y documentar exactamente qué devuelve la API.

Guards y autenticación

5 objetivos
  • Usar @UseGuards() en controlador o método para proteger rutas y permitir el acceso solo a quien cumpla ciertas condiciones.
  • Implementar la interface CanActivate (método canActivate()) para definir tu propia lógica de quién puede entrar a una ruta.
  • Crear un AuthGuard con JWT usando passport-jwt para verificar que el usuario está autenticado antes de acceder a un recurso.
  • Crear un guard de roles para verificar permisos según el rol del usuario y restringir acciones sensibles.
  • Crear un decorador personalizado @GetUsuario() para obtener el usuario autenticado directamente desde la request de forma limpia.

Interceptors y pipes

5 objetivos
  • Usar interceptors para transformar la respuesta, hacer logging o cachear, ejecutando lógica antes o después del controlador.
  • Aplicar @UseInterceptors(TransformInterceptor) para envolver las respuestas en un formato estándar para toda la API.
  • Usar pipes para transformar o validar los datos de entrada antes de que lleguen al controlador.
  • Conocer pipes integrados (ParseIntPipe, ParseUUIDPipe, ValidationPipe) para convertir y validar parámetros automáticamente.
  • Crear un pipe personalizado para resolver transformaciones o validaciones específicas de tu app.

Exception filters

4 objetivos
  • Usar las excepciones nativas (NotFoundException, BadRequestException, UnauthorizedException, ForbiddenException, ConflictException) para lanzar errores con el código HTTP correcto de forma expresiva.
  • Usar HttpException para lanzar excepciones genéricas con mensaje y código a medida.
  • Crear filtros de excepción personalizados para capturar errores y darles el formato que quieras.
  • Devolver respuestas de error consistentes para que el frontend siempre reciba la misma estructura ante cualquier fallo.

Módulos especiales

4 objetivos
  • Usar ConfigModule y ConfigService para acceder a las variables de entorno de forma tipada y segura.
  • Usar ThrottlerModule para aplicar rate limiting integrado y proteger la API de abusos.
  • Documentar la API automáticamente con Swagger (@nestjs/swagger) para generar una página interactiva donde probar y entender los endpoints.
  • Usar @ApiProperty() en los DTOs para enriquecer la documentación de Swagger con descripciones y ejemplos.

Capa 07Parte 1 · Base y empleabilidad

Autenticación

El tema que más se pregunta en entrevistas y el que más cuesta si no se aprende bien. Dominar esto te separa de un montón de candidatos.

Tecnologías
  • JSON Web Tokens
  • Passport.js
Duración estimada
2 semanas
Temas
7
Objetivos
43
Tu progreso

Fundamentos de seguridad

6 objetivos
  • Entender la diferencia entre autenticación y autorización para tener claro que una cosa es saber quién sos y otra es saber qué podés hacer.
  • Diferenciar hashing de encriptación para saber cuándo usar cada uno: el hash es de una sola vía (ideal para contraseñas) y la encriptación es reversible.
  • Usar bcrypt (costo de hashing, hash(), compare()) para guardar contraseñas de forma segura y verificarlas sin almacenarlas nunca en texto plano.
  • Entender por qué no se guardan contraseñas en texto plano para no exponer a tus usuarios si la base de datos se filtra.
  • Comprender HTTPS y por qué importa para proteger los datos que viajan entre el cliente y el servidor.
  • Conocer los headers de seguridad básicos para reducir vulnerabilidades comunes con configuración sencilla.

JWT — JSON Web Tokens

8 objetivos
  • Entender la estructura de un JWT (header, payload, signature) para saber qué contiene un token y cómo está armado.
  • Comprender cómo se firma y verifica un token para confiar en que la información no fue alterada.
  • Usar jsonwebtoken (sign(), verify(), opciones de expiración) para generar y validar tokens en tu backend.
  • Comparar el almacenamiento del token (localStorage vs httpOnly cookies) para entender los pros, contras y riesgos de seguridad de cada opción.
  • Manejar access token vs refresh token (flujo completo) para mantener al usuario logueado de forma segura sin pedirle la contraseña a cada rato.
  • Implementar rotación de refresh tokens para reducir el riesgo si un token se filtra.
  • Aprender a revocar tokens (blacklist en Redis o estrategias alternativas) para poder cerrar sesiones de forma efectiva pese a que los JWT son stateless.
  • Conocer los claims estándar (sub, iat, exp, iss) para usar correctamente la información que viaja dentro del token.

Flujos de autenticación

5 objetivos
  • Implementar el registro (validar datos, hashear contraseña, guardar usuario, retornar token) para dar de alta usuarios de forma segura.
  • Implementar el login (buscar usuario, comparar contraseña, generar tokens) para autenticar y entregar las credenciales de sesión.
  • Implementar el refresh (verificar refresh token, generar nuevo access token) para renovar la sesión sin volver a pedir la contraseña.
  • Implementar el logout (invalidar refresh token) para cerrar sesión de forma segura.
  • Crear una ruta protegida (middleware/guard que verifica el token) para permitir el acceso solo a usuarios autenticados.

Envío de correos

9 objetivos
  • Entender qué es un correo transaccional (verificación, recuperación de contraseña, notificaciones) y por qué se separa del correo masivo o de marketing, para saber qué herramienta corresponde a cada caso.
  • Comprender la diferencia entre enviar correos en local y en producción para no intentar mandar correos reales mientras desarrollás: en local se interceptan y en producción se envían de verdad.
  • Usar Nodemailer (createTransport, sendMail, opciones del transporte SMTP) para tener el cliente base de envío de correos desde Node, que funciona con cualquier proveedor.
  • Configurar un servidor SMTP de prueba en local con Mailtrap o Mailhog para capturar los correos en una bandeja falsa y revisarlos sin que lleguen a nadie real.
  • Usar un servicio transaccional en producción (Resend, SendGrid o Amazon SES) con su API key para enviar correos de verdad de forma confiable y con buena entregabilidad.
  • Manejar las credenciales del correo con variables de entorno (SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS o RESEND_API_KEY) para no exponer secretos y poder cambiar de proveedor entre local y despliegue sin tocar el código.
  • Crear plantillas de correo en HTML (con un motor como Handlebars o cadenas simples) para enviar correos con un formato decente en vez de texto plano.
  • Configurar el módulo de correo en NestJS (@nestjs-modules/mailer o un servicio propio inyectable) para integrar el envío dentro de la arquitectura del framework y reutilizarlo desde cualquier servicio.
  • Enviar el correo de forma asíncrona (sin bloquear la respuesta de la API, idealmente con una cola) para que el usuario no tenga que esperar a que el correo salga antes de recibir respuesta.

Verificación de cuenta y recuperación de contraseña

7 objetivos
  • Implementar la verificación de cuenta por email (generar un token único, enviarlo por correo, validar en un endpoint de confirmación y marcar al usuario como verificado) para asegurarte de que el correo registrado realmente le pertenece al usuario.
  • Guardar el token de verificación con expiración (en base de datos o en Redis con TTL corto) para que el enlace o código deje de ser válido pasado un tiempo y no quede activo para siempre.
  • Bloquear el acceso a usuarios no verificados (un guard que revise el campo isVerified) para proteger acciones sensibles hasta que confirmen su correo.
  • Implementar el reenvío del correo de verificación (con rate limiting) para que el usuario pueda pedir otro enlace si el primero expiró, sin permitir abuso.
  • Implementar el flujo de recuperación de contraseña (solicitar reset, generar token temporal, enviar enlace, validar token y permitir cambiar la contraseña) para que el usuario pueda recuperar su cuenta sin intervención manual.
  • Invalidar el token de reset después de usarlo (o al expirar) para que un mismo enlace no pueda reutilizarse y cerrar el riesgo de que un correo viejo siga funcionando.
  • Usar OTPs o códigos cortos por correo (con TTL corto en Redis) como alternativa al enlace, para flujos donde es más cómodo escribir un código que abrir un link.

Passport.js con NestJS

4 objetivos
  • Usar la estrategia local (passport-local) para autenticar con usuario y contraseña de forma estándar.
  • Usar la estrategia JWT (passport-jwt) para proteger rutas verificando el token en cada petición.
  • Configurar PassportModule y JwtModule en NestJS para integrar todo el sistema de autenticación dentro del framework.
  • Implementar OAuth básico con Google (passport-google-oauth20) para ofrecer login con cuentas externas, algo muy común en apps reales.

Roles y permisos

4 objetivos
  • Definir un enum de roles (admin, usuario, moderador) para clasificar a los usuarios según su nivel de acceso.
  • Crear un guard de roles que verifique el rol dentro del token para restringir acciones a ciertos tipos de usuario.
  • Usar el decorador @Roles('admin') en los controladores para declarar de forma clara qué rol se necesita en cada endpoint.
  • Entender la diferencia entre RBAC básico y sistemas más complejos para saber cuándo basta con roles simples y cuándo necesitás permisos más finos.

Capa 08Parte 1 · Base y empleabilidad

PostgreSQL + Prisma

Ya sabés MySQL — PostgreSQL es casi lo mismo pero más potente. Prisma te da TypeScript en la base de datos, así que escribís queries con autocompletado y seguridad de tipos.

Tecnologías
  • PostgreSQL
  • Prisma
Duración estimada
4 semanas
Temas
4
Objetivos
55
Tu progreso

PostgreSQL — SQL

20 objetivos
  • Conocer los tipos de datos (VARCHAR, TEXT, INTEGER, BIGINT, BOOLEAN, TIMESTAMP, DATE, UUID, JSONB, DECIMAL) para elegir el tipo correcto en cada columna y guardar la información de forma eficiente.
  • Usar GENERATED ALWAYS AS IDENTITY como forma moderna de generar IDs autoincrementales en lugar de SERIAL, para seguir el estándar actual de PostgreSQL.
  • Crear tipos ENUM (CREATE TYPE estado AS ENUM (...)) para limitar una columna a un conjunto fijo de valores, algo que Prisma usa con frecuencia.
  • Aprender a crear y modificar tablas (CREATE TABLE, ALTER TABLE, DROP TABLE) para definir y ajustar la estructura de tu base de datos.
  • Organizar tablas en schemas (CREATE SCHEMA, search_path) para separar la base por módulos o áreas y mantenerla ordenada cuando crece.
  • Aplicar constraints (PRIMARY KEY, FOREIGN KEY, UNIQUE, NOT NULL, CHECK, DEFAULT) para garantizar la integridad de los datos y evitar información inválida o duplicada.
  • Definir acciones referenciales en las llaves foráneas (ON DELETE CASCADE, RESTRICT, SET NULL, ON UPDATE) para controlar qué pasa con los registros hijos cuando se borra o modifica el padre.
  • Dominar el CRUD completo (INSERT INTO, SELECT, UPDATE, DELETE) para crear, leer, actualizar y borrar datos, que es la base de cualquier aplicación.
  • Usar las cláusulas (WHERE, ORDER BY ASC/DESC, LIMIT, OFFSET, GROUP BY, HAVING) para filtrar, ordenar, paginar y agrupar resultados según lo que necesités.
  • Aplicar funciones de agregación (COUNT(), SUM(), AVG(), MIN(), MAX()) para calcular totales, promedios y resúmenes a partir de los datos.
  • Manejar los JOINs (INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL OUTER JOIN) para combinar datos de varias tablas relacionadas en una sola consulta.
  • Escribir subqueries (en WHERE, en FROM, correlacionadas) para resolver consultas complejas anidando una query dentro de otra.
  • Usar CTEs (WITH nombre AS (...) SELECT ...) para dividir consultas complejas en pasos legibles y reutilizables.
  • Aplicar window functions básicas (ROW_NUMBER(), RANK(), PARTITION BY) para hacer cálculos por grupos sin colapsar las filas, útil en rankings y reportes.
  • Crear índices (CREATE INDEX, índices compuestos) y entender cuándo conviene para acelerar las consultas más frecuentes.
  • Usar transacciones (BEGIN, COMMIT, ROLLBACK, SAVEPOINT) para agrupar operaciones que deben completarse todas o ninguna, manteniendo la consistencia.
  • Crear vistas (CREATE VIEW) para guardar consultas frecuentes como si fueran tablas y simplificar el acceso a datos complejos.
  • Escribir funciones y procedimientos en PL/pgSQL (CREATE FUNCTION, CREATE PROCEDURE) para encapsular lógica que conviene ejecutar directamente en la base de datos.
  • Crear triggers (CREATE TRIGGER ... BEFORE/AFTER INSERT/UPDATE/DELETE) para automatizar acciones como actualizar updated_at o registrar cambios en una tabla de auditoría.
  • Conocer las diferencias clave con MySQL (SERIAL vs AUTO_INCREMENT, ILIKE, arrays, JSONB) para aprovechar lo propio de PostgreSQL y migrar tu conocimiento previo sin tropezar.

Diseño de base de datos

8 objetivos
  • Hacer un diagrama entidad-relación antes de escribir código (dbdiagram.io, draw.io o similar) para pensar la estructura completa y detectar errores de diseño cuando todavía es barato corregirlos.
  • Aprender normalización (1FN, 2FN, 3FN) para entender qué es y por qué importa estructurar los datos sin redundancia ni inconsistencias.
  • Modelar relaciones (uno a uno, uno a muchos, muchos a muchos) para representar correctamente cómo se conectan las entidades del mundo real.
  • Usar tablas pivot para relaciones N:M para conectar dos entidades que se relacionan en ambos sentidos, como usuarios y roles.
  • Comparar estrategias de ID (entero autoincremental vs UUID) para elegir el identificador más adecuado según seguridad y escalabilidad.
  • Implementar soft delete (deleted_at TIMESTAMP DEFAULT NULL) para "borrar" registros sin perderlos realmente, manteniendo el historial.
  • Agregar auditoría básica (created_at, updated_at con DEFAULT NOW()) para saber cuándo se creó y modificó cada registro.
  • Modelar un sistema real (e-commerce, blog, sistema de usuarios) para practicar el diseño completo de una base de datos de principio a fin.

Prisma ORM

15 objetivos
  • Instalar Prisma (prisma init, configurar DATABASE_URL) para conectar tu proyecto Node con la base de datos.
  • Definir el schema (model, tipos, campos opcionales, valores por defecto) para describir tus tablas en un solo archivo legible y tipado.
  • Modelar relaciones en Prisma (@relation, campos de referencia) para conectar tus modelos respetando las relaciones de la base de datos.
  • Manejar migraciones (prisma migrate dev, prisma migrate deploy) para versionar y aplicar cambios en la estructura de la base de forma controlada.
  • Manejar migraciones en escenarios reales para no romper la base cuando ya tiene datos:
    • prisma db pull para generar el schema a partir de una base de datos que ya existe.
    • prisma migrate reset para reiniciar la base en desarrollo cuando el historial se desordena.
    • prisma migrate resolve para marcar y corregir migraciones que fallaron a medias.
    • Cambios en pasos (agregar columna nueva, copiar datos, luego borrar la vieja) para renombrar o transformar columnas en producción sin perder información.
  • Usar Prisma Client (PrismaClient, instancia singleton) para consultar la base con autocompletado y tipos seguros desde tu código.
  • Dominar el CRUD con Prisma para realizar todas las operaciones sobre los datos de forma tipada:
    • create(), createMany() para insertar uno o varios registros.
    • findMany(), findUnique(), findFirst() para leer registros según distintos criterios.
    • update(), updateMany() para modificar uno o varios registros.
    • delete(), deleteMany() para eliminar uno o varios registros.
    • upsert() para crear o actualizar según exista o no el registro.
  • Aplicar filtros avanzados (where con AND, OR, NOT, contains, startsWith, gt, gte, lt, lte, in) para construir consultas precisas según múltiples condiciones.
  • Implementar paginación (skip, take, cursor) para traer los datos por páginas y no saturar la respuesta ni la memoria.
  • Usar selección de campos (select) para traer solo las columnas que necesitás y optimizar la consulta.
  • Cargar relaciones en queries (include) para traer datos relacionados en una sola consulta.
  • Usar transacciones (prisma.$transaction([])) para ejecutar varias operaciones como una sola unidad atómica.
  • Escribir raw queries (prisma.$queryRaw, prisma.$executeRaw) para casos donde necesitás SQL directo que el ORM no cubre.
  • Usar Prisma Studio para explorar y editar los datos visualmente sin escribir queries.
  • Crear seeds (prisma/seed.ts) para poblar la base con datos de prueba de forma automática.

Administración básica de PostgreSQL

12 objetivos
  • Usar psql en la terminal (\l, \dt, \d tabla, \du) y un cliente gráfico como pgAdmin o DBeaver para inspeccionar y administrar la base sin depender solo del ORM.
  • Crear usuarios y roles (CREATE ROLE, CREATE USER) para que cada aplicación o persona se conecte con su propia cuenta.
  • Asignar y quitar permisos (GRANT, REVOKE sobre bases, schemas y tablas) para aplicar el principio de mínimo privilegio y que tu app nunca se conecte como superusuario.
  • Hacer respaldos con pg_dump (formato plano y formato custom) para tener una copia de la base antes de cambios riesgosos o como rutina.
  • Restaurar respaldos con pg_restore y psql para comprobar que tus backups realmente funcionan, porque un respaldo que nunca se probó no es confiable.
  • Conocer los backups automáticos de servicios como Railway o Render para saber qué te dan incluido y qué tenés que hacer por tu cuenta.
  • Entender el límite de conexiones (max_connections) y el connection pooling (connection_limit en la URL de Prisma, PgBouncer) para evitar que la base rechace conexiones cuando la app recibe tráfico o corre en serverless.
  • Conocer los niveles de aislamiento de transacciones (READ COMMITTED, REPEATABLE READ, SERIALIZABLE) para entender qué ve cada transacción cuando varias trabajan al mismo tiempo.
  • Entender locks y deadlocks (SELECT ... FOR UPDATE, bloqueos de filas) para evitar que dos usuarios modifiquen el mismo dato a la vez y saber qué hacer cuando la base se traba.
  • Monitorear la base con pg_stat_activity y consultas de tamaño (pg_size_pretty, pg_total_relation_size) para ver conexiones activas, consultas colgadas y cuánto espacio ocupa cada tabla.
  • Conectarte a la base por SSL (sslmode=require) para que los datos no viajen sin cifrar entre tu app y el servidor.
  • Evitar SQL injection en raw queries (preferir $queryRaw con parámetros sobre $queryRawUnsafe) para no abrir una vulnerabilidad al salir del ORM.

Capa 09Parte 1 · Base y empleabilidad

DevOps básico

Lo mínimo para entrar a trabajar. No necesitás ser experto, pero sí manejarlo con soltura para colaborar en equipo y poner tus proyectos en producción.

Tecnologías
  • Git
  • Docker
  • GitHub Actions
Duración estimada
3 semanas
Temas
4
Objetivos
39
Tu progreso

Git avanzado

13 objetivos
  • Manejar un flujo de trabajo con ramas (main, develop, feature/*, hotfix/*) para trabajar en equipo sin pisarse el código y mantener la rama principal estable.
  • Crear, cambiar y eliminar ramas (checkout -b, switch, branch -d) para organizar tu trabajo en líneas independientes.
  • Entender merge (fast-forward vs merge commit, --no-ff) para combinar ramas sabiendo qué historial vas a generar.
  • Usar rebase (git rebase, git rebase -i para squash y reordenar) para mantener un historial de commits limpio y ordenado.
  • Resolver conflictos (entender los marcadores, usar herramientas visuales) para fusionar cambios cuando dos personas tocaron lo mismo sin romper nada.
  • Usar git stash (stash pop, stash list) para guardar cambios a medias y cambiar de tarea sin perder el trabajo.
  • Usar git cherry-pick para traer un commit puntual de una rama a otra sin mover todo lo demás.
  • Manejar git log (--oneline, --graph, --all) para revisar y entender el historial del proyecto.
  • Usar git bisect para encontrar en qué commit se introdujo un bug mediante búsqueda binaria.
  • Manejar Pull Requests (crear, revisar, comentar, aprobar, mergear) para colaborar y revisar código en equipo, parte central del trabajo diario.
  • Aplicar Conventional Commits (feat:, fix:, chore:, docs:, refactor:) para escribir mensajes de commit claros y estandarizados.
  • Configurar .gitignore (patrones, ignorar node_modules, .env) para no subir al repo archivos pesados o con secretos.
  • Usar tags (git tag) y versionado semántico básico para marcar versiones liberadas de tu proyecto.

Docker

7 objetivos
  • Entender los conceptos (imagen, contenedor, volumen, red, registry) para comprender cómo Docker empaqueta y corre aplicaciones de forma aislada.
  • Escribir un Dockerfile básico para empaquetar tu app y que corra igual en cualquier máquina:
    • FROM para elegir la imagen base.
    • WORKDIR para definir el directorio de trabajo.
    • COPY para copiar tus archivos al contenedor.
    • RUN para ejecutar comandos durante la construcción.
    • ENV para definir variables de entorno.
    • EXPOSE para documentar el puerto que usa la app.
    • CMD para indicar el comando que arranca el contenedor.
  • Manejar los comandos esenciales (build, run, stop, rm, exec, logs, ps, images) para construir, ejecutar y administrar tus contenedores.
  • Usar multi-stage builds para separar la etapa de build de la de producción y generar imágenes más livianas.
  • Usar Docker Compose para levantar varios servicios juntos con un solo comando:
    • Conocer services, image, build, ports, volumes, environment, depends_on, networks para configurar cada servicio del stack.
    • Levantar un stack completo (app Node + PostgreSQL + Redis) para reproducir tu entorno real en local.
    • Usar docker compose up -d, docker compose down, docker compose logs para controlar el ciclo de vida del stack.
    • Usar variables de entorno con .env en Compose para configurar los servicios sin hardcodear valores.
  • Usar volúmenes para persistir los datos de PostgreSQL y no perderlos al recrear el contenedor.
  • Configurar redes en Compose para que los servicios se comuniquen entre sí por nombre.

CI/CD con GitHub Actions

10 objetivos
  • Entender los conceptos (workflow, job, step, runner, evento) para comprender cómo se automatizan tareas en GitHub.
  • Crear el archivo .github/workflows/ci.yml para definir tu pipeline de integración continua.
  • Configurar eventos (push, pull_request, workflow_dispatch) para disparar el workflow cuando corresponde.
  • Armar jobs y steps básicos para encadenar las tareas que querés automatizar.
  • Crear un workflow de CI (instalar dependencias, correr linter, correr tests) para validar automáticamente cada cambio antes de integrarlo.
  • Crear un workflow de CD (build de Docker, push a registry, deploy) para automatizar el despliegue de tu aplicación.
  • Usar secrets en GitHub (${{ secrets.MI_SECRETO }}) para manejar credenciales sin exponerlas en el código.
  • Usar variables de entorno en los workflows para configurar el comportamiento del pipeline.
  • Usar matrix builds para testear en múltiples versiones de Node y asegurar compatibilidad.
  • Cachear dependencias para acelerar los workflows y no reinstalar todo cada vez.

Deploy real

9 objetivos
  • Usar Railway (conectar repo, variables de entorno, PostgreSQL incluido) para desplegar tu backend de forma rápida y con base de datos lista.
  • Usar Render (deploy de web service y de base de datos) como otra opción sencilla para poner apps en producción.
  • Usar Vercel (deploy de frontend React con variables de entorno) para publicar tu frontend de forma óptima.
  • Manejar variables de entorno en producción (nunca en el código) para mantener seguros los secretos en cada ambiente.
  • Revisar logs en producción para diagnosticar errores que solo aparecen en el servidor.
  • Usar AWS EC2 básico (lanzar instancia, conectar por SSH, instalar Node + PM2) para entender un despliegue más manual sobre un servidor propio.
  • Usar PM2 (pm2 start, pm2 logs, pm2 restart) para mantener tu proceso Node corriendo y reiniciarlo si se cae.
  • Configurar Nginx como reverse proxy básico para Node para servir tu app detrás de un servidor web profesional.
  • Configurar un certificado SSL gratuito con Let's Encrypt para servir tu app por HTTPS sin costo.

Capa 10Parte 1 · Base y empleabilidad

Buenas prácticas y testing base

Estos temas no son una etapa aparte: incorporalos desde el primer proyecto. Son lo que diferencia a alguien que "hace que funcione" de alguien que escribe código mantenible y profesional.

Tecnologías
  • Jest
  • ESLint
Duración
Aprenderlos en paralelo desde el inicio
Temas
4
Objetivos
25
Tu progreso

Testing

8 objetivos
  • Entender por qué testear (confianza en los cambios, documentación viva) para perderle el miedo a modificar código sabiendo que las pruebas te avisan si rompiste algo.
  • Aprender Jest (describe, it/test, expect, matchers como toBe, toEqual, toContain, toThrow) para escribir y estructurar pruebas automatizadas.
  • Escribir tests unitarios (funciones puras, servicios aislados) para verificar que cada pieza pequeña de lógica funciona por sí sola.
  • Usar mocks (jest.fn(), jest.spyOn(), jest.mock()) para simular dependencias externas y testear tu código de forma aislada.
  • Usar Supertest para hacer peticiones HTTP a tu API dentro de los tests y verificar que los endpoints responden bien.
  • Escribir tests de integración (endpoint completo con base de datos de prueba) para comprobar que las piezas funcionan juntas de verdad.
  • Medir coverage (jest --coverage) y entender qué conviene medir y qué no, para enfocar el esfuerzo donde aporta valor.
  • Aplicar TDD básico (escribir el test antes del código) para diseñar mejor tu código guiado por las pruebas.

Buenas prácticas de código

8 objetivos
  • Aplicar Clean Code (nombres descriptivos, funciones pequeñas con una sola responsabilidad) para escribir código que cualquiera entienda sin explicaciones.
  • Conocer los principios SOLID (Single Responsibility, Open/Closed, Liskov, Interface Segregation, Dependency Inversion) para diseñar código flexible y fácil de mantener, tema clásico de entrevistas.
  • Aplicar DRY (Don't Repeat Yourself) y entender cuándo sí conviene repetir para evitar duplicación sin caer en abstracciones forzadas.
  • Configurar ESLint (reglas, plugins para TypeScript y React) para detectar errores y malas prácticas automáticamente mientras escribís.
  • Configurar Prettier (formateo automático, integración con ESLint) para mantener un estilo de código consistente sin discutirlo a mano.
  • Aplicar manejo de errores consistente (no swallow errors, siempre loggear) para no esconder fallos y poder diagnosticarlos después.
  • Usar logging estructurado con Winston o Pino (niveles, formato JSON en producción) para registrar lo que pasa en tu app de forma útil y analizable.
  • Aplicar seguridad básica (nunca exponer stack traces en producción, sanitizar inputs, no hardcodear secrets) para proteger tu aplicación de errores comunes y ataques.

Portafolio — los tres proyectos que necesitás

3 objetivos
  • Proyecto 1 — API REST con autenticación: construir un sistema de gestión (usuarios, tareas, productos — lo que quieras) con registro y login con JWT, rutas protegidas, CRUD completo, validación de datos, manejo de errores, tests básicos, deploy en Railway con PostgreSQL y un README con instrucciones para correrlo. Sirve para demostrar que dominás el backend de punta a punta.
  • Proyecto 2 — App full stack completa: construir un frontend en React + backend en Node/NestJS + PostgreSQL, con relaciones entre entidades, paginación, filtros y funcionalidad real, deployed con el frontend en Vercel y el backend en Railway. Sirve para mostrar que sabés conectar y desplegar todo el stack.
  • Proyecto 3 — Algo que te apasione: construir el proyecto que mostrás con orgullo, que puede ser más simple técnicamente pero que resuelva un problema real. Sirve para diferenciarte y demostrar iniciativa propia.

LinkedIn y búsqueda de trabajo en CR

6 objetivos
  • Tener un perfil en inglés y en español para llegar tanto a reclutadores locales como a empresas con clientes en EEUU.
  • Mantener un GitHub con los tres proyectos y README en inglés para que tu código hable por vos ante cualquier reclutador.
  • Conocer las empresas nearshore donde aplicar (Gorilla Logic, EX² Outcoding, Broditec, 3Pillar Global, Softtek, Deloitte Digital, Grupo Inversiones La Carpio) para enfocar tu búsqueda en lugares que contratan este stack.
  • Conocer las plataformas (LinkedIn CR, Computrabajo CR, Indeed CR, Tecoloco) para buscar y postularte a vacantes reales en Costa Rica.
  • Preparar respuestas para entrevistas técnicas (event loop, closures, async/await, diferencias entre == y ===, qué es un middleware) para responder con seguridad las preguntas que más se repiten.
  • Practicar diseñar un sistema en vivo en una entrevista técnica para defender tus decisiones técnicas bajo presión.

Capa 11Parte 2 · Nivel medio-avanzado

Redis

Aparece en prácticamente todos los proyectos de empresa. Lo pedís desde el primer día en nearshore, así que dominarlo te da una ventaja clara.

Tecnologías
  • Redis
Duración estimada
2 semanas
Temas
5
Objetivos
22
Tu progreso

Conceptos fundamentales

4 objetivos
  • Entender qué es Redis (base de datos en memoria, key-value store) para comprender por qué es tan rápido y para qué tipo de tareas brilla.
  • Saber cuándo usar Redis vs PostgreSQL (velocidad vs persistencia) para elegir la herramienta correcta según si necesitás rapidez o almacenamiento duradero.
  • Instalar Redis local y con Docker (redis:alpine en Docker Compose) para integrarlo a tu entorno de desarrollo.
  • Manejar el CLI básico (redis-cli, PING, FLUSHALL, KEYS *, TTL) para inspeccionar y probar Redis directamente desde la terminal.

Estructuras de datos

5 objetivos
  • Usar strings (SET, GET, DEL, EXPIRE, TTL, INCR, DECR) para guardar valores simples, contadores y datos con expiración.
  • Usar hashes (HSET, HGET, HGETALL, HDEL) para guardar objetos con varios campos bajo una sola key.
  • Usar lists (LPUSH, RPUSH, LRANGE, LPOP, RPOP) para manejar colas FIFO/LIFO, útiles para tareas en orden.
  • Usar sets (SADD, SMEMBERS, SISMEMBER, SREM) para manejar conjuntos de elementos únicos sin duplicados.
  • Usar sorted sets (ZADD, ZRANGE, ZRANK) para crear leaderboards y rankings ordenados por puntaje.

Redis desde Node.js / NestJS

4 objetivos
  • Usar la librería ioredis (conexión, comandos básicos, manejo de errores) para conectar tu app de Node con Redis.
  • Crear un singleton de cliente Redis para usar una sola instancia en toda la app y no abrir conexiones de más.
  • Integrar Redis en NestJS con @nestjs/cache-manager o un módulo personalizado para usarlo de forma ordenada dentro del framework.
  • Configurar las variables de entorno (REDIS_URL, REDIS_HOST, REDIS_PORT) para conectar a Redis sin hardcodear datos sensibles.

Patrones de uso reales

5 objetivos
  • Implementar caché de respuestas de API (guardar el resultado de una query costosa con TTL e invalidar al mutar) para responder más rápido y aliviar la base de datos.
  • Manejar sesiones y tokens (refresh tokens con EXPIRE, blacklist de JWT revocados) para controlar sesiones y revocar accesos de forma eficiente.
  • Implementar rate limiting (contar peticiones por IP con INCR + EXPIRE) para limitar el abuso complementando express-rate-limit.
  • Crear colas de trabajo simples (lista como cola FIFO) para procesar tareas en segundo plano sin frenar la respuesta al usuario.
  • Guardar datos temporales (códigos de verificación por email, OTPs con TTL corto) para manejar información que debe expirar sola.

Buenas prácticas

4 objetivos
  • Usar un naming de keys consistente (entidad:id:campo, ejemplo usuario:42:perfil) para mantener Redis ordenado y fácil de entender.
  • Evitar guardar objetos grandes (serializar con JSON.stringify solo lo necesario) para no llenar la memoria innecesariamente.
  • Poner siempre TTL en datos temporales para que las keys no crezcan para siempre y consuman memoria sin control.
  • Hacer monitoreo básico (INFO, MONITOR) para ver el estado de Redis y los comandos en tiempo real cuando algo falla.

Capa 12Parte 2 · Nivel medio-avanzado

Testing en React

Las empresas nearshore que trabajan con clientes en EEUU lo piden. Te diferencia de la mayoría de candidatos locales que solo testean el backend.

Tecnologías
  • Vitest
  • Testing Library
Duración estimada
2 semanas
Temas
5
Objetivos
22
Tu progreso

Por qué testear el frontend

3 objetivos
  • Entender la diferencia entre tests unitarios, de integración y end-to-end en React para saber qué nivel de prueba aplicar en cada caso.
  • Saber qué NO testear (estilos, implementación interna, detalles de librerías) para no perder tiempo en pruebas frágiles que se rompen con cualquier cambio.
  • Adoptar la filosofía de Testing Library (testear comportamiento, no implementación) para escribir pruebas que reflejan cómo el usuario realmente usa la interfaz.

Vitest

4 objetivos
  • Entender por qué usar Vitest sobre Jest en proyectos con Vite (velocidad, compatibilidad nativa) para elegir la herramienta que mejor se integra a tu stack moderno.
  • Configurar Vitest en vite.config.ts (test: { environment: 'jsdom' }) para simular un navegador y poder testear componentes.
  • Aprovechar que comparte la misma API que Jest (describe, it, expect, beforeEach, afterEach) para reutilizar todo lo que ya sabés de testing.
  • Usar vi.fn(), vi.spyOn(), vi.mock() (equivalentes a los de Jest) para simular funciones y módulos en tus pruebas.

React Testing Library (RTL)

6 objetivos
  • Instalar RTL (@testing-library/react, @testing-library/user-event, @testing-library/jest-dom) para tener todo el set de herramientas necesarias para testear componentes.
  • Renderizar componentes (render(), screen) para montarlos en un entorno de prueba y consultar lo que se muestra.
  • Usar queries por prioridad (getByRole > getByLabelText > getByText > getByTestId) para buscar elementos como lo haría el usuario y de paso fomentar accesibilidad.
  • Diferenciar getBy, queryBy, findBy (sincrónicos vs asíncronos) para buscar elementos correctamente según si ya están o aparecen después.
  • Simular interacciones con userEvent (click, type, selectOptions, keyboard) para reproducir lo que hace un usuario real con la interfaz.
  • Usar assertions de jest-dom (toBeInTheDocument, toBeVisible, toHaveValue, toBeDisabled) para verificar el estado del DOM de forma clara y legible.

Patrones de test comunes

6 objetivos
  • Testear que un componente renderiza sin errores para tener una primera red de seguridad básica.
  • Testear que un formulario valida y muestra errores para asegurar que la experiencia ante datos inválidos funciona.
  • Testear que un botón llama a una función al hacer click para verificar que las interacciones disparan la lógica correcta.
  • Testear estados de carga y error en componentes con fetch para confirmar que la UI responde bien mientras espera o cuando algo falla.
  • Mockear módulos externos (vi.mock('axios'), vi.mock('../api/usuarios')) para aislar el componente de la red y las dependencias.
  • Testear hooks personalizados con renderHook para verificar su lógica de forma aislada sin montar un componente entero.

Integración con React Query y formularios

3 objetivos
  • Mockear useQuery y useMutation de TanStack Query para testear componentes que dependen de datos del servidor sin hacer peticiones reales.
  • Testear formularios con React Hook Form (submit, validaciones, errores) para cubrir el flujo completo de captura y validación de datos.
  • Crear un wrapper de providers para tests (QueryClientProvider, Router, Context) para que los componentes que dependen de contexto se puedan renderizar correctamente en las pruebas.

Capa 13Parte 2 · Nivel medio-avanzado

SQL avanzado y rendimiento

Esto es lo que separa a alguien que "sabe SQL" de alguien que lo usa bien en producción. Es la diferencia entre una query que funciona y una que aguanta miles de usuarios.

Tecnologías
  • PostgreSQL
Duración estimada
2 semanas
Temas
5
Objetivos
24
Tu progreso

Análisis de rendimiento

5 objetivos
  • Usar EXPLAIN para leer el plan de ejecución de una query y entender qué hace PostgreSQL por debajo antes de optimizar a ciegas.
  • Usar EXPLAIN ANALYZE para ejecutar la query y medir los tiempos reales, no solo los estimados.
  • Conocer los nodos de plan (Seq Scan, Index Scan, Hash Join, Nested Loop) para interpretar qué estrategia usa la base y detectar dónde está el cuello de botella.
  • Aprender a interpretar cost, rows y actual time para leer correctamente el plan y saber qué parte de la query es la cara.
  • Identificar queries lentos con pg_stat_statements para encontrar de forma sistemática qué consultas están castigando tu base de datos.

Índices avanzados

5 objetivos
  • Entender cuándo un índice NO se usa (funciones en columna, LIKE '%texto', tipos incompatibles) para no crear índices que la base ignora y que no sirven de nada.
  • Crear índices parciales (CREATE INDEX ON pedidos (estado) WHERE estado = 'pendiente') para indexar solo la porción de datos que realmente consultás y ahorrar espacio.
  • Crear índices compuestos entendiendo que el orden de columnas importa (columna de mayor selectividad primero) para que el índice sea efectivo en tus consultas más frecuentes.
  • Crear índices en expresiones (CREATE INDEX ON usuarios (LOWER(email))) para acelerar búsquedas sobre funciones aplicadas a una columna.
  • Entender VACUUM y ANALYZE para saber por qué PostgreSQL necesita mantenimiento y cómo eso afecta el rendimiento.

El problema N+1

5 objetivos
  • Entender qué es el problema N+1 (una query por cada fila en vez de una sola con JOIN) para reconocer uno de los errores de rendimiento más comunes y silenciosos.
  • Aprender a identificarlo (contar queries en los logs, DEBUG en Prisma con log: ['query']) para detectarlo en tu propio código antes de que escale.
  • Resolverlo en Prisma (include en vez de múltiples findUnique en un loop) para traer todo lo necesario en una sola consulta.
  • Resolverlo en SQL puro (JOIN explícito desde el inicio) para entender la solución de raíz sin depender del ORM.
  • Conocer el patrón DataLoader para casos extremos donde necesitás agrupar y optimizar muchas consultas relacionadas.

Consultas avanzadas

5 objetivos
  • Usar window functions (LAG(), LEAD(), FIRST_VALUE(), LAST_VALUE()) para análisis de series y comparaciones entre filas sin colapsar el resultado.
  • Usar LATERAL JOIN para escribir subqueries que referencian columnas de la query exterior, resolviendo casos que un JOIN normal no cubre.
  • Usar índices GIN para búsqueda full-text (to_tsvector, to_tsquery, @@) para hacer búsquedas de texto eficientes dentro de PostgreSQL.
  • Implementar búsqueda full-text básica (crear índice, hacer query, rankear con ts_rank) para ofrecer un buscador real sin depender de servicios externos.
  • Usar operadores de JSONB (->, ->>, @>, ?, #>) para consultar y filtrar datos JSON guardados en columnas.

Prisma y rendimiento

4 objetivos
  • Usar selección explícita de campos con select para nunca traer más datos de los necesarios y reducir el peso de cada consulta.
  • Usar findMany con _count para obtener conteos sin traer todos los registros, ahorrando memoria y tiempo.
  • Usar $queryRaw con tipos para salir del ORM y escribir SQL directo cuando una consulta lo amerita, manteniendo seguridad de tipos.
  • Activar el logging de queries en desarrollo para ver exactamente qué SQL genera Prisma y detectar consultas ineficientes.

Capa 14Parte 2 · Nivel medio-avanzado

Subida de archivos a la nube

Aparece en casi todos los proyectos reales: fotos de perfil, documentos, imágenes de productos. Saber manejar esto bien es casi obligatorio.

Tecnologías
  • Cloudinary
  • Amazon S3
Duración estimada
1.5 semanas
Temas
4
Objetivos
23
Tu progreso

Conceptos base

3 objetivos
  • Entender por qué no se guardan archivos en el servidor (no escala, se pierden en cada deploy) para tomar la decisión correcta desde el inicio del proyecto.
  • Conocer las opciones (AWS S3 como estándar de industria, Cloudinary más simple y con transformaciones incluidas) para elegir el servicio según la complejidad del proyecto.
  • Entender los flujos comunes (subida desde el backend vs subida directa desde el frontend con URL firmada) para diseñar la arquitectura de carga más adecuada en cada caso.

Cloudinary (recomendado para empezar)

7 objetivos
  • Crear cuenta y obtener las credenciales (CLOUDINARY_URL, CLOUD_NAME, API_KEY, API_SECRET) para conectar tu app con el servicio.
  • Configurar el SDK de Node.js (paquete cloudinary con variables de entorno) para integrarlo de forma segura.
  • Subir archivos desde un buffer (con multer.memoryStorage() y cloudinary.uploader.upload_stream()) para enviar archivos a la nube sin guardarlos en disco primero.
  • Entender la respuesta de Cloudinary (public_id, secure_url, format, width, height) para saber qué datos guardar y usar después.
  • Guardar el secure_url en PostgreSQL (no el archivo) para referenciar el archivo en tu base sin almacenar el binario.
  • Eliminar archivos (cloudinary.uploader.destroy(public_id)) para borrar de la nube lo que ya no se necesita.
  • Aplicar transformaciones en la URL (resize, crop, formato WebP automático) para optimizar imágenes sin escribir código extra.

AWS S3 (para proyectos más serios)

8 objetivos
  • Entender los conceptos (bucket, objeto, key, región, ACL) para comprender cómo S3 organiza y controla el acceso a los archivos.
  • Usar el SDK v3 (@aws-sdk/client-s3, PutObjectCommand, GetObjectCommand, DeleteObjectCommand) para subir, leer y borrar archivos desde Node.
  • Configurar las variables de entorno (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, S3_BUCKET) para conectar a AWS de forma segura.
  • Subir archivos con PutObjectCommand (Body, Bucket, Key, ContentType) para almacenar contenido en tu bucket correctamente tipado.
  • Generar URLs firmadas (presigned URLs con getSignedUrl + GetObjectCommand y expiración) para dar acceso temporal y controlado a archivos privados.
  • Implementar la subida directa desde el frontend (el backend genera la URL firmada y el cliente hace PUT directo a S3) para descargar trabajo del servidor y subir más rápido.
  • Configurar políticas de bucket (acceso público vs privado) para decidir cuándo un archivo debe ser visible para todos o restringido.
  • Organizar carpetas lógicas con keys (avatars/userId/filename, documentos/empresaId/archivo) para mantener los archivos ordenados dentro del bucket.

Integración en NestJS

5 objetivos
  • Crear un módulo de archivos (FilesModule con FilesService) para centralizar toda la lógica de subida en un solo lugar.
  • Usar @UseInterceptors(FileInterceptor('archivo')) para recibir archivos en el controlador de forma declarativa.
  • Usar @UploadedFile() con un pipe de validación (tipo MIME, tamaño máximo) para asegurarte de que solo se suban archivos válidos.
  • Validar los tipos permitidos (image/jpeg, image/png, application/pdf) para rechazar formatos no deseados o peligrosos.
  • Responder con la URL pública del archivo subido para que el frontend pueda mostrarlo o referenciarlo de inmediato.

Capa 15Parte 2 · Nivel medio-avanzado

Patrones de API y system design básico

Lo que te preguntan en entrevistas cuando ya pasaste las preguntas técnicas de código. Acá demostrás que pensás como alguien con experiencia, no solo que sabés programar.

Tecnologías
  • Swagger
Duración estimada
2 semanas
Temas
3
Objetivos
39
Tu progreso

Patrones de API maduros

15 objetivos

Paginación por cursor

  • Entender por qué offset + limit falla en datos que cambian (páginas inconsistentes, mala performance) para reconocer las limitaciones de la paginación clásica.
  • Aprender cursor pagination (usar el id o created_at del último elemento como punto de partida) para paginar de forma estable y eficiente en datos que se actualizan.
  • Implementarlo en Prisma (cursor: { id: lastId }, skip: 1, take: pageSize) para aplicar este patrón en proyectos reales.
  • Devolver una respuesta estandarizada ({ data, nextCursor, hasNextPage }) para que el frontend pueda navegar entre páginas de forma predecible.
  • Saber cuándo usar offset vs cursor (reportes estáticos vs feeds en tiempo real) para elegir la estrategia correcta según el caso.

Versionado de API

  • Entender por qué versionar (los clientes existentes no deben romperse con cambios) para evolucionar tu API sin afectar a quien ya la consume.
  • Conocer las estrategias (versión en URL /api/v1/, header Accept, query param) para implementar el versionado de la forma que mejor se ajuste.
  • Distinguir un breaking change de un cambio compatible para saber cuándo realmente necesitás una versión nueva.
  • Mantener dos versiones en paralelo con NestJS (módulos separados por versión) para soportar clientes viejos y nuevos a la vez.
  • Manejar la deprecation (headers de aviso, documentar en Swagger) para dar de baja versiones antiguas de forma ordenada y comunicada.

Diseño de contratos

  • Entender qué es un contrato de API (la promesa al cliente de qué devolvés y qué aceptás) para diseñar interfaces estables y confiables.
  • Definir errores consistentes (siempre la misma estructura { statusCode, message, error }) para que el frontend maneje los fallos de forma uniforme.
  • Definir respuestas paginadas consistentes (siempre la misma estructura { data, meta: { total, page, limit } }) para que el consumo de listas sea siempre igual.
  • Conocer HATEOAS básico (incluir links de navegación en las respuestas) como práctica opcional pero valorada en APIs maduras.
  • Versionar el schema en Swagger para documentar con claridad los cambios entre versiones de la API.

System design básico

13 objetivos

No necesitás ser experto — necesitás poder hablar inteligentemente en una entrevista.

Conceptos que te van a preguntar

  • Entender escalabilidad horizontal vs vertical (agregar más servidores vs un servidor más grande) para explicar cómo crece un sistema bajo carga.
  • Comprender stateless vs stateful para explicar por qué las APIs REST deben ser stateless y cómo eso facilita escalar.
  • Saber qué hace un load balancer (distribuir tráfico entre varias instancias) para describir cómo se reparte la carga entre servidores.
  • Entender el caché (dónde cachear: cliente, CDN, servidor, base de datos; y qué cachear) para mejorar el rendimiento sin sobrecargar la base.
  • Saber cuándo considerar réplicas de lectura en la base de datos para manejar mucha lectura sin afectar las escrituras.
  • Entender para qué sirve un CDN y qué tipo de contenido va ahí para acelerar la entrega de archivos estáticos a usuarios de todo el mundo.

Ejercicios de diseño para entrevistas

  • Diseñar un acortador de URLs (componentes, base de datos, caché) para practicar un clásico de las entrevistas de system design.
  • Diseñar un sistema de notificaciones (cómo llegan, en tiempo real o por polling) para razonar sobre comunicación y tiempo real.
  • Diseñar una API de e-commerce (entidades, relaciones, endpoints, autenticación) para practicar el diseño de un sistema completo y realista.
  • Para cada diseño, dibujar el diagrama, explicar las decisiones y mencionar los trade-offs, porque en la entrevista importa tanto el razonamiento como la solución.

Vocabulario técnico en inglés

  • Manejar términos como throughput, latency, availability, consistency y eventual consistency para comunicarte con propiedad en entrevistas en inglés.
  • Conocer single point of failure, fault tolerance y graceful degradation para hablar de la resiliencia de un sistema.
  • Entender idempotency y por qué importa en operaciones de creación para evitar duplicados ante reintentos.

Accesibilidad (a11y)

11 objetivos

Las empresas nearshore con clientes en EEUU lo exigen por cumplimiento legal (WCAG 2.1).

  • Entender por qué importa (ADA compliance en EEUU, litigios reales por apps inaccesibles) para tomar en serio la accesibilidad como requisito, no como extra.
  • Conocer los estándares WCAG 2.1 (niveles A, AA, AAA) y saber que AA es el mínimo exigido en contratos enterprise.
  • Usar semántica HTML correcta (<button> y no <div onClick>, <nav>, <main>, <h1> en orden) para que la interfaz sea operable y comprensible por tecnologías de asistencia.
  • Aplicar ARIA cuando la semántica no alcanza (aria-label, aria-describedby, aria-expanded, role) para describir elementos complejos a los lectores de pantalla.
  • Garantizar navegación por teclado (todo operable con Tab, Enter, Escape, flechas) para usuarios que no usan mouse.
  • Manejar el focus management (focus() al abrir un modal, restaurar el foco al cerrar, focus-visible) para una navegación por teclado coherente.
  • Cumplir el contraste de colores (mínimo 4.5:1 para texto normal, 3:1 para texto grande) para que el contenido sea legible para todos.
  • Manejar las imágenes (alt descriptivo vs alt="" para decorativas) para dar contexto donde aporta y no ruido donde no.
  • Hacer formularios accesibles (<label for>, mensajes de error asociados con aria-describedby) para que cualquiera pueda completarlos sin problemas.
  • Usar herramientas de auditoría (axe-core, axe DevTools, Lighthouse) para detectar problemas de accesibilidad de forma automática.
  • Integrar axe en los tests (jest-axe o @axe-core/react) para detectar violaciones de accesibilidad automáticamente en tu pipeline.