🏆 2.13 · Proyecto integrador: tu primera API FullStack profesional

⏱ 8h 00min ⚡ 150 XP 🏅 Profesional Junior → Mid 📖 Backend FullStack
"Construir una app profesional completa es lo que te separa de un junior. Aquí lo demuestras."

🎯 Objetivo del tema

Al terminar este tema serás capaz de: En este proyecto integrador aplicarás TODO lo aprendido en el Capítulo 2: crearás una API REST profesional con Express, MongoDB (o PostgreSQL con Prisma), autenticación JWT, CRUD completo, validación, manejo de errores, deploy en Railway, y monitoreo con UptimeRobot + Sentry. El resultado: tu primera API production-ready que puedes usar en tu portafolio y mostrar en entrevistas.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

🗺️ Mapa del tema

Este NO es un tema teórico: es un PROYECTO integrador que demuestra que dominas el backend moderno. Combinarás TODAS las habilidades del Capítulo 2: Express, MongoDB o PostgreSQL, JWT, validaciones, RLS, deploy, monitoreo, buenas prácticas. El resultado será una API que cualquier empresa moderna reconocer como 'production-ready'. Es la pieza que te diferencia de un junior que solo hizo tutoriales.

1. Fase 1: Diseño y planificación

Qué vas a construir, qué stack, qué endpoints, qué schema.

2. Fase 2: Setup del proyecto y conexión a BD

Express + Mongoose (o Prisma), conexión con pool, variables de entorno.

3. Fase 3: Modelos y validaciones

Schemas de Mongoose o Prisma con validación robusta.

4. Fase 4: Autenticación JWT completa

Register, login, refresh, middleware de auth y roles.

5. Fase 5: CRUD + búsqueda + paginación

Rutas completas con validación, paginación, búsqueda.

6. Fase 6: Deploy + monitoreo + documentación

Railway + Sentry + UptimeRobot + README profesional.

2.13.1 Fase 1: Diseño y planificación

Antes de escribir código, planifica. Decide el stack, los endpoints, el schema de BD, y documenta todo en un archivo DECISIONES.md. Esto te ahorra reescrituras a mitad de camino y demuestra pensamiento estructurado.

📷 Imagen referencial: Arquitectura completa FullStack: React frontend, Express + Mongoose backend, MongoDB Atlas, JWT auth, deploy en Railway, monitoreo con Sentry + UptimeRobot.

Elección del proyecto: tu primera decisión

Elige una app que te interese genuinamente. Algunas ideas: biblioteca de películas, gestor de tareas, red social de libros, app de recetas, blog con comentarios, e-commerce simple. Lo importante es que tengas al menos 2-3 entidades relacionadas (ej: usuarios + posts + comentarios), para que el CRUD y las relaciones sean reales.

Stack recomendado

CapaTecnologíaPor qué
BackendExpress + Node.jsLo que aprendiste.El más usado en el mercado.
BDMongoDB Atlas (gratis M0)Si elegiste NoSQL. Schema flexible, fácil.
BD alternativaPostgreSQL + PrismaSi elegiste SQL. Tipos estrictos, migrations.
AuthJWT con bcrypt + jsonwebtokenEstándar del mercado, escalable.
DeployRailwayEl más simple, plan gratuito generoso.
MonitoreoSentry + UptimeRobotErrores + uptime 24/7, ambos gratis.
⭐ DECISIONES.md es tu mapa: DECISIONES.md debe tener: (1) nombre y descripción del proyecto, (2) stack con justificación, (3) lista de endpoints, (4) schema de BD (tablas/colecciones y relaciones), (5) casos de uso principales. Es tu mapa: si te pierdes a mitad del proyecto, vuelves a leer DECISIONES.md y recuperas el rumbo. También demuestra pensamiento crítico a un reclutador.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

2.13.2 Fase 2: Setup del proyecto y conexión a BD

El primer paso técnico: crear la estructura del proyecto, instalar dependencias, configurar variables de entorno, y conectar a la BD. Es el equivalente de preparar el taller antes de empezar a construir.

Estructura recomendada del proyecto

mi-proyecto-fullstack/
├── .env              # variables de entorno (NO subir a Git)
├── .env.example      # plantilla con placeholders (SÍ subir)
├── .gitignore       # .env, node_modules, etc.
├── package.json     # dependencias y scripts
├── README.md        # documentación principal
├── DECISIONES.md    # decisiones de diseño
├── server.js        # punto de entrada
├── src/
│   ├── config/      # configuración (db, etc.)
│   ├── models/       # modelos de Mongoose / Prisma
│   ├── routes/       # rutas de la API
│   ├── controllers/  # lógica de negocio (opcional, o dentro de routes)
│   ├── middleware/   # auth, errores, etc.
│   ├── utils/         # helpers (asyncHandler, validators)
│   └── jobs/         # tareas programadas (opcional)
├── tests/            # tests (opcional pero recomendado)
└── docs/             # documentación extra

Estructura de carpetas profesional

Configuración de conexión (server.js + db.js)

// .env (NO subir a Git)
PORT=3000
NODE_ENV=development
MONGODB_URI=mongodb+srv://user:pass@cluster.mongodb.net/mi_app
JWT_SECRET=este_es_un_secret_largo_y_aleatorio_de_32_caracteres_min
JWT_REFRESH_SECRET=otro_secret_diferente_tambien_de_32_caracteres_min
SENTRY_DSN=https://examplePublicKey@o0.ingest.sentry.io/0

// db.js: conexión a MongoDB con pool
import mongoose from 'mongoose';

const conectarDB = async () => {
  try {
    await mongoose.connect(process.env.MONGODB_URI);
    console.log('MongoDB conectado');
  } catch (error) {
    console.error('Error de conexión:', error.message);
    process.exit(1);
  }
};

export default conectarDB;

// server.js: punto de entrada
import express from 'express';
import * as Sentry from '@sentry/node';
import conectarDB from './src/config/db.js';
import authRoutes from './src/routes/auth.js';
import recursoRoutes from './src/routes/recurso.js';
import { errorHandler } from './src/middleware/errorHandler.js';

Sentry.init({ dsn: process.env.SENTRY_DSN });

const app = express();
app.use(express.json());
app.use(Sentry.Handlers.requestHandler);

// Rutas
app.use('/api/auth', authRoutes);
app.use('/api/recurso', recursoRoutes);

// Health check (para UptimeRobot)
app.get('/health', (req, res) => res.json({ status: 'ok' }));

// Errores
app.use(Sentry.Handlers.errorHandler());
app.use(errorHandler);

conectarDB().then(() => {
  const PORT = process.env.PORT || 3000;
  app.listen(PORT, () => console.log(`Servidor en puerto ${PORT}`));
});

Setup completo: server.js + db.js + Sentry

⭐ /health para UptimeRobot: El endpoint /health es CRÍTICO en producción: lo usa UptimeRobot para revisar que tu API esté viva cada 5 min. Sin él, no tienes forma automática de saber si la API está caída. Es una línea de código (app.get('/health', ...)) que te puede ahorrar horas de debugging cuando algo falla silenciosamente.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

2.13.3 Fase 3: Modelos y validaciones

Los modelos definen la estructura de tus datos. Son la base de toda la app. Invertir tiempo en diseñarlos bien (con validación robusta y las relaciones correctas) te ahorra meses de bugs después.

// models/Recurso.js: ejemplo de modelo con validación completa
import mongoose from 'mongoose';

const recursoSchema = new mongoose.Schema({
  titulo: {
    type: String,
    required: [true, 'El título es obligatorio'],
    trim: true,
    minlength: [3, 'Mínimo 3 caracteres'],
    maxlength: [200, 'Máximo 200 caracteres'],
  },
  descripcion: {
    type: String,
    required: [true, 'La descripción es obligatoria'],
    trim: true,
    maxlength: [2000, 'Máximo 2000 caracteres'],
  },
  categoria: {
    type: String,
    required: true,
    enum: {
      values: ['tech', 'lifestyle', 'educacion', 'entretenimiento'],
      message: '{VALUE} no es una categoría válida',
    },
  },
  tags: {
    type: [String],
    default: [],
  },
  autor: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Usuario',
    required: true,
  },
  publicado: {
    type: Boolean,
    default: true,
  },
  visitas: {
    type: Number,
    default: 0,
  },
}, { timestamps: true });  // crea creadoEn y actualizadoEn automáticamente

// Índices para queries frecuentes
recursoSchema.index({ categoria: 1, creadoEn: -1 });
recursoSchema.index({ titulo: 'text', descripcion: 'text' });

// Método virtual (no se guarda en la BD)
recursoSchema.virtual('resumen').get(function() {
  return `${this.titulo} - ${this.descripcion.substring(0, 100)}...`;
});

export const Recurso = mongoose.model('Recurso', recursoSchema);

Modelo Mongoose con validación completa

⭐ timestamps + índices desde el inicio: Los timestamps: true en el schema crean automáticamente creadoEn y actualizadoEn. Sin esto, tendrías que agregarlos manualmente y actualizarlos en cada save(). Es uno de los detalles que separa un modelo amateur de uno profesional. Lo mismo con los índices: sin ellos, las queries de búsqueda son lentas en colecciones grandes.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

2.13.4 Fase 4: Autenticación JWT completa

Tu API necesita saber QUIÉN hace cada petición. JWT con bcrypt es el estándar. Implementa register, login, refresh, logout, y middlewares de autenticación y autorización por roles.

Checklist de auth que tu app debe tener

  • ✓ POST /api/auth/register con bcrypt.hash(password, 12)
  • ✓ POST /api/auth/login con bcrypt.compare() y emisión de JWT
  • ✓ POST /api/auth/refresh con refresh token en cookie httpOnly
  • ✓ POST /api/auth/logout que limpia la cookie
  • ✓ Middleware authMiddleware que verifica el JWT y añade req.user
  • ✓ Middleware adminMiddleware (opcional) para rutas solo-admin
  • ✓ Variables JWT_SECRET y JWT_REFRESH_SECRET únicas y largas (32+ chars)
  • ✓ Códigos HTTP correctos: 401 (no autenticado), 403 (no autorizado), 201 (creado), 200 (OK), 204 (sin contenido)
  • ✓ Mensajes genéricos: 'Credenciales inválidas' en login (no 'Email no existe' vs 'Contraseña incorrecta')
⭐ Mensaje genérico en login: El detalle de seguridad más violado: en el login, si el email no existe vs la contraseña es incorrecta, muchos devs devuelven mensajes diferentes ('Email no existe' vs 'Contraseña incorrecta'). Esto permite a un atacante saber qué emails están registrados. SIEMPRE devuelve un mensaje genérico: 'Credenciales inválidas'. Es un detalle pequeño con un impacto grande en seguridad.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

2.13.5 Fase 5: CRUD + búsqueda + paginación

El corazón de tu API: las rutas que permiten a los usuarios interactuar con los datos. CRUD (Create, Read, Update, Delete) + búsqueda + paginación es el 80% de lo que cualquier app necesita.

Checklist de rutas que tu app debe tener

  • ✓ GET /api/recurso - listar paginado (con ?page y ?limit)
  • ✓ GET /api/recurso/:id - ver detalle de un recurso
  • ✓ POST /api/recurso - crear (protegido con auth)
  • ✓ PUT /api/recurso/:id - actualizar (protegido, solo el autor)
  • ✓ DELETE /api/recurso/:id - eliminar (protegido, solo el autor o admin)
  • ✓ GET /api/recurso/buscar?q=termino - búsqueda por texto
  • ✓ GET /api/recurso/categoria/:cat - filtrar por categoría
  • ✓ GET /api/recurso/mios - listar solo los del usuario actual
  • ✓ Validación en TODAS las rutas POST/PUT
  • ✓ Códigos HTTP correctos en TODAS las respuestas
⭐ PUT vs PATCH: PUT vs PATCH: PUT reemplaza el recurso COMPLETO (todos los campos). PATCH actualiza SOLO los campos enviados. Si tu frontend envía solo el título, con PUT perderías el resto de los campos; con PATCH solo se actualiza el título. La mayoría de apps modernas usan PATCH para updates parciales. Si quieres mantener compatibilidad REST clásica, usa PUT y exige todos los campos.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

2.13.6 Fase 6: Deploy + monitoreo + documentación

Tu código está listo, pero si no está en internet y monitoreado, no es una app real. La última fase: deploy en Railway, configurar Sentry para tracking de errores, UptimeRobot para uptime 24/7, y escribir un README.md que un reclutador pueda leer en 2 minutos.

El README.md profesional

# 📚 Mi Red Social de Libros

API REST para gestionar libros, reseñas y listas de lectura.
Construida con Node.js, Express, MongoDB Atlas, y JWT.

## 🚀 Demo en vivo
https://mi-api.railway.app

## ✨ Características
- Auth con JWT (registro, login, refresh tokens)
- CRUD completo de libros, reseñas, listas
- Búsqueda por texto y filtros por categoría
- Paginación y ordenamiento
- Tracking de errores con Sentry
- Uptime 24/7 con UptimeRobot
- HTTPS automático
- Documentación con OpenAPI/Swagger

## 🛠️ Stack
- **Backend**: Node.js 20, Express 4
- **BD**: MongoDB Atlas (M0 gratis)
- **Auth**: JWT con bcrypt (12 rounds)
- **Deploy**: Railway
- **Monitoreo**: Sentry + UptimeRobot
- **Validación**: Mongoose validators + express-validator

## 📚 Documentación API
Visita `/api-docs` para la documentación interactiva con Swagger.

## 🏃 Correr localmente
```bash
git clone https://github.com/tu-usuario/mi-proyecto.git
cd mi-proyecto
npm install
cp .env.example .env  # llenar con tus credenciales
npm run dev
```

## 🧪 Tests
```bash
npm test
```

## 📝 Licencia
MIT

## 👤 Autor
Tu Nombre - [LinkedIn](https://linkedin.com/in/tu-usuario) - tu@correo.com

README.md profesional

⭐ README = tu carta de presentación: El README.md es tu CARTA DE PRESENTACIÓN. Un reclutador lo lee ANTES de mirar el código. Si tu README está vacío o es vago ('un proyecto de Node.js'), pierdes la oportunidad. Si está completo con demo, stack, instrucciones, y contacto, ya ganaste puntos. Es la diferencia entre 'ejercicio de clase' y 'proyecto profesional'.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

📚 Contenido ampliado

Material adicional, referencias externas verificadas y ejemplos extendidos.

🤖 AI Mission

Un proyecto integrador es la mejor forma de consolidar todo lo aprendido.

Misión: Construye tu proyecto integrador completo: API REST con Express, MongoDB o PostgreSQL, JWT, CRUD, búsqueda, paginación, deploy en Railway, Sentry, UptimeRobot, y README profesional. Después, pídele a la IA que audite tu código, tu seguridad, y tu deploy. Anota en tu cuaderno: ¿qué aprendiste HACIENDO que ningún tutorial te enseñó? ¿qué fue lo más difícil?

Pasos sugeridos

  1. DECISIONES.md: nombre del proyecto, stack, endpoints, schema, casos de uso.
  2. Setup: npm init, dependencias (express, mongoose, bcrypt, jsonwebtoken, dotenv, cors, helmet), .env.example, .gitignore.
  3. Modelos: 2-3 entidades relacionadas (ej: Usuario, Recurso, Comentario) con validación completa.
  4. Conexión a BD: pool con manejo de errores.
  5. Auth: register, login, refresh, logout, middlewares.
  6. CRUD: 5+ rutas con validación, paginación, búsqueda.
  7. Manejo de errores: middleware centralizado con códigos correctos.
  8. Documentación: OpenAPI/Swagger en /api-docs.
  9. Tests: al menos 5 tests con Jest o Vitest.
  10. Deploy: Railway + variables de entorno + health check.
  11. Monitoreo: Sentry + UptimeRobot.
  12. README: profesional con demo, stack, instrucciones.
  13. Comparte con 2 personas: una técnica, una no técnica. Recoge feedback.
  14. Aplica al menos 2 mejoras basadas en el feedback.
  15. Comparte en LinkedIn: 'Acabo de terminar mi proyecto integrador del curso'. Adjunta screenshots.
  16. Anota en tu cuaderno: 3 cosas que aprendiste HACIENDO, y 1 limitación que encontraste.

📓 Entregable: URL pública del proyecto en producción, capturas de: dashboard de Railway, Sentry capturando errores, UptimeRobot monitoreando, Swagger con la documentación API, tests pasando, README.md profesional, y 1 página de cuaderno con tu reflexión final del Capítulo 2.

🚫 Errores típicos de razonamiento

Error 1: Querer que el proyecto sea 'perfecto' antes de publicarlo.
Por qué: El síndrome del 'casi listo': nunca terminas porque siempre hay algo más. Publica una versión funcional MÍNIMA y luego itera. Tu primer proyecto no será tu mejor trabajo, y está bien: lo importante es que EXISTA y esté público. Cada 3 meses, vuélvelo a revisar con ojos nuevos y agrega mejoras.
Error 2: No documentar nada porque 'el código se explica solo'.
Por qué: El código se explica a SÍ MISMO, no a otros. Un reclutador o un compañero nuevo no sabe qué hace tu app, qué stack usa, ni cómo correrla localmente. DECISIONES.md + README.md + comentarios en código + Swagger /api-docs son la diferencia entre un proyecto que otros pueden USAR y uno que solo tú entiendes.
Error 3: No hacer tests y luego romper algo sin darse cuenta.
Por qué: Sin tests, un cambio en una parte del código puede romper otra parte sin que te enteres hasta que el usuario reporte el bug. Tests automatizados (Jest, Vitest) ejecutan en segundos lo que te tomaría horas probar manualmente. Empieza con 5-10 tests en las funciones críticas (auth, validaciones, queries complejas) y ve creciendo. Es una inversión que se paga sola en tiempo de debugging.
Error 4: No monitorear en producción y enterarte de los errores por usuarios.
Por qué: Sentry + UptimeRobot son GRATIS y te dan visibilidad total de tu app en producción. Sin ellos, te enteras de los errores cuando un usuario se queja (puede ser horas o días después). Con Sentry, ves el error en tiempo real con stack trace y contexto. Con UptimeRobot, te llega un email en 5 minutos si tu API se cae. Es la diferencia entre operar como amateur y como profesional.
Error 5: Olvidar CORS y que el frontend no pueda hablar con el backend.
Por qué: Si tu frontend está en mi-app.vercel.app y tu backend en api.railway.app, el navegador BLOQUEA las peticiones cross-origin por seguridad. Tienes que configurar cors() en tu backend: app.use(cors({ origin: 'https://mi-app.vercel.app' })). Es un error del primer deploy que se resuelve en 2 minutos una que lo identificas, pero que puede hacerte perder horas si no lo conoces.

🧪 Laboratorio práctico

El proyecto integrador es tu carta de presentación al mercado laboral.

Laboratorio: Proyecto integrador: API FullStack profesional con todo lo aprendido

Objetivo: Construir y desplegar una API REST profesional completa que demuestre TODAS las habilidades del Capítulo 2: Express, MongoDB, JWT, CRUD, validaciones, deploy, monitoreo, documentación. El resultado: tu primera API production-ready para tu portafolio.

Pasos

  1. Crea DECISIONES.md: nombre, descripción, stack, endpoints, schema, casos de uso.
  2. npm init -y, type:module. Instala: express, mongoose, bcrypt, jsonwebtoken, dotenv, cors, helmet, express-rate-limit.
  3. Crea .env.example con todas las variables (MONGODB_URI, JWT_SECRET, etc.). Agrégalo a .gitignore.
  4. Crea models/ para 2-3 entidades (ej: Usuario, Libro, Resena) con validación completa.
  5. Crea config/db.js con conexión Mongoose y manejo de errores.
  6. Crea middleware/auth.js (verifica JWT) y middleware/errorHandler.js (errores centralizados).
  7. Crea routes/auth.js: register, login, refresh, logout.
  8. Crea routes/recursos.js: CRUD completo + búsqueda + paginación + filtros.
  9. Crea tests/ con al menos 5 tests (Jest o Vitest).
  10. Crea server.js que orquesta todo: middlewares, rutas, error handler, listen.
  11. Crea README.md profesional con demo, stack, instrucciones, screenshots.
  12. Despliega en Railway: conecta repo, configura env vars, verifica deploy.
  13. Configura Sentry: install @sentry/node, init con DSN, prueba que captura errores.
  14. Configura UptimeRobot: monitor HTTP cada 5 min a tu URL/health.
  15. Comparte con 2 personas: una técnica, una no técnica. Recoge feedback.
  16. Aplica 2 mejoras basadas en el feedback.
  17. Comparte en LinkedIn/Twitter con el enlace y screenshots.
  18. Haz commit final: 'feat: proyecto integrador completo, production-ready'.

📓 Entregable: URL pública del proyecto en producción, capturas de: Railway dashboard, Sentry capturando errores, UptimeRobot monitoreando, tests pasando, Swagger docs, README profesional, y 1 página de cuaderno con tu reflexión final.

📓 Tu cuaderno: Anota pseudocódigo, diagramas, errores que encontraste y respuestas a "explica sin código". La escritura manual refuerza tu razonamiento. Tu profesor puede pedirte que subas fotos de páginas específicas.