architecture refactoring
This commit is contained in:
209
backend/ARCHITECTURE.md
Normal file
209
backend/ARCHITECTURE.md
Normal file
@@ -0,0 +1,209 @@
|
||||
# Clean Architecture - Backend OptiHack
|
||||
|
||||
## Estructura del Proyecto
|
||||
|
||||
```
|
||||
src/
|
||||
├── config/ # Configuración e integración con librerías
|
||||
│ ├── env.ts # Variables de entorno
|
||||
│ ├── jwt.ts # JwtAdapter - genera y valida tokens
|
||||
│ └── bcrypt.ts # BcryptAdapter - hashea y compara contraseñas
|
||||
│
|
||||
├── domain/ # Lógica de negocio (sin dependencias externas)
|
||||
│ ├── dtos/ # Data Transfer Objects con validación
|
||||
│ │ ├── auth/
|
||||
│ │ │ ├── register-user.dto.ts
|
||||
│ │ │ └── login-user.dto.ts
|
||||
│ │ └── index.ts
|
||||
│ │
|
||||
│ ├── repositories/ # Interfaces de repositorios (contratos)
|
||||
│ │ └── auth.repository.ts
|
||||
│ │
|
||||
│ ├── use-cases/ # Lógica de negocio (casos de uso)
|
||||
│ │ └── auth/
|
||||
│ │ ├── register-user.use-case.ts
|
||||
│ │ ├── login-user.use-case.ts
|
||||
│ │ └── get-me.use-case.ts
|
||||
│ │
|
||||
│ └── errors/ # Errores personalizados
|
||||
│ └── custom.error.ts
|
||||
│
|
||||
├── data/ # Implementación de datos (Prisma, BD)
|
||||
│ ├── postgres/ # Cliente de Prisma
|
||||
│ │ └── index.ts
|
||||
│ └── repositories/ # Implementación de repositorios
|
||||
│ └── auth.repository.impl.ts
|
||||
│
|
||||
├── presentation/ # HTTP (Express, controladores, middlewares)
|
||||
│ ├── auth/
|
||||
│ │ ├── controller.ts
|
||||
│ │ └── routes.ts
|
||||
│ ├── middlewares/
|
||||
│ │ └── auth.middleware.ts
|
||||
│ ├── routes.ts # Rutas principales
|
||||
│ └── server.ts # Instancia de Express
|
||||
│
|
||||
├── app.ts # Punto de entrada
|
||||
└── ...
|
||||
```
|
||||
|
||||
## Flujo de Datos (Regla Principal)
|
||||
|
||||
```
|
||||
HTTP Request
|
||||
↓
|
||||
Controller recibe los datos
|
||||
↓
|
||||
Controller llama al UseCase
|
||||
↓
|
||||
UseCase hace la lógica de negocio
|
||||
↓
|
||||
UseCase llama al Repository
|
||||
↓
|
||||
Repository implementación habla con Prisma
|
||||
↓
|
||||
Prisma ejecuta queries en la BD
|
||||
↓
|
||||
Response va hacia arriba
|
||||
↓
|
||||
HTTP Response
|
||||
```
|
||||
|
||||
### Ejemplo: Register
|
||||
|
||||
1. **Cliente** envía POST `/api/auth/register` con `{ name, email, password }`
|
||||
2. **Controller** recibe la request
|
||||
3. **Controller** llama a `RegisterUserUseCase.execute()`
|
||||
4. **UseCase** valida el DTO
|
||||
5. **UseCase** verifica si el email existe (llama al Repository)
|
||||
6. **Repository** busca en la BD
|
||||
7. **UseCase** hashea la contraseña
|
||||
8. **UseCase** crea el usuario (llama al Repository)
|
||||
9. **Repository** inserta en la BD
|
||||
10. **UseCase** genera el JWT
|
||||
11. **Controller** responde con user + token
|
||||
|
||||
## Responsabilidades por Capa
|
||||
|
||||
### **Config**
|
||||
- Variables de entorno
|
||||
- Adapters (JWT, Bcrypt)
|
||||
- Configuraciones globales
|
||||
|
||||
### **Domain** (Sin dependencias externas)
|
||||
- DTOs con validación
|
||||
- Interfaces de repositorios (contratos)
|
||||
- Casos de uso (lógica de negocio)
|
||||
- Errores personalizados
|
||||
|
||||
### **Data**
|
||||
- Implementación de repositorios
|
||||
- Cliente de Prisma
|
||||
- Queries a la base de datos
|
||||
|
||||
### **Presentation**
|
||||
- Controladores (Express handlers)
|
||||
- Rutas
|
||||
- Middlewares
|
||||
- Validación HTTP
|
||||
|
||||
## Endpoints de Autenticación
|
||||
|
||||
### 1. Register
|
||||
```
|
||||
POST /api/auth/register
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "John Doe",
|
||||
"email": "john@example.com",
|
||||
"password": "password123"
|
||||
}
|
||||
|
||||
Response 201:
|
||||
{
|
||||
"user": {
|
||||
"id": 1,
|
||||
"email": "john@example.com",
|
||||
"name": "John Doe"
|
||||
},
|
||||
"token": "eyJhbGc..."
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Login
|
||||
```
|
||||
POST /api/auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "john@example.com",
|
||||
"password": "password123"
|
||||
}
|
||||
|
||||
Response 200:
|
||||
{
|
||||
"user": {
|
||||
"id": 1,
|
||||
"email": "john@example.com",
|
||||
"name": "John Doe"
|
||||
},
|
||||
"token": "eyJhbGc..."
|
||||
}
|
||||
```
|
||||
|
||||
### 3. GetMe (Protegida)
|
||||
```
|
||||
GET /api/auth/me
|
||||
Authorization: Bearer eyJhbGc...
|
||||
|
||||
Response 200:
|
||||
{
|
||||
"id": 1,
|
||||
"email": "john@example.com",
|
||||
"name": "John Doe",
|
||||
"role": "USER"
|
||||
}
|
||||
```
|
||||
|
||||
## Validaciones
|
||||
|
||||
### DTOs
|
||||
- **name**: string no vacío
|
||||
- **email**: email válido (regex)
|
||||
- **password**: mínimo 6 caracteres
|
||||
|
||||
### Errores
|
||||
- **400 Bad Request**: Datos inválidos
|
||||
- **401 Unauthorized**: Token inválido, usuario no autenticado
|
||||
- **404 Not Found**: Usuario no encontrado
|
||||
- **409 Conflict**: Email ya en uso
|
||||
- **500 Internal Server Error**: Error del servidor
|
||||
|
||||
## Variables de Entorno (.env)
|
||||
|
||||
```
|
||||
PORT=3000 # Puerto del servidor
|
||||
NODE_ENV=development # Entorno
|
||||
DATABASE_URL=postgresql://user:pass@host:5432/db # URL de BD
|
||||
JWT_SEED=tu_secreto_super_seguro # Seed para JWT
|
||||
JWT_EXPIRES_IN=7d # Expiración del token
|
||||
BCRYPT_ROUNDS=10 # Rondas de bcrypt
|
||||
```
|
||||
|
||||
## Cómo Agregar un Nuevo UseCase
|
||||
|
||||
1. **Crear el UseCase** en `domain/use-cases/auth/new-feature.use-case.ts`
|
||||
2. **Agregar método al Repository** en `domain/repositories/auth.repository.ts`
|
||||
3. **Implementar en** `data/repositories/auth.repository.impl.ts`
|
||||
4. **Crear método en Controller** en `presentation/auth/controller.ts`
|
||||
5. **Agregar ruta** en `presentation/auth/routes.ts`
|
||||
|
||||
## Ventajas de Esta Arquitectura
|
||||
|
||||
✓ **Separación de responsabilidades**: Cada capa hace una cosa
|
||||
✓ **Fácil de testear**: UseCase no conoce HTTP ni BD
|
||||
✓ **Mantenible**: Cambios en BD no afectan lógica de negocio
|
||||
✓ **Escalable**: Fácil agregar nuevos módulos
|
||||
✓ **Simple**: No over-engineered, ideal para MVP/Hackathon
|
||||
✓ **Limpio**: Código organizado y fácil de entender
|
||||
Reference in New Issue
Block a user