84 lines
5.4 KiB
Markdown
84 lines
5.4 KiB
Markdown
📌 CONTEXTO DEL PROYECTO:
|
||
Estoy desarrollando una API en **Node.js** con **TypeScript**, **Express.js**, **Sequelize**, y **Arquitectura Hexagonal (Ports & Adapters)** bajo los principios de **DDD (Domain-Driven Design)** y **SOLID**.
|
||
La API maneja **autenticación con PassportJS**, soporte para **JWT y LocalStrategy**, gestión segura de contraseñas con **bcrypt**, y transformación de respuestas con **DTOs (Data Transfer Objects)**.
|
||
|
||
📌 PRINCIPIOS Y PATRONES A APLICAR:
|
||
✅ **DDD (Domain-Driven Design):**
|
||
- Los **agregados** encapsulan su estado y exponen solo lo necesario.
|
||
- Cada **agregado** tiene su propio **mapper** para conversión entre persistencia y dominio.
|
||
- **Repositorios** manejan **agregados** y deben desacoplarse de Sequelize.
|
||
|
||
✅ **SOLID (Principios de Diseño):**
|
||
- **SRP:** Cada clase tiene una única responsabilidad.
|
||
- **OCP:** El código debe ser fácil de extender sin modificarlo.
|
||
- **LSP:** Los objetos derivados deben poder sustituir a sus clases base.
|
||
- **ISP:** Usar interfaces específicas en lugar de dependencias directas.
|
||
- **DIP:** Usar **interfaces** (`IAuthProvider`, `ITransactionManager`) en lugar de acoplarse a implementaciones concretas.
|
||
|
||
📌 GESTIÓN DE DEPENDENCIAS:
|
||
✅ **Factory Pattern (`createAuthService`)**
|
||
- `AuthService` debe crearse con un **Factory** (`createAuthService()`), permitiendo cambiar su implementación sin afectar la API.
|
||
- `AuthService` depende de `IAuthenticatedUserRepository`, `ITransactionManager` y `IAuthProvider`.
|
||
|
||
📌 AUTENTICACIÓN CON `PassportJS`:
|
||
✅ **Soporte para JWT y LocalStrategy**
|
||
- `PassportAuthProvider` maneja **JWTStrategy** para autenticación con tokens y **LocalStrategy** para validación con email y contraseña.
|
||
- Se debe usar `bcrypt` para cifrar contraseñas antes de almacenarlas.
|
||
- `validateUser()` en `PassportAuthProvider` verifica credenciales con `LocalStrategy`.
|
||
|
||
📌 GESTIÓN SEGURA DE CONTRASEÑAS:
|
||
✅ **Uso de `bcrypt` para cifrado de contraseñas**
|
||
- `PasswordHash.create()` valida la fuerza de la contraseña antes de cifrarla.
|
||
- `bcrypt.compare()` se usa para validar la contraseña al hacer login.
|
||
- Las contraseñas **nunca deben almacenarse en texto plano en la base de datos**.
|
||
|
||
📌 GESTIÓN DE ERRORES:
|
||
✅ **Uso de `ApiError` para respuestas de error estructuradas**
|
||
- `ExpressController` debe devolver errores con `ApiError` (`status`, `title`, `detail`, `timestamp`).
|
||
- `RegisterController` y `LoginController` deben usar `ApiError` en caso de errores (`409 Conflict`, `401 Unauthorized`, `500 Internal Server Error`).
|
||
- Se deben capturar errores de **Sequelize** en `BaseRepository` (`UniqueConstraintError`, `ConnectionError`, `TimeoutError`).
|
||
- **Errores de unicidad (`SequelizeUniqueConstraintError`) deben ser personalizados según el contexto usando `errorMapper` en los repositorios.**
|
||
|
||
📌 FLUJO DE LA API `/register`:
|
||
1️⃣ **Request llega a `RegisterController`**.
|
||
2️⃣ **Valida `email`, `username`, `password` como Value Objects**.
|
||
3️⃣ **Llama a `AuthService.registerUser()`**.
|
||
4️⃣ **`AuthService` usa `validateUser()` para evitar usuarios duplicados**.
|
||
5️⃣ **Si el usuario es nuevo, se cifra la contraseña con `bcrypt.hash()`**.
|
||
6️⃣ **Se almacena en la BD con `AuthenticatedUserRepository.create()`**.
|
||
7️⃣ **Se generan `accessToken` y `refreshToken` con `PassportAuthProvider`**.
|
||
8️⃣ **Se responde con los tokens y el `userId`**.
|
||
|
||
📌 FLUJO DE LA API `/login`:
|
||
1️⃣ **Request llega a `LoginController`**.
|
||
2️⃣ **Llama a `AuthService.loginUser()` con `email` y `password`**.
|
||
3️⃣ **`AuthService` busca el usuario en `AuthenticatedUserRepository.findUserByEmail()`**.
|
||
4️⃣ **Si el usuario existe, compara contraseñas con `bcrypt.compare()`**.
|
||
5️⃣ **Si la contraseña es correcta, genera `accessToken` y `refreshToken`**.
|
||
6️⃣ **Devuelve los tokens en la respuesta**.
|
||
|
||
📌 TRANSFORMACIÓN DE RESPUESTAS:
|
||
✅ **Los Controladores son responsables de la transformación de datos antes de enviarlos.**
|
||
✅ **Se usan `Presenters` (`AuthResponsePresenter`) para mapear datos del dominio a DTOs (`AuthResponseDTO`).**
|
||
✅ **Se inyectan `Presenters` en los controladores para desacoplar la lógica de transformación.**
|
||
|
||
📌 SEGURIDAD Y MEJORES PRÁCTICAS:
|
||
✅ **Usar `TransactionManager.complete()` para manejar transacciones.**
|
||
✅ **Evitar acoplamientos directos entre servicios y repositorios.**
|
||
✅ **Usar `bcrypt` con `SALT_ROUNDS=12` configurables en `.env`.**
|
||
✅ **Si ocurre un error en la BD, `rollback()` debe ejecutarse automáticamente.**
|
||
✅ **Devolver códigos HTTP adecuados (`401 Unauthorized`, `409 Conflict`, `500 Internal Server Error`).**
|
||
|
||
📌 SOLICITUDES QUE PUEDO HACERTE:
|
||
- **Generar código** cumpliendo con estas reglas.
|
||
- **Revisar código y detectar violaciones de SOLID o DDD**.
|
||
- **Optimizar `AuthService` para mejorar la seguridad y escalabilidad**.
|
||
- **Implementar `/refresh` para renovar `accessTokens`**.
|
||
- **Escribir pruebas unitarias y de integración para `registerUser()` y `loginUser()`**.
|
||
- **Optimizar `AuthResponsePresenter` para soportar más formatos (`XML`, `CSV`).**
|
||
|
||
⚠️ **IMPORTANTE:**
|
||
- **NO generes código que acople dependencias directamente**.
|
||
- **NO uses Sequelize directamente en los servicios**.
|
||
- **SIEMPRE usa interfaces (`IAuthProvider`, `ITransactionManager`) en lugar de instancias concretas**.
|