diff --git a/README.md b/README.md
index e69de29..4abca9b 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1,519 @@
+# 🌊 Código Abisal - API REST
+
+
+
+
+
+
+
+
+
+**API REST profesional para la gestión de artículos sobre las profundidades oceánicas**
+
+[Características](#-características) •
+[Instalación](#-instalación) •
+[Configuración](#️-configuración) •
+[API](#-endpoints-principales) •
+[Despliegue](#-despliegue)
+
+
+
+---
+
+## 📋 Descripción
+
+**Código Abisal** es una API REST robusta y escalable diseñada para gestionar artículos científicos y divulgativos sobre las profundidades del océano. El proyecto permite crear, editar, eliminar y consultar contenido sobre fauna abisal, ecosistemas marinos, exploraciones oceánicas y conservación.
+
+
+
+### 🎯 Objetivo del Proyecto
+
+Proporcionar una plataforma backend completa para compartir conocimiento sobre el mundo abisal, con un sistema de autenticación seguro, gestión de usuarios y un sistema de "likes" para artículos populares.
+
+---
+
+## ✨ Características
+
+### 🔐 Autenticación y Autorización
+- ✅ Registro de usuarios con hash de contraseñas (bcrypt)
+- ✅ Login con JWT (JSON Web Tokens)
+- ✅ Middleware de autenticación y roles (user/admin)
+- ✅ Sistema de recuperación de contraseña con tokens temporales
+
+### 📰 Gestión de Artículos
+- ✅ CRUD completo de artículos (Create, Read, Update, Delete)
+- ✅ Categorías especializadas: Fauna Abisal, Ecosistemas, Exploración, Conservación
+- ✅ Sistema de likes por usuario
+- ✅ Asignación automática de creador (creator_id)
+- ✅ Validaciones robustas con express-validator
+
+### 👥 Gestión de Usuarios
+- ✅ Panel de administración de usuarios (solo admins)
+- ✅ Actualización de perfiles
+- ✅ Protección contra auto-eliminación
+- ✅ Consulta pública de perfiles de usuario
+
+### 🛡️ Seguridad
+- ✅ Conexión TLS/SSL a base de datos (compatible con TiDB Cloud)
+- ✅ Variables de entorno separadas para desarrollo/producción/test
+- ✅ Validación de entrada exhaustiva
+- ✅ Protección contra ataques comunes (SQL injection, XSS)
+
+### 🧪 Testing
+- ✅ Suite de tests con Jest y Supertest
+- ✅ Tests unitarios e integración
+- ✅ Base de datos de prueba aislada
+- ✅ Cobertura completa de endpoints críticos
+
+---
+
+## 🚀 Tecnologías
+
+| Categoría | Tecnologías |
+|-----------|------------|
+| **Runtime** | Node.js 20+ |
+| **Lenguaje** | TypeScript 5.9 |
+| **Framework** | Express 5.1 |
+| **Base de Datos** | MySQL 8.0 / TiDB Cloud |
+| **ORM** | Sequelize 6.37 |
+| **Autenticación** | JWT, bcryptjs |
+| **Validación** | express-validator |
+| **Testing** | Jest, Supertest, ts-jest |
+| **DevOps** | Docker, GitHub Actions |
+
+---
+
+## 📦 Instalación
+
+### Prerrequisitos
+
+```bash
+Node.js >= 20.0.0
+npm >= 10.0.0
+MySQL >= 8.0 o TiDB Cloud
+```
+
+### Pasos de Instalación
+
+1️⃣ **Clonar el repositorio**
+
+```bash
+git clone https://github.com/Codigo-Inmersion/codigo-abisal-server.git
+cd codigo-abisal-server
+```
+
+2️⃣ **Instalar dependencias**
+
+```bash
+npm install
+```
+
+3️⃣ **Configurar variables de entorno**
+
+```bash
+cp .env.example .env
+```
+
+Edita el archivo `.env` con tus credenciales (ver sección [Configuración](#️-configuración))
+
+4️⃣ **Ejecutar migraciones (automático al iniciar)**
+
+```bash
+npm run dev
+```
+
+5️⃣ **Ejecutar tests (opcional)**
+
+```bash
+npm test
+```
+
+---
+
+## ⚙️ Configuración
+
+### Variables de Entorno
+
+Crea un archivo `.env` en la raíz del proyecto con las siguientes variables:
+
+```env
+# Base de Datos
+DB_NAME=tu_base_de_datos
+DB_USER=tu_usuario
+DB_PASS=tu_contraseña
+DB_HOST=tu_host
+DB_PORT=3306
+DB_DIALECT=mysql
+
+# TLS/SSL (opcional, para TiDB Cloud)
+DB_SSL=true
+DB_SSL_CA_PATH=./certs/tidb-ca.pem
+
+# Servidor
+PORT=8000
+CORS_ORIGIN=http://localhost:5173
+
+# JWT
+JWT_SECRET=tu_clave_secreta_muy_segura
+JWT_EXPIRES=7d
+
+# Frontend (para recuperación de contraseña)
+FRONTEND_URL=http://localhost:5173
+```
+
+### Base de Datos de Pruebas
+
+Crea un archivo `.env.test` para tests:
+
+```env
+NODE_ENV=test
+DB_NAME=abisal_app_test
+DB_USER=tu_usuario
+DB_PASS=tu_contraseña
+DB_HOST=localhost
+DB_PORT=3306
+DB_DIALECT=mysql
+DB_SSL=false
+
+PORT=8001
+CORS_ORIGIN=*
+JWT_SECRET=test_secret_key
+JWT_EXPIRES=1h
+```
+
+---
+
+## 🔌 Endpoints Principales
+
+### Base URL
+```
+http://localhost:8000
+```
+
+### 🔐 Autenticación
+
+| Método | Endpoint | Descripción | Auth |
+|--------|----------|-------------|------|
+| `POST` | `/auth/register` | Registrar nuevo usuario | ❌ |
+| `POST` | `/auth/login` | Iniciar sesión | ❌ |
+| `POST` | `/auth/forgot-password` | Solicitar recuperación | ❌ |
+| `POST` | `/auth/reset-password` | Restablecer contraseña | ❌ |
+
+#### Ejemplo: Registro
+
+```bash
+POST /auth/register
+Content-Type: application/json
+
+{
+ "username": "oceanexplorer",
+ "name": "María",
+ "last_name": "González",
+ "email": "maria@example.com",
+ "password": "SecurePass123!"
+}
+```
+
+**Respuesta:**
+```json
+{
+ "message": "Usuario registrado exitosamente",
+ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
+}
+```
+
+---
+
+### 📰 Artículos
+
+| Método | Endpoint | Descripción | Auth |
+|--------|----------|-------------|------|
+| `GET` | `/article` | Listar todos los artículos | ❌ |
+| `GET` | `/article/:id` | Obtener artículo específico | ❌ |
+| `POST` | `/article` | Crear artículo | ✅ User/Admin |
+| `PUT` | `/article/:id` | Actualizar artículo | ✅User /Admin |
+| `DELETE` | `/article/:id` | Eliminar artículo | ✅ Admin |
+| `POST` | `/article/:id/like` | Dar like | ✅ User/Admin |
+| `DELETE` | `/article/:id/like` | Quitar like | ✅ User/Admin |
+
+#### Ejemplo: Crear Artículo
+
+```bash
+POST /article
+Authorization: Bearer {token}
+Content-Type: application/json
+
+{
+ "title": "El Pez Abisal Más Profundo del Mundo",
+ "description": "Descubrimiento de una nueva especie a 8,178 metros",
+ "content": "En las profundidades de la Fosa de las Marianas...",
+ "category": "Fauna Abisal",
+ "species": "Pseudoliparis swirei",
+ "image": "https://example.com/pez-abisal.jpg",
+ "references": "Nature Magazine 2023"
+}
+```
+
+**Respuesta:**
+```json
+{
+ "id": 42,
+ "title": "El Pez Abisal Más Profundo del Mundo",
+ "description": "Descubrimiento de una nueva especie a 8,178 metros",
+ "content": "En las profundidades de la Fosa de las Marianas...",
+ "category": "Fauna Abisal",
+ "species": "Pseudoliparis swirei",
+ "image": "https://example.com/pez-abisal.jpg",
+ "references": "Nature Magazine 2023",
+ "creator_id": 1,
+ "likes": 0,
+ "created_at": "2025-01-15T10:30:00.000Z",
+ "updated_at": "2025-01-15T10:30:00.000Z"
+}
+```
+
+---
+
+### 👥 Usuarios
+
+| Método | Endpoint | Descripción | Auth |
+|--------|----------|-------------|------|
+| `GET` | `/users` | Listar todos los usuarios | ✅ Admin |
+| `GET` | `/users/user/:id` | Perfil público de usuario | ❌ |
+| `PUT` | `/users/:id` | Actualizar usuario | ✅ Admin |
+| `DELETE` | `/users/:id` | Eliminar usuario | ✅ Admin |
+
+---
+
+## 🧪 Testing
+
+
+### Ejecutar Tests
+
+```bash
+# Todos los tests
+npm test
+
+# Tests en modo watch
+npm test -- --watch
+
+# Tests con cobertura
+npm test -- --coverage
+```
+
+### Estructura de Tests
+
+```
+test/
+├── auth.test.ts # Tests de autenticación
+├── article.test.ts # Tests de artículos
+└── jest.setup.ts # Configuración de Jest
+```
+
+### Cobertura Actual
+
+- ✅ Registro y login de usuarios
+- ✅ CRUD completo de artículos
+- ✅ Validaciones de entrada
+- ✅ Autorización y roles
+
+---
+
+## 🐳 Docker
+
+### Construcción de Imagen
+
+```bash
+docker build -t codigo-abisal-api .
+```
+
+### Ejecución con Docker Compose
+
+```bash
+docker-compose up -d
+```
+
+El archivo `docker-compose.yml` ya está configurado para usar la imagen de Docker Hub:
+
+```yaml
+services:
+ api:
+ image: gema284/codigo-abisal-server-api:dev
+ container_name: abisal-api
+ platform: linux/amd64
+ env_file: .env.docker
+ ports:
+ - "8000:8000"
+```
+
+---
+
+## 🚀 Despliegue
+
+### Render (Recomendado)
+
+1️⃣ **Conecta tu repositorio de GitHub**
+
+2️⃣ **Configura las variables de entorno** en el dashboard de Render
+
+3️⃣ **Build Command:**
+```bash
+npm install && npm run build
+```
+
+4️⃣ **Start Command:**
+```bash
+npm start
+```
+
+### Railway / Heroku
+
+Similar a Render, asegúrate de:
+- Configurar todas las variables de entorno
+- Establecer `NODE_ENV=production`
+- Configurar `DB_SSL=true` si usas TiDB Cloud
+
+---
+
+## 📁 Estructura del Proyecto
+
+```
+codigo-abisal-server/
+├── src/
+│ ├── controllers/ # Lógica de negocio
+│ │ ├── ArticleController.ts
+│ │ ├── AuthController.ts
+│ │ ├── UserController.ts
+│ │ └── PasswordResetController.ts
+│ ├── middlewares/ # Middlewares personalizados
+│ │ ├── authMiddlewares.ts
+│ │ └── handleValidation.ts
+│ ├── models/ # Modelos de Sequelize
+│ │ ├── ArticleModel.ts
+│ │ ├── UserModel.ts
+│ │ └── PasswordResetToken.ts
+│ ├── routes/ # Definición de rutas
+│ │ ├── articleRoutes.ts
+│ │ ├── authRoutes.ts
+│ │ ├── userRoutes.ts
+│ │ └── passwordReset.routes.ts
+│ ├── validators/ # Validaciones con express-validator
+│ │ ├── articleValidators.ts
+│ │ ├── userValidators.ts
+│ │ └── passwordResetValidators.ts
+│ ├── utils/ # Utilidades
+│ │ ├── jwt.ts
+│ │ └── resetToken.ts
+│ ├── database/ # Configuración DB
+│ │ └── db_connection.ts
+│ ├── interface/ # Interfaces TypeScript
+│ │ ├── articleInterface.ts
+│ │ └── userInterface.ts
+│ └── app.ts # Punto de entrada
+├── test/ # Tests
+│ ├── auth.test.ts
+│ ├── article.test.ts
+│ └── jest.setup.ts
+├── certs/ # Certificados TLS
+│ └── tidb-ca.pem
+├── .github/workflows/ # CI/CD
+│ └── docker-publish.yml
+├── Dockerfile
+├── docker-compose.yml
+├── tsconfig.json
+├── jest.config.mjs
+├── package.json
+└── README.md
+```
+
+---
+
+## 🔒 Seguridad
+
+### Buenas Prácticas Implementadas
+
+✅ **Hashing de contraseñas** con bcrypt (10 rounds)
+✅ **Tokens JWT** con expiración configurable
+✅ **Validación exhaustiva** de entrada con express-validator
+✅ **Conexión TLS/SSL** a base de datos en producción
+✅ **CORS configurado** para dominios permitidos
+✅ **Variables de entorno** nunca comiteadas
+✅ **Middleware de autorización** por roles
+✅ **Normalización de emails** (lowercase, trim)
+✅ **Protección contra auto-eliminación** de usuarios admin
+
+### Recomendaciones Adicionales
+
+- 🔄 Rotar `JWT_SECRET` periódicamente
+- 🚫 No exponer `PORT` públicamente sin proxy reverso
+- 📝 Implementar rate limiting (ej: express-rate-limit)
+- 📊 Monitorear logs en producción
+- 🛡️ Usar Helmet.js para headers de seguridad
+
+---
+
+## 📝 Scripts Disponibles
+
+```bash
+# Desarrollo con recarga automática
+npm run dev
+
+# Compilar TypeScript a JavaScript
+npm run build
+
+# Ejecutar en producción
+npm start
+
+# Ejecutar tests
+npm test
+```
+
+---
+
+## 🤝 Contribuciones
+
+Las contribuciones son bienvenidas. Por favor:
+
+1. Fork el proyecto
+2. Crea una rama para tu feature (`git checkout -b feature/AmazingFeature`)
+3. Commit tus cambios (`git commit -m 'Add: AmazingFeature'`)
+4. Push a la rama (`git push origin feature/AmazingFeature`)
+5. Abre un Pull Request
+
+---
+
+## 👩🏽🏫👩🏻🏫👩🏼🏫👩🏾🏫👩🏽🏫 Equipo de Desarrollo
+
+| Desarrolladora | GitHub | LinkedIn |
+|----------------|--------|----------|
+| **Camila Arenas** | [GitHub](https://github.com/mcarenashd) | [LinkedIn](https://www.linkedin.com/in/mcarenash) |
+| **Gema Yébenes** | [GitHub](https://github.com/gemayc) | [LinkedIn](https://www.linkedin.com/in/gema-yebenes-83b6a6100/) |
+| **Mariana Moreno** | [GitHub](https://github.com/MarianaMH1195) | [LinkedIn](https://www.linkedin.com/in/mariana-moreno-henao-70305a16b/) |
+| **Olga Ramírez** | [GitHub](https://github.com/olgararo) | [LinkedIn](https://www.linkedin.com/in/olga-ramirez-rodriguez/) |
+| **Rocio Coronel** | [GitHub](https://github.com/Rocio-Coronel) | [LinkedIn](https://www.linkedi) |
+
+
+## 📄 Licencia
+
+Este proyecto está bajo la Licencia ISC. Ver el archivo `LICENSE` para más detalles.
+
+---
+
+## 🙏 Agradecimientos
+
+- Comunidad de TypeScript y Node.js
+- Documentación de Sequelize
+- Express.js Team
+- Render y TiDB Cloud por sus servicios
+
+---
+
+
+
+**[⬆ Volver arriba](#-código-abisal---api-rest)**
+
+Hecho con 💙 para explorar las profundidades del océano
+
+[](https://github.com/Codigo-Inmersion)
+
+
\ No newline at end of file
diff --git a/certs/tidb-ca.pem b/certs/tidb-ca.pem
new file mode 100644
index 0000000..b85c803
--- /dev/null
+++ b/certs/tidb-ca.pem
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
+TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
+cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
+WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
+ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
+MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
+h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
+0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
+A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
+T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
+B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
+B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
+KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
+OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
+jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
+qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
+rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
+hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
+ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
+3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
+NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
+ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
+TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
+jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
+oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
+4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
+mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
+emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
+-----END CERTIFICATE-----
diff --git a/docs/image/Captura de pantalla 2025-10-16 113134.png b/docs/image/Captura de pantalla 2025-10-16 113134.png
new file mode 100644
index 0000000..884e88f
Binary files /dev/null and b/docs/image/Captura de pantalla 2025-10-16 113134.png differ
diff --git a/docs/image/drawSQL-image-export-2025-09-24_2.png b/docs/image/drawSQL-image-export-2025-09-24_2.png
new file mode 100644
index 0000000..2f6d504
Binary files /dev/null and b/docs/image/drawSQL-image-export-2025-09-24_2.png differ
diff --git a/src/app.ts b/src/app.ts
index dab12bb..bdac2bb 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -1,52 +1,148 @@
+// import express from "express";
+// import db_connection from "./database/db_connection.js";
+// import "dotenv/config";
+// import "./models/UserModel.js";
+// import "./models/ArticleModel.js";
+// import authRouter from "./routes/authRoutes.js";
+// import articleRouter from "./routes/articleRoutes.js";
+// import { User } from "./models/UserModel.js";
+// import { Article } from "./models/ArticleModel.js";
+// import passwordResetRouter from "./routes/passwordReset.routes.js";
+// import "./models/PasswordResetToken.js";
+// import cors from "cors";
+// import userRouter from "./routes/userRoutes.js"; // 👈 el nuevo archivo
+
+
+// User.hasMany(Article, { foreignKey: 'creator_id' });
+// Article.belongsTo(User, { foreignKey: 'creator_id' });
+
+// export const app = express();
+// const PORT = process.env.PORT ? Number(process.env.PORT) : 8000;
+// app.use(cors({ origin: process.env.CORS_ORIGIN || "*" })); // puerto de Vite
+// app.use(express.json());
+// app.get("/", (_req, res) => {
+// res.send("Hola API");
+// });
+// app.get("/healthz", (_req, res) => {
+// res.status(200).send("ok");
+// });
+// app.use("/auth", authRouter )
+// app.use("/article", articleRouter)
+// app.use("/users", userRouter);
+// app.use("/auth", passwordResetRouter);
+
+// // await db_connection.sync({ alter: true }); // o { force: true } si quieres regenerar
+
+// async function startServer() {
+// try {
+// // Sincroniza los modelos con la base de datos
+// await db_connection.sync();
+// console.log("✅ Database synchronized successfully.");
+
+// app.listen(PORT, () => {
+// console.log(`🚀 Server is running on port ${PORT}`);
+// });
+// } catch (error) {
+// console.error("❌ Unable to sync database:", error);
+// }
+// }
+
+// if (process.env.NODE_ENV !== 'test') {
+// startServer();
+// }
+
import express from "express";
+import cors from "cors";
+import dotenv from "dotenv";
+
+// ✅ 1) Cargar .env SOLO en desarrollo (en Render ya usas el panel de variables)
+if (process.env.NODE_ENV !== "production") {
+ dotenv.config();
+}
+
import db_connection from "./database/db_connection.js";
-import "dotenv/config";
-import "./models/UserModel.js";
+import "./models/UserModel.js";
import "./models/ArticleModel.js";
-import authRouter from "./routes/authRoutes.js";
-import articleRouter from "./routes/articleRoutes.js";
import { User } from "./models/UserModel.js";
import { Article } from "./models/ArticleModel.js";
-import passwordResetRouter from "./routes/passwordReset.routes.js";
import "./models/PasswordResetToken.js";
-import cors from "cors";
-import userRouter from "./routes/userRoutes.js"; // 👈 el nuevo archivo
+import authRouter from "./routes/authRoutes.js";
+import articleRouter from "./routes/articleRoutes.js";
+import userRouter from "./routes/userRoutes.js";
+import passwordResetRouter from "./routes/passwordReset.routes.js";
+// Relaciones
+User.hasMany(Article, { foreignKey: "creator_id" });
+Article.belongsTo(User, { foreignKey: "creator_id" });
-User.hasMany(Article, { foreignKey: 'creator_id' });
-Article.belongsTo(User, { foreignKey: 'creator_id' });
+export const app = express();
- export const app = express();
+// ✅ 2) PORT: usa el dinámico de Render si existe; 8000 en local
const PORT = process.env.PORT ? Number(process.env.PORT) : 8000;
- app.use(cors({ origin: process.env.CORS_ORIGIN || "*" })); // puerto de Vite
- app.use(express.json());
- app.get("/", (_req, res) => {
+
+// ✅ 3) CORS con **lista** de orígenes (soporta uno o varios desde la env)
+// Ejemplos de CORS_ORIGIN:
+// - Solo prod: "https://codigo-abisal-client.vercel.app"
+// - Prod + local: "https://codigo-abisal-client.vercel.app,http://localhost:5174"
+const rawOrigins = process.env.CORS_ORIGIN || "";
+const whitelist = rawOrigins
+ .split(",")
+ .map(s => s.trim())
+ .filter(Boolean);
+
+// ⚠️ IMPORTANTE: deja SOLO este middleware de CORS (no dupliques otro en otro archivo)
+app.use(
+ cors({
+ origin: (origin, callback) => {
+ // Peticiones sin "Origin" (curl/healthz) → permite
+ if (!origin) return callback(null, true);
+
+ // Si no configuraste nada, permite todo (cámbialo a false si quieres bloquear por defecto)
+ if (whitelist.length === 0) return callback(null, true);
+
+ // Permite si el origin está en la lista
+ if (whitelist.includes(origin)) return callback(null, true);
+
+ // Origen no permitido
+ return callback(new Error("Not allowed by CORS"));
+ },
+ credentials: true, // déjalo true solo si usas cookies/autenticación con credenciales
+ })
+);
+
+// Body parser
+app.use(express.json());
+
+// Rutas
+app.get("/", (_req, res) => {
res.send("Hola API");
});
-app.get("/healthz", (_req, res) => {
- res.status(200).send("ok");
-});
-app.use("/auth", authRouter )
-app.use("/article", articleRouter)
+
+// Healthcheck para Render
+app.get("/healthz", (_req, res) => res.status(200).send("ok"));
+
+app.use("/auth", authRouter);
+app.use("/article", articleRouter);
app.use("/users", userRouter);
app.use("/auth", passwordResetRouter);
-// await db_connection.sync({ alter: true }); // o { force: true } si quieres regenerar
-
+// Arranque
async function startServer() {
try {
- // Sincroniza los modelos con la base de datos
- await db_connection.sync();
- console.log("✅ Database synchronized successfully.");
+ await db_connection.sync();
+ console.log("✅ Database synchronized successfully.");
- app.listen(PORT, () => {
+ // ✅ 4) Escucha en 0.0.0.0 (necesario en Render) y en el PORT correcto
+ app.listen(PORT, "0.0.0.0", () => {
console.log(`🚀 Server is running on port ${PORT}`);
+ console.log("CORS_ORIGIN =", process.env.CORS_ORIGIN || "(no configurado)");
});
} catch (error) {
console.error("❌ Unable to sync database:", error);
+ process.exit(1);
}
}
-if (process.env.NODE_ENV !== 'test') {
+if (process.env.NODE_ENV !== "test") {
startServer();
}
diff --git a/test/.gitkeep b/test/.gitkeep
deleted file mode 100644
index e69de29..0000000