617 lines
22 KiB
Markdown
617 lines
22 KiB
Markdown
# Backend MVP - API de Gestión de Actividades
|
|
|
|
Este es un proyecto backend desarrollado con Node.js y Express para gestionar actividades de usuarios con sistema de gamificación (insignias, metas, niveles).
|
|
|
|
## Tabla de Contenidos
|
|
|
|
1. [Tecnologías Utilizadas](#tecnologías-utilizadas)
|
|
2. [Estructura del Proyecto](#estructura-del-proyecto)
|
|
3. [Configuración Inicial](#configuración-inicial)
|
|
4. [Arquitectura y Flujo de Datos](#arquitectura-y-flujo-de-datos)
|
|
5. [Endpoints Disponibles](#endpoints-disponibles)
|
|
6. [Explicación del Código](#explicación-del-código)
|
|
|
|
---
|
|
|
|
## Tecnologías Utilizadas
|
|
|
|
- **Node.js**: Entorno de ejecución de JavaScript
|
|
- **Express**: Framework web para crear la API REST
|
|
- **MySQL**: Base de datos relacional
|
|
- **JWT (JSON Web Tokens)**: Autenticación basada en tokens
|
|
- **bcryptjs**: Encriptación de contraseñas
|
|
- **express-validator**: Validación de datos de entrada
|
|
- **dotenv**: Gestión de variables de entorno
|
|
- **cors**: Permitir peticiones desde el frontend
|
|
- **morgan**: Logger de peticiones HTTP
|
|
|
|
---
|
|
|
|
## Estructura del Proyecto
|
|
|
|
```
|
|
backend-mvp/
|
|
│
|
|
├── server.js # Punto de entrada principal
|
|
│
|
|
├── src/
|
|
│ ├── config/
|
|
│ │ └── db.js # Configuración del pool de MySQL
|
|
│ │
|
|
│ ├── middleware/
|
|
│ │ ├── auth.js # Middleware de autenticación (legacy)
|
|
│ │ ├── requireAdmin.js # Middleware para verificar rol admin
|
|
│ │ └── handleValidation.js # Middleware para procesar validaciones
|
|
│ │
|
|
│ ├── utils/
|
|
│ │ └── jwt.js # Utilidades JWT (sign, verify, requireAuth)
|
|
│ │
|
|
│ ├── validators/
|
|
│ │ ├── auth.validators.js # Validaciones para autenticación
|
|
│ │ ├── actividades.validators.js
|
|
│ │ ├── categorias.validators.js
|
|
│ │ └── ... (otros validadores)
|
|
│ │
|
|
│ └── routes/
|
|
│ ├── auth.routes.js # Rutas de autenticación (login, register)
|
|
│ ├── actividades.routes.js
|
|
│ ├── categorias.routes.js
|
|
│ ├── roles.routes.js
|
|
│ ├── insignias.routes.js
|
|
│ ├── metas.routes.js
|
|
│ ├── niveles.routes.js
|
|
│ ├── notificaciones.routes.js
|
|
│ ├── agenda.routes.js
|
|
│ ├── registroActividad.routes.js
|
|
│ ├── usuarioMetricas.routes.js
|
|
│ ├── usuarioInsignias.routes.js
|
|
│ ├── usuarioRoles.routes.js
|
|
│ └── adminMetrics.routes.js
|
|
│
|
|
├── .env # Variables de entorno (NO incluir en git)
|
|
├── package.json # Dependencias del proyecto
|
|
└── README.md # Este archivo
|
|
```
|
|
|
|
---
|
|
|
|
## Configuración Inicial
|
|
|
|
### 1. Instalar dependencias
|
|
|
|
```bash
|
|
npm install
|
|
```
|
|
|
|
### 2. Configurar variables de entorno
|
|
|
|
Crear un archivo `.env` en la raíz del proyecto con el siguiente contenido:
|
|
|
|
```env
|
|
# Base de datos
|
|
DB_HOST=localhost
|
|
DB_USER=tu_usuario
|
|
DB_PASS=tu_contraseña
|
|
DB_NAME=nombre_base_datos
|
|
DB_PORT=3306
|
|
|
|
# JWT
|
|
JWT_SECRET=tu_secreto_super_seguro_cambiar_en_produccion
|
|
|
|
# Servidor
|
|
PORT=3000
|
|
```
|
|
|
|
### 3. Configurar la base de datos
|
|
|
|
Asegúrate de tener MySQL instalado y crea las tablas necesarias. El proyecto espera las siguientes tablas:
|
|
|
|
- `usuarios`: Información de usuarios (id_usuario, nombre, apellido, email, password_hash, genero, fecha_registro, activo)
|
|
- `roles`: Roles del sistema (id_rol, nombre, descripcion)
|
|
- `usuarios_roles`: Relación muchos a muchos entre usuarios y roles
|
|
- `categorias`: Categorías de actividades
|
|
- `actividades`: Actividades del sistema
|
|
- `insignias`: Insignias/badges del sistema de gamificación
|
|
- `metas`: Metas/objetivos de usuarios
|
|
- `niveles`: Niveles del sistema de progreso
|
|
- `notificaciones`: Sistema de notificaciones
|
|
- `agenda`: Calendario/planificación de actividades
|
|
- `registro_actividad`: Registro de actividades completadas
|
|
- `usuario_metricas`: Estadísticas de usuarios
|
|
- `usuario_insignias`: Insignias obtenidas por usuarios
|
|
|
|
### 4. Iniciar el servidor
|
|
|
|
```bash
|
|
node server.js
|
|
```
|
|
|
|
El servidor estará disponible en `http://localhost:3000` (o el puerto configurado en `.env`).
|
|
|
|
---
|
|
|
|
## Arquitectura y Flujo de Datos
|
|
|
|
### Flujo General de una Petición
|
|
|
|
```
|
|
1. Cliente (Frontend) → HTTP Request
|
|
↓
|
|
2. CORS Middleware (permite peticiones del frontend)
|
|
↓
|
|
3. Body Parser (convierte JSON a objeto JavaScript)
|
|
↓
|
|
4. Morgan Logger (registra la petición en consola)
|
|
↓
|
|
5. Router (encuentra la ruta correspondiente)
|
|
↓
|
|
6. Validadores (express-validator verifica datos)
|
|
↓
|
|
7. handleValidation (procesa errores de validación)
|
|
↓
|
|
8. Middlewares de Autenticación (requireAuth / requireAdmin)
|
|
↓
|
|
9. Lógica de la Ruta (consultas a BD, procesamiento)
|
|
↓
|
|
10. Response (JSON con resultado o error)
|
|
↓
|
|
11. Cliente recibe la respuesta
|
|
```
|
|
|
|
### Flujo de Autenticación
|
|
|
|
```
|
|
REGISTRO:
|
|
Usuario → POST /api/auth/register → Validación → Hash password
|
|
→ Insertar en BD → Generar JWT → Devolver token + user
|
|
|
|
LOGIN:
|
|
Usuario → POST /api/auth/login → Validación → Buscar en BD
|
|
→ Verificar password → Generar JWT → Devolver token + user
|
|
|
|
RUTAS PROTEGIDAS:
|
|
Usuario → Petición con header "Authorization: Bearer <token>"
|
|
→ requireAuth middleware → Verificar token → Adjuntar req.user
|
|
→ Continuar a la ruta → Devolver respuesta
|
|
```
|
|
|
|
### Flujo de Validación
|
|
|
|
```
|
|
Cliente envía datos → Validador (express-validator marca errores)
|
|
→ handleValidation middleware
|
|
→ Si hay errores: devuelve 400 con lista de errores
|
|
→ Si no hay errores: continúa a la lógica de la ruta
|
|
```
|
|
|
|
---
|
|
|
|
## Endpoints Disponibles
|
|
|
|
### Autenticación (`/api/auth`)
|
|
|
|
| Método | Endpoint | Descripción | Auth | Body |
|
|
|--------|----------|-------------|------|------|
|
|
| POST | `/api/auth/register` | Registrar nuevo usuario | No | `{ nombre, apellido, email, genero, password }` |
|
|
| POST | `/api/auth/login` | Iniciar sesión | No | `{ email, password }` |
|
|
| GET | `/api/auth/me` | Obtener perfil + roles | Sí | - |
|
|
| PUT | `/api/auth/me/profile` | Actualizar perfil | Sí | `{ nombre?, apellido? }` |
|
|
| PUT | `/api/auth/me/password` | Cambiar contraseña | Sí | `{ actual, nueva }` |
|
|
|
|
### Catálogos
|
|
|
|
| Endpoint | Descripción |
|
|
|----------|-------------|
|
|
| `/api/categorias` | CRUD de categorías de actividades |
|
|
| `/api/roles` | CRUD de roles del sistema |
|
|
| `/api/actividades` | CRUD de actividades |
|
|
| `/api/insignias` | CRUD de insignias/badges |
|
|
| `/api/metas` | CRUD de metas/objetivos |
|
|
| `/api/niveles` | CRUD de niveles |
|
|
|
|
### Gestión de Usuario
|
|
|
|
| Endpoint | Descripción |
|
|
|----------|-------------|
|
|
| `/api/notificaciones` | Notificaciones del usuario |
|
|
| `/api/agenda` | Agenda/calendario de actividades |
|
|
| `/api/registroactividad` | Registro de actividades completadas |
|
|
| `/api/metricas` | Métricas y estadísticas del usuario |
|
|
| `/api/usuario-insignias` | Insignias obtenidas por el usuario |
|
|
| `/api/usuario-roles` | Roles asignados al usuario |
|
|
|
|
### Administración
|
|
|
|
| Endpoint | Descripción |
|
|
|----------|-------------|
|
|
| `/api/admin/metrics` | Métricas administrativas del sistema |
|
|
|
|
### Rutas de Prueba
|
|
|
|
| Método | Endpoint | Descripción |
|
|
|--------|----------|-------------|
|
|
| GET | `/public` | Ruta pública de prueba |
|
|
| GET | `/__ping` | Health check sin autenticación |
|
|
| GET | `/api/admin/_ping_noauth` | Ping admin sin auth |
|
|
| GET | `/api/admin/_ping_token` | Ping con autenticación |
|
|
|
|
---
|
|
|
|
## Explicación del Código
|
|
|
|
### 1. Punto de Entrada (`server.js`)
|
|
|
|
Este es el archivo principal que:
|
|
1. Carga las variables de entorno con `dotenv`
|
|
2. Configura Express y los middlewares globales (CORS, body parser, logger)
|
|
3. Registra todas las rutas de la aplicación
|
|
4. Inicia el servidor en el puerto especificado
|
|
|
|
**Ver:** [`server.js`](./server.js) para documentación detallada línea por línea.
|
|
|
|
---
|
|
|
|
### 2. Configuración de Base de Datos (`src/config/db.js`)
|
|
|
|
Crea un **pool de conexiones** a MySQL usando `mysql2/promise`. Un pool reutiliza conexiones en lugar de crear una nueva cada vez, mejorando el rendimiento.
|
|
|
|
**Configuración clave:**
|
|
- `connectionLimit: 10` → Máximo 10 conexiones simultáneas
|
|
- `namedPlaceholders: true` → Permite usar `:nombre` en queries
|
|
- Lee las credenciales desde variables de entorno (`.env`)
|
|
|
|
**Exporta:** El pool que se importa en todas las rutas.
|
|
|
|
**Ver:** [`src/config/db.js`](./src/config/db.js) para más detalles.
|
|
|
|
---
|
|
|
|
### 3. Utilidades JWT (`src/utils/jwt.js`)
|
|
|
|
Maneja todo lo relacionado con JSON Web Tokens:
|
|
|
|
**Funciones principales:**
|
|
|
|
1. **`signToken(payload, expiresIn)`**
|
|
- Genera un token JWT firmado
|
|
- Usado en register/login para crear tokens
|
|
- Incluye datos del usuario (id_usuario, email)
|
|
|
|
2. **`verifyTokenPayload(token)`**
|
|
- Verifica que un token sea válido
|
|
- Extrae y devuelve el payload decodificado
|
|
|
|
3. **`requireAuth(req, res, next)`** (Middleware)
|
|
- Protege rutas que requieren autenticación
|
|
- Extrae el token del header `Authorization: Bearer <token>`
|
|
- Verifica el token y adjunta `req.user` con los datos del usuario
|
|
- Si el token es inválido o expiró, devuelve error 401
|
|
|
|
**Flujo de uso:**
|
|
```javascript
|
|
// En una ruta protegida:
|
|
router.get('/perfil', requireAuth, (req, res) => {
|
|
console.log(req.user); // { id_usuario: 123, email: 'user@mail.com' }
|
|
// ... lógica de la ruta
|
|
});
|
|
```
|
|
|
|
**Ver:** [`src/utils/jwt.js`](./src/utils/jwt.js) para documentación completa.
|
|
|
|
---
|
|
|
|
### 4. Middlewares
|
|
|
|
#### a) `handleValidation` (`src/middleware/handleValidation.js`)
|
|
|
|
Procesa los resultados de `express-validator`:
|
|
- Recoge los errores marcados por los validadores
|
|
- Si hay errores: devuelve `400 Bad Request` con la lista
|
|
- Si no hay errores: continúa a la ruta
|
|
|
|
**Uso:**
|
|
```javascript
|
|
router.post('/register', registerValidator, handleValidation, async (req, res) => {
|
|
// Si llega aquí, los datos ya fueron validados
|
|
});
|
|
```
|
|
|
|
#### b) `requireAdmin` (`src/middleware/requireAdmin.js`)
|
|
|
|
Verifica que el usuario autenticado sea administrador:
|
|
1. Verifica que `req.user` exista (debe usarse DESPUÉS de `requireAuth`)
|
|
2. Consulta la BD para verificar si el usuario tiene rol 'admin'
|
|
3. Si es admin: continúa; si no: devuelve `403 Forbidden`
|
|
|
|
**Uso:**
|
|
```javascript
|
|
router.get('/admin/users', requireAuth, requireAdmin(), async (req, res) => {
|
|
// Solo admins pueden llegar aquí
|
|
});
|
|
```
|
|
|
|
**Ver:** [`src/middleware/`](./src/middleware/) para más detalles.
|
|
|
|
---
|
|
|
|
### 5. Validadores (`src/validators/`)
|
|
|
|
Definen reglas de validación usando `express-validator`.
|
|
|
|
**Ejemplo:** `auth.validators.js`
|
|
|
|
```javascript
|
|
const registerValidator = [
|
|
body('nombre').trim().notEmpty().withMessage('Nombre requerido'),
|
|
body('email').isEmail().withMessage('Email inválido'),
|
|
body('password').isLength({ min: 6 }).withMessage('Mínimo 6 caracteres'),
|
|
];
|
|
```
|
|
|
|
**Flujo:**
|
|
1. Se aplica como middleware en la ruta
|
|
2. `express-validator` verifica cada campo
|
|
3. `handleValidation` recoge los errores y responde
|
|
|
|
**Ver:** [`src/validators/auth.validators.js`](./src/validators/auth.validators.js) para ejemplo completo.
|
|
|
|
---
|
|
|
|
### 6. Rutas (`src/routes/`)
|
|
|
|
Cada archivo de rutas maneja un recurso específico (usuarios, actividades, etc.).
|
|
|
|
**Ejemplo:** `auth.routes.js`
|
|
|
|
#### **POST /api/auth/register**
|
|
|
|
**Flujo completo:**
|
|
1. `registerValidator` valida nombre, email, password
|
|
2. `handleValidation` verifica errores
|
|
3. Verifica que el email no esté registrado
|
|
4. Hashea la contraseña con `bcrypt`
|
|
5. Inserta el usuario en la BD
|
|
6. Genera un token JWT con `signToken()`
|
|
7. Devuelve el token + datos del usuario
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"nombre": "Juan",
|
|
"apellido": "Pérez",
|
|
"email": "juan@mail.com",
|
|
"genero": "M",
|
|
"password": "miPassword123"
|
|
}
|
|
```
|
|
|
|
**Response (201):**
|
|
```json
|
|
{
|
|
"msg": "Usuario registrado con éxito",
|
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
"user": {
|
|
"id_usuario": 1,
|
|
"nombre": "Juan",
|
|
"apellido": "Pérez",
|
|
"email": "juan@mail.com",
|
|
"genero": "M"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### **POST /api/auth/login**
|
|
|
|
**Flujo completo:**
|
|
1. `loginValidator` valida email y password
|
|
2. Busca el usuario por email en la BD
|
|
3. Verifica que el usuario esté activo
|
|
4. Compara la contraseña con `bcrypt.compare()`
|
|
5. Genera token JWT
|
|
6. Devuelve token + datos del usuario
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"email": "juan@mail.com",
|
|
"password": "miPassword123"
|
|
}
|
|
```
|
|
|
|
**Response (200):**
|
|
```json
|
|
{
|
|
"msg": "Login exitoso",
|
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
"user": {
|
|
"id_usuario": 1,
|
|
"nombre": "Juan",
|
|
...
|
|
}
|
|
}
|
|
```
|
|
|
|
**Ver:** [`src/routes/auth.routes.js`](./src/routes/auth.routes.js) para documentación línea por línea.
|
|
|
|
---
|
|
|
|
## Diagrama de Componentes
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ CLIENTE │
|
|
│ (Frontend - React/Vue) │
|
|
└────────────────────────┬────────────────────────────────────┘
|
|
│ HTTP Request
|
|
│ Authorization: Bearer <token>
|
|
↓
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ SERVER.JS │
|
|
│ ┌──────────────────────────────────────────────────────┐ │
|
|
│ │ MIDDLEWARES GLOBALES │ │
|
|
│ │ - CORS (permite frontend) │ │
|
|
│ │ - express.json() (parsea body) │ │
|
|
│ │ - morgan (logger) │ │
|
|
│ └──────────────────────────────────────────────────────┘ │
|
|
└────────────────────────┬────────────────────────────────────┘
|
|
│
|
|
↓
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ ROUTER (Rutas) │
|
|
│ /api/auth → auth.routes.js │
|
|
│ /api/actividades → actividades.routes.js │
|
|
│ /api/categorias → categorias.routes.js │
|
|
│ ... │
|
|
└────────────────────────┬────────────────────────────────────┘
|
|
│
|
|
↓
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ VALIDADORES + handleValidation │
|
|
│ - registerValidator (express-validator) │
|
|
│ - handleValidation (procesa errores) │
|
|
└────────────────────────┬────────────────────────────────────┘
|
|
│
|
|
↓
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ MIDDLEWARES DE AUTH │
|
|
│ - requireAuth (verifica JWT) │
|
|
│ - requireAdmin (verifica rol admin) │
|
|
└────────────────────────┬────────────────────────────────────┘
|
|
│
|
|
↓
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ LÓGICA DE LA RUTA │
|
|
│ - Consultas a BD (pool) │
|
|
│ - Procesamiento de datos │
|
|
│ - Generación de respuesta │
|
|
└────────────────────────┬────────────────────────────────────┘
|
|
│
|
|
↓
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ BASE DE DATOS │
|
|
│ (MySQL) │
|
|
│ - usuarios, roles, actividades, insignias, etc. │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Conceptos Clave para Entender
|
|
|
|
### 1. **Middleware**
|
|
Funciones que se ejecutan ANTES de la lógica de la ruta. Se ejecutan en orden:
|
|
```javascript
|
|
app.use(cors()); // 1. Permite CORS
|
|
app.use(express.json()); // 2. Parsea JSON
|
|
// ...
|
|
router.post('/login', loginValidator, handleValidation, async (req, res) => {
|
|
// 3. loginValidator → 4. handleValidation → 5. Esta función
|
|
});
|
|
```
|
|
|
|
### 2. **JWT (JSON Web Token)**
|
|
Token firmado que contiene información del usuario. Permite autenticación sin sesiones:
|
|
- **Frontend:** Guarda el token (localStorage/cookie)
|
|
- **Cada petición:** Envía el token en header `Authorization: Bearer <token>`
|
|
- **Backend:** Verifica el token y extrae datos del usuario
|
|
|
|
### 3. **Bcrypt**
|
|
Librería para hashear contraseñas de forma segura:
|
|
- `bcrypt.hash(password, 10)` → Hashea la contraseña
|
|
- `bcrypt.compare(password, hash)` → Verifica si coinciden
|
|
- **NUNCA** se guardan contraseñas en texto plano
|
|
|
|
### 4. **Pool de Conexiones**
|
|
En lugar de abrir/cerrar conexiones a MySQL constantemente, un pool mantiene conexiones abiertas y las reutiliza, mejorando el rendimiento.
|
|
|
|
### 5. **Express Router**
|
|
Permite modularizar las rutas:
|
|
```javascript
|
|
// En server.js
|
|
app.use('/api/auth', authRoutes);
|
|
|
|
// En auth.routes.js
|
|
router.post('/login', ...); // Resulta en: POST /api/auth/login
|
|
```
|
|
|
|
---
|
|
|
|
## Para Estudiantes
|
|
|
|
### Cómo leer este código paso a paso
|
|
|
|
1. **Empieza por `server.js`**: Entiende cómo se inicia el servidor y se registran las rutas.
|
|
|
|
2. **Lee `src/config/db.js`**: Aprende cómo se conecta a MySQL.
|
|
|
|
3. **Estudia `src/utils/jwt.js`**: Comprende cómo funciona la autenticación con JWT.
|
|
|
|
4. **Analiza `src/routes/auth.routes.js`**: Sigue el flujo completo de register/login.
|
|
|
|
5. **Revisa los middlewares**: Entiende cómo `requireAuth`, `handleValidation`, etc. protegen y validan.
|
|
|
|
6. **Explora otros módulos de rutas**: Aplica lo aprendido a otras funcionalidades.
|
|
|
|
### Preguntas frecuentes
|
|
|
|
**¿Cómo funciona el login?**
|
|
1. Usuario envía email + password
|
|
2. Backend busca el usuario en BD
|
|
3. Compara password con bcrypt
|
|
4. Genera un JWT con los datos del usuario
|
|
5. Devuelve el JWT al frontend
|
|
6. Frontend guarda el JWT y lo envía en cada petición
|
|
|
|
**¿Cómo proteger una ruta?**
|
|
```javascript
|
|
router.get('/perfil', requireAuth, async (req, res) => {
|
|
// requireAuth verifica el JWT antes de ejecutar esto
|
|
const userId = req.user.id_usuario;
|
|
// ...
|
|
});
|
|
```
|
|
|
|
**¿Cómo validar datos?**
|
|
```javascript
|
|
const miValidator = [
|
|
body('email').isEmail(),
|
|
body('edad').isInt({ min: 18 })
|
|
];
|
|
|
|
router.post('/ruta', miValidator, handleValidation, async (req, res) => {
|
|
// Si llega aquí, los datos ya están validados
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Buenas Prácticas Implementadas
|
|
|
|
1. **Seguridad:**
|
|
- Contraseñas hasheadas con bcrypt
|
|
- Autenticación con JWT
|
|
- Validación de datos de entrada
|
|
- Variables sensibles en `.env`
|
|
|
|
2. **Código limpio:**
|
|
- Comentarios explicativos
|
|
- Separación de responsabilidades (rutas, middlewares, validadores)
|
|
- Nombres descriptivos de variables y funciones
|
|
|
|
3. **Arquitectura:**
|
|
- Modular (cada funcionalidad en su archivo)
|
|
- Reutilizable (middlewares, validadores)
|
|
- Escalable (fácil agregar nuevas rutas)
|
|
|
|
---
|
|
|
|
## Autor
|
|
|
|
Proyecto educativo desarrollado para aprendizaje de backend con Node.js y Express.
|
|
|
|
---
|
|
|
|
## Licencia
|
|
|
|
Este es un proyecto de escuela sin licencia específica.
|