🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
870 lines
25 KiB
Markdown
870 lines
25 KiB
Markdown
# Patrones de Backend - GAMILIT
|
|
|
|
**Documento:** Analisis de Patrones de Backend Node.js + TypeScript
|
|
**Proyecto de Referencia:** GAMILIT
|
|
**Fecha:** 2025-11-23
|
|
**Analista:** Architecture-Analyst Agent
|
|
|
|
---
|
|
|
|
## 1. VISION GENERAL
|
|
|
|
GAMILIT implementa un **backend modular en Node.js 18+ con Express.js y TypeScript 5+** que demuestra excelentes practicas de organizacion, separacion de responsabilidades y mantenibilidad del codigo.
|
|
|
|
**Stack tecnologico:**
|
|
- **Runtime:** Node.js 18+
|
|
- **Framework:** Express.js
|
|
- **Lenguaje:** TypeScript 5+ (strict mode)
|
|
- **Database Client:** node-postgres (pg)
|
|
- **Testing:** Jest (40 tests, 15% coverage - GAP CRITICO)
|
|
- **Process Manager:** PM2
|
|
- **Linting:** ESLint + Prettier
|
|
|
|
**Metricas:**
|
|
- **LOC:** ~45,000 lineas
|
|
- **Modulos:** 11 modulos funcionales
|
|
- **Endpoints:** 470+ API endpoints
|
|
- **Controllers:** ~50
|
|
- **Services:** ~80
|
|
- **DTOs:** ~100
|
|
- **Entities:** ~40
|
|
|
|
---
|
|
|
|
## 2. ESTRUCTURA MODULAR (11 MODULOS)
|
|
|
|
### 2.1 Organizacion del Backend
|
|
|
|
```
|
|
backend/
|
|
├── src/
|
|
│ ├── shared/ # Codigo compartido (constants SSOT, utils, types)
|
|
│ │ ├── constants/ # ⭐ Single Source of Truth
|
|
│ │ │ ├── enums.constants.ts # 687 lineas de ENUMs
|
|
│ │ │ ├── database.constants.ts # Schemas y tablas
|
|
│ │ │ ├── routes.constants.ts # 368 lineas de rutas API
|
|
│ │ │ ├── regex.ts # Expresiones regulares
|
|
│ │ │ └── index.ts # Barrel export
|
|
│ │ ├── types/ # Tipos TypeScript compartidos
|
|
│ │ ├── utils/ # Utilidades generales
|
|
│ │ └── decorators/ # Decoradores personalizados
|
|
│ │
|
|
│ ├── middleware/ # Middleware de Express
|
|
│ │ ├── auth.middleware.ts # Autenticacion JWT
|
|
│ │ ├── validation.middleware.ts # Validacion de DTOs
|
|
│ │ ├── error.middleware.ts # Manejo de errores global
|
|
│ │ └── logging.middleware.ts # Logging de requests
|
|
│ │
|
|
│ ├── config/ # Configuraciones
|
|
│ │ ├── database.config.ts # Configuracion DB
|
|
│ │ ├── jwt.config.ts # Configuracion JWT
|
|
│ │ └── cors.config.ts # Configuracion CORS
|
|
│ │
|
|
│ ├── database/ # Conexion DB, migrations, seeds
|
|
│ │ ├── connection.ts # Pool de conexiones
|
|
│ │ └── pool.ts # Singleton pool
|
|
│ │
|
|
│ ├── modules/ # ⭐ 11 MODULOS DE NEGOCIO
|
|
│ │ ├── auth/ # Autenticacion y autorizacion
|
|
│ │ ├── educational/ # Contenido educativo
|
|
│ │ ├── gamification/ # Sistema de gamificacion
|
|
│ │ ├── progress/ # Tracking de progreso
|
|
│ │ ├── social/ # Features sociales
|
|
│ │ ├── content/ # Content management
|
|
│ │ ├── admin/ # Panel de administracion
|
|
│ │ ├── teacher/ # Portal de profesor
|
|
│ │ ├── analytics/ # Analytics y reportes
|
|
│ │ ├── notifications/ # Sistema de notificaciones
|
|
│ │ └── system/ # Sistema y configuracion
|
|
│ │
|
|
│ └── main.ts # Entry point de la aplicacion
|
|
│
|
|
├── __tests__/ # Tests (40 tests, 15% coverage)
|
|
├── dist/ # Build output (compilado)
|
|
├── logs/ # Application logs
|
|
├── node_modules/ # Dependencies (95 MB)
|
|
├── package.json # NPM config
|
|
├── tsconfig.json # ⭐ TypeScript config (path aliases)
|
|
├── jest.config.js # Jest config
|
|
├── .eslintrc.js # ESLint config
|
|
└── README.md # Documentacion
|
|
```
|
|
|
|
### 2.2 Los 11 Modulos Funcionales
|
|
|
|
| Modulo | Responsabilidad | Endpoints | Aplicabilidad ERP |
|
|
|--------|-----------------|-----------|-------------------|
|
|
| **auth/** | Autenticacion, autorizacion, usuarios, roles | ~40 | ⭐⭐⭐⭐⭐ MAXIMA |
|
|
| **educational/** | Modulos, ejercicios, recursos educativos | ~60 | ❌ No aplicable |
|
|
| **gamification/** | Logros, rangos, ML Coins, comodines | ~80 | ❌ No aplicable |
|
|
| **progress/** | Tracking de progreso, sesiones, attempts | ~90 | 🔧 Adaptar (avance de obra) |
|
|
| **social/** | Aulas, equipos, amistades, desafios | ~70 | 🔧 Adaptar (jerarquias) |
|
|
| **content/** | Plantillas, multimedia, Marie Curie | ~40 | 🔧 Adaptar (docs, plantillas) |
|
|
| **admin/** | Panel de administracion, bulk operations | ~30 | ⭐⭐⭐⭐⭐ MAXIMA |
|
|
| **teacher/** | Portal de profesor, grading, classrooms | ~30 | 🔧 Adaptar (supervisor) |
|
|
| **analytics/** | Analytics, reportes, metricas | ~20 | ⭐⭐⭐⭐⭐ MAXIMA |
|
|
| **notifications/** | Notificaciones multi-canal | ~10 | ⭐⭐⭐⭐⭐ MAXIMA |
|
|
| **system/** | Configuracion, feature flags, health | ~10 | ⭐⭐⭐⭐⭐ MAXIMA |
|
|
|
|
**Total endpoints:** 470+
|
|
|
|
---
|
|
|
|
## 3. PATRON DE MODULO TIPICO
|
|
|
|
Cada modulo en GAMILIT sigue un **patron consistente** que facilita navegacion y mantenimiento:
|
|
|
|
### 3.1 Estructura de un Modulo (ejemplo: auth/)
|
|
|
|
```
|
|
modules/auth/
|
|
├── entities/ # Entidades de base de datos
|
|
│ ├── user.entity.ts
|
|
│ ├── role.entity.ts
|
|
│ ├── session.entity.ts
|
|
│ └── tenant.entity.ts
|
|
│
|
|
├── dtos/ # Data Transfer Objects (validacion)
|
|
│ ├── login.dto.ts
|
|
│ ├── register.dto.ts
|
|
│ ├── update-profile.dto.ts
|
|
│ └── change-password.dto.ts
|
|
│
|
|
├── services/ # Logica de negocio
|
|
│ ├── auth.service.ts # Servicio principal
|
|
│ ├── user.service.ts # Servicios especializados
|
|
│ ├── session.service.ts
|
|
│ └── tenant.service.ts
|
|
│
|
|
├── controllers/ # Controllers Express (rutas)
|
|
│ ├── auth.controller.ts
|
|
│ └── user.controller.ts
|
|
│
|
|
├── routes/ # Definicion de rutas
|
|
│ ├── auth.routes.ts # Rutas de autenticacion
|
|
│ └── user.routes.ts # Rutas de usuarios
|
|
│
|
|
├── middleware/ # Middleware especifico del modulo
|
|
│ ├── auth.middleware.ts # Verificacion JWT
|
|
│ └── rate-limit.middleware.ts # Rate limiting
|
|
│
|
|
├── validators/ # Validadores personalizados
|
|
│ └── user.validator.ts
|
|
│
|
|
├── types/ # Tipos TypeScript del modulo
|
|
│ └── auth.types.ts
|
|
│
|
|
└── index.ts # Barrel export (Public API)
|
|
```
|
|
|
|
### 3.2 Capas del Modulo
|
|
|
|
**1. Entities (Entidades):**
|
|
- Representacion de tablas de base de datos
|
|
- Mapeo 1:1 con esquema PostgreSQL
|
|
- Tipos TypeScript para type safety
|
|
|
|
Ejemplo `user.entity.ts`:
|
|
```typescript
|
|
import { DB_SCHEMAS, DB_TABLES } from '@shared/constants';
|
|
|
|
export interface UserEntity {
|
|
id: string;
|
|
email: string;
|
|
password_hash: string;
|
|
tenant_id: string;
|
|
created_at: Date;
|
|
updated_at: Date;
|
|
}
|
|
|
|
export const USER_TABLE = `${DB_SCHEMAS.AUTH}.${DB_TABLES.AUTH.USERS}`;
|
|
```
|
|
|
|
**2. DTOs (Data Transfer Objects):**
|
|
- Validacion de datos de entrada
|
|
- Transformacion de datos
|
|
- Documentacion de contratos
|
|
|
|
Ejemplo `login.dto.ts`:
|
|
```typescript
|
|
export interface LoginDto {
|
|
email: string; // Validacion: email valido
|
|
password: string; // Validacion: minimo 8 caracteres
|
|
tenant_id?: string; // Opcional para multi-tenancy
|
|
}
|
|
|
|
export function validateLoginDto(data: unknown): LoginDto {
|
|
// Validacion con Zod, class-validator, etc.
|
|
// ...
|
|
return data as LoginDto;
|
|
}
|
|
```
|
|
|
|
**3. Services (Servicios):**
|
|
- Logica de negocio
|
|
- Interaccion con base de datos
|
|
- Orquestacion de operaciones
|
|
|
|
Ejemplo `auth.service.ts`:
|
|
```typescript
|
|
import { pool } from '@database/pool';
|
|
import { USER_TABLE } from './entities/user.entity';
|
|
import { DB_SCHEMAS } from '@shared/constants';
|
|
|
|
export class AuthService {
|
|
async login(dto: LoginDto): Promise<LoginResponse> {
|
|
// 1. Buscar usuario por email
|
|
const user = await this.findUserByEmail(dto.email);
|
|
|
|
// 2. Verificar password
|
|
const isValid = await bcrypt.compare(dto.password, user.password_hash);
|
|
if (!isValid) throw new UnauthorizedError();
|
|
|
|
// 3. Generar JWT
|
|
const token = jwt.sign({ userId: user.id }, JWT_SECRET);
|
|
|
|
// 4. Crear sesion
|
|
await this.createSession(user.id, token);
|
|
|
|
return { user, token };
|
|
}
|
|
|
|
private async findUserByEmail(email: string): Promise<UserEntity> {
|
|
const result = await pool.query(
|
|
`SELECT * FROM ${USER_TABLE} WHERE email = $1`,
|
|
[email]
|
|
);
|
|
return result.rows[0];
|
|
}
|
|
}
|
|
```
|
|
|
|
**4. Controllers (Controladores):**
|
|
- Manejo de requests HTTP
|
|
- Validacion de input
|
|
- Delegacion a servicios
|
|
- Manejo de responses
|
|
|
|
Ejemplo `auth.controller.ts`:
|
|
```typescript
|
|
import { Router } from 'express';
|
|
import { AuthService } from './services/auth.service';
|
|
import { API_ROUTES } from '@shared/constants';
|
|
|
|
const router = Router();
|
|
const authService = new AuthService();
|
|
|
|
// POST /api/v1/auth/login
|
|
router.post(API_ROUTES.AUTH.LOGIN, async (req, res, next) => {
|
|
try {
|
|
const dto = validateLoginDto(req.body);
|
|
const result = await authService.login(dto);
|
|
res.json(result);
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
export default router;
|
|
```
|
|
|
|
**5. Routes (Rutas):**
|
|
- Configuracion de rutas
|
|
- Aplicacion de middleware
|
|
- Documentacion de endpoints
|
|
|
|
**6. Middleware:**
|
|
- Autenticacion
|
|
- Autorizacion
|
|
- Validacion
|
|
- Rate limiting
|
|
|
|
**7. Validators:**
|
|
- Validaciones personalizadas
|
|
- Reglas de negocio
|
|
|
|
---
|
|
|
|
## 4. PATH ALIASES (IMPORTS LIMPIOS)
|
|
|
|
### 4.1 Configuracion en tsconfig.json
|
|
|
|
```json
|
|
{
|
|
"compilerOptions": {
|
|
"baseUrl": "./src",
|
|
"paths": {
|
|
"@/*": ["./*"],
|
|
"@shared/*": ["shared/*"],
|
|
"@middleware/*": ["middleware/*"],
|
|
"@config/*": ["config/*"],
|
|
"@database/*": ["database/*"],
|
|
"@modules/*": ["modules/*"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### 4.2 Comparacion de Imports
|
|
|
|
**❌ SIN PATH ALIASES (malo, fragil):**
|
|
```typescript
|
|
import { UserEntity } from '../../../modules/auth/entities/user.entity';
|
|
import { DB_SCHEMAS } from '../../../shared/constants/database.constants';
|
|
import { AuthService } from '../../../modules/auth/services/auth.service';
|
|
import { validateLoginDto } from '../../../modules/auth/dtos/login.dto';
|
|
```
|
|
|
|
**✅ CON PATH ALIASES (bueno, mantenible):**
|
|
```typescript
|
|
import { UserEntity } from '@modules/auth/entities/user.entity';
|
|
import { DB_SCHEMAS } from '@shared/constants/database.constants';
|
|
import { AuthService } from '@modules/auth/services/auth.service';
|
|
import { validateLoginDto } from '@modules/auth/dtos/login.dto';
|
|
```
|
|
|
|
### 4.3 Beneficios
|
|
|
|
1. **Legibilidad:** Imports semanticos y claros
|
|
2. **Mantenibilidad:** Facil refactoring de estructura
|
|
3. **Prevencion de errores:** No mas `../../../` incorrectos
|
|
4. **IDE Support:** Autocompletado mejorado
|
|
5. **Consistencia:** Mismo patron en todo el proyecto
|
|
|
|
### 4.4 Aplicabilidad a ERP Generico
|
|
|
|
⭐⭐⭐⭐⭐ (MAXIMA)
|
|
|
|
**Decision:** ✅ **ADOPTAR COMPLETAMENTE**
|
|
|
|
**Aliases propuestos para ERP:**
|
|
```json
|
|
{
|
|
"paths": {
|
|
"@/*": ["./*"],
|
|
"@shared/*": ["shared/*"],
|
|
"@middleware/*": ["middleware/*"],
|
|
"@config/*": ["config/*"],
|
|
"@database/*": ["database/*"],
|
|
"@modules/*": ["modules/*"],
|
|
"@shared/*": ["modules/core/*"],
|
|
"@accounting/*": ["modules/accounting/*"],
|
|
"@budgets/*": ["modules/budgets/*"],
|
|
"@purchasing/*": ["modules/purchasing/*"]
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5. MIDDLEWARE PATTERNS
|
|
|
|
### 5.1 Tipos de Middleware Implementados
|
|
|
|
**1. Authentication Middleware:**
|
|
```typescript
|
|
// middleware/auth.middleware.ts
|
|
import jwt from 'jsonwebtoken';
|
|
|
|
export const authenticate = async (req, res, next) => {
|
|
try {
|
|
const token = extractToken(req.headers.authorization);
|
|
const decoded = jwt.verify(token, JWT_SECRET);
|
|
|
|
// Establecer contexto del usuario
|
|
req.user = decoded;
|
|
req.userId = decoded.userId;
|
|
req.tenantId = decoded.tenantId;
|
|
|
|
next();
|
|
} catch (error) {
|
|
res.status(401).json({ error: 'Unauthorized' });
|
|
}
|
|
};
|
|
```
|
|
|
|
**2. Validation Middleware:**
|
|
```typescript
|
|
// middleware/validation.middleware.ts
|
|
export const validateDto = (schema) => {
|
|
return (req, res, next) => {
|
|
try {
|
|
req.body = schema.parse(req.body);
|
|
next();
|
|
} catch (error) {
|
|
res.status(400).json({ errors: error.errors });
|
|
}
|
|
};
|
|
};
|
|
|
|
// Uso:
|
|
router.post('/login', validateDto(loginSchema), authController.login);
|
|
```
|
|
|
|
**3. Error Middleware:**
|
|
```typescript
|
|
// middleware/error.middleware.ts
|
|
export const errorHandler = (err, req, res, next) => {
|
|
console.error(err);
|
|
|
|
// Errores conocidos
|
|
if (err instanceof UnauthorizedError) {
|
|
return res.status(401).json({ error: err.message });
|
|
}
|
|
|
|
if (err instanceof ValidationError) {
|
|
return res.status(400).json({ errors: err.errors });
|
|
}
|
|
|
|
// Error generico
|
|
res.status(500).json({ error: 'Internal server error' });
|
|
};
|
|
```
|
|
|
|
**4. Logging Middleware:**
|
|
```typescript
|
|
// middleware/logging.middleware.ts
|
|
export const requestLogger = (req, res, next) => {
|
|
const start = Date.now();
|
|
|
|
res.on('finish', () => {
|
|
const duration = Date.now() - start;
|
|
console.log(`${req.method} ${req.url} ${res.statusCode} - ${duration}ms`);
|
|
});
|
|
|
|
next();
|
|
};
|
|
```
|
|
|
|
### 5.2 Aplicabilidad a ERP Generico
|
|
|
|
⭐⭐⭐⭐⭐ (MAXIMA)
|
|
|
|
**Decision:** ✅ **ADOPTAR COMPLETAMENTE**
|
|
|
|
**Middleware criticos para ERP:**
|
|
- Authentication (JWT con multi-tenancy)
|
|
- Authorization (permisos por rol)
|
|
- Validation (DTOs con Zod)
|
|
- Error handling (global)
|
|
- Logging (auditoria de requests)
|
|
- Rate limiting (proteccion DDoS)
|
|
|
|
---
|
|
|
|
## 6. ERROR HANDLING
|
|
|
|
### 6.1 Jerarquia de Errores Personalizados
|
|
|
|
```typescript
|
|
// shared/errors/base.error.ts
|
|
export class AppError extends Error {
|
|
constructor(
|
|
public statusCode: number,
|
|
public message: string,
|
|
public isOperational = true
|
|
) {
|
|
super(message);
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
|
|
// Errores especificos
|
|
export class UnauthorizedError extends AppError {
|
|
constructor(message = 'Unauthorized') {
|
|
super(401, message);
|
|
}
|
|
}
|
|
|
|
export class NotFoundError extends AppError {
|
|
constructor(resource: string) {
|
|
super(404, `${resource} not found`);
|
|
}
|
|
}
|
|
|
|
export class ValidationError extends AppError {
|
|
constructor(public errors: any[]) {
|
|
super(400, 'Validation failed');
|
|
}
|
|
}
|
|
|
|
export class ForbiddenError extends AppError {
|
|
constructor(message = 'Forbidden') {
|
|
super(403, message);
|
|
}
|
|
}
|
|
|
|
export class ConflictError extends AppError {
|
|
constructor(message: string) {
|
|
super(409, message);
|
|
}
|
|
}
|
|
```
|
|
|
|
### 6.2 Uso en Servicios
|
|
|
|
```typescript
|
|
// modules/auth/services/auth.service.ts
|
|
export class AuthService {
|
|
async findUserById(id: string): Promise<UserEntity> {
|
|
const user = await this.userRepository.findById(id);
|
|
|
|
if (!user) {
|
|
throw new NotFoundError('User');
|
|
}
|
|
|
|
return user;
|
|
}
|
|
|
|
async updateUser(id: string, dto: UpdateUserDto): Promise<UserEntity> {
|
|
// Verificar si email ya existe
|
|
const existing = await this.userRepository.findByEmail(dto.email);
|
|
if (existing && existing.id !== id) {
|
|
throw new ConflictError('Email already in use');
|
|
}
|
|
|
|
return await this.userRepository.update(id, dto);
|
|
}
|
|
}
|
|
```
|
|
|
|
### 6.3 Aplicabilidad a ERP Generico
|
|
|
|
⭐⭐⭐⭐⭐ (MAXIMA)
|
|
|
|
**Decision:** ✅ **ADOPTAR COMPLETAMENTE**
|
|
|
|
---
|
|
|
|
## 7. DATABASE PATTERNS
|
|
|
|
### 7.1 Connection Pool (Singleton)
|
|
|
|
```typescript
|
|
// database/pool.ts
|
|
import { Pool } from 'pg';
|
|
import { DB_CONFIG } from '@config/database.config';
|
|
|
|
let pool: Pool | null = null;
|
|
|
|
export function getPool(): Pool {
|
|
if (!pool) {
|
|
pool = new Pool({
|
|
host: DB_CONFIG.host,
|
|
port: DB_CONFIG.port,
|
|
database: DB_CONFIG.database,
|
|
user: DB_CONFIG.user,
|
|
password: DB_CONFIG.password,
|
|
max: 20, // Maximo 20 conexiones
|
|
idleTimeoutMillis: 30000,
|
|
connectionTimeoutMillis: 2000,
|
|
});
|
|
}
|
|
|
|
return pool;
|
|
}
|
|
|
|
export const pool = getPool();
|
|
```
|
|
|
|
### 7.2 Uso de Constants para Queries
|
|
|
|
```typescript
|
|
import { pool } from '@database/pool';
|
|
import { DB_SCHEMAS, DB_TABLES, getFullTableName } from '@shared/constants';
|
|
|
|
export class UserRepository {
|
|
private readonly TABLE = getFullTableName(
|
|
DB_SCHEMAS.AUTH,
|
|
DB_TABLES.AUTH.USERS
|
|
);
|
|
|
|
async findById(id: string): Promise<UserEntity | null> {
|
|
const result = await pool.query(
|
|
`SELECT * FROM ${this.TABLE} WHERE id = $1`,
|
|
[id]
|
|
);
|
|
return result.rows[0] || null;
|
|
}
|
|
|
|
async create(user: CreateUserDto): Promise<UserEntity> {
|
|
const result = await pool.query(
|
|
`INSERT INTO ${this.TABLE} (email, password_hash, tenant_id)
|
|
VALUES ($1, $2, $3)
|
|
RETURNING *`,
|
|
[user.email, user.passwordHash, user.tenantId]
|
|
);
|
|
return result.rows[0];
|
|
}
|
|
}
|
|
```
|
|
|
|
### 7.3 Transacciones
|
|
|
|
```typescript
|
|
export class OrderService {
|
|
async createOrderWithItems(dto: CreateOrderDto): Promise<Order> {
|
|
const client = await pool.connect();
|
|
|
|
try {
|
|
await client.query('BEGIN');
|
|
|
|
// 1. Crear orden
|
|
const order = await this.createOrder(client, dto);
|
|
|
|
// 2. Crear items
|
|
await this.createOrderItems(client, order.id, dto.items);
|
|
|
|
// 3. Actualizar inventario
|
|
await this.updateInventory(client, dto.items);
|
|
|
|
await client.query('COMMIT');
|
|
return order;
|
|
} catch (error) {
|
|
await client.query('ROLLBACK');
|
|
throw error;
|
|
} finally {
|
|
client.release();
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### 7.4 Critica: Sin ORM
|
|
|
|
**Observacion:** GAMILIT usa `node-postgres` (pg) directamente, sin ORM.
|
|
|
|
**Ventajas:**
|
|
- ✅ Control total sobre queries
|
|
- ✅ Performance optimo
|
|
- ✅ Queries SQL explicitas
|
|
|
|
**Desventajas:**
|
|
- ❌ Sin type safety en queries
|
|
- ❌ Mapeo manual de resultados
|
|
- ❌ Migrations manuales
|
|
- ❌ Propenso a SQL injection si no se usan placeholders
|
|
|
|
**Recomendacion para ERP Generico:**
|
|
|
|
⭐⭐⭐⭐ (ALTA)
|
|
|
|
**Decision:** 🔧 **CONSIDERAR TypeORM o Prisma**
|
|
|
|
**Justificacion:**
|
|
- Type safety completo
|
|
- Migrations automaticas
|
|
- Query builder type-safe
|
|
- Reduccion de codigo boilerplate
|
|
|
|
---
|
|
|
|
## 8. TESTING PATTERNS
|
|
|
|
### 8.1 Metricas de Testing (GAP CRITICO)
|
|
|
|
| Metrica | Actual | Objetivo | Gap |
|
|
|---------|--------|----------|-----|
|
|
| **Tests Backend** | 40 | 210 | **-170 (81%)** |
|
|
| **Coverage** | 15% | 70% | **-55pp** |
|
|
|
|
**Critica:** Coverage extremadamente bajo. NO copiar este anti-patron.
|
|
|
|
### 8.2 Ejemplos de Tests (los pocos que existen)
|
|
|
|
**Test de Servicio:**
|
|
```typescript
|
|
// modules/auth/__tests__/auth.service.test.ts
|
|
describe('AuthService', () => {
|
|
let authService: AuthService;
|
|
|
|
beforeEach(() => {
|
|
authService = new AuthService();
|
|
});
|
|
|
|
describe('login', () => {
|
|
it('should return token for valid credentials', async () => {
|
|
const dto = { email: 'test@example.com', password: 'password123' };
|
|
const result = await authService.login(dto);
|
|
|
|
expect(result).toHaveProperty('token');
|
|
expect(result).toHaveProperty('user');
|
|
});
|
|
|
|
it('should throw UnauthorizedError for invalid password', async () => {
|
|
const dto = { email: 'test@example.com', password: 'wrong' };
|
|
|
|
await expect(authService.login(dto)).rejects.toThrow(UnauthorizedError);
|
|
});
|
|
});
|
|
});
|
|
```
|
|
|
|
### 8.3 Recomendacion para ERP Generico
|
|
|
|
⭐⭐⭐⭐⭐ (MAXIMA - CRITICO)
|
|
|
|
**Decision:** ✅ **IMPLEMENTAR TESTING DESDE EL INICIO**
|
|
|
|
**Objetivos:**
|
|
- **Coverage:** 70%+ desde el inicio
|
|
- **TDD:** Test-Driven Development
|
|
- **Tests por capa:** Unit, Integration, E2E
|
|
- **CI/CD:** Tests automaticos en pipeline
|
|
|
|
**Herramientas:**
|
|
- **Jest** para unit tests
|
|
- **Supertest** para integration tests
|
|
- **Test containers** para tests con DB
|
|
|
|
---
|
|
|
|
## 9. MATRIZ DE DECISION: ADOPTAR / ADAPTAR / EVITAR
|
|
|
|
### 9.1 ADOPTAR COMPLETAMENTE ✅
|
|
|
|
| Patron | Descripcion | Justificacion | Prioridad |
|
|
|--------|-------------|---------------|-----------|
|
|
| **Estructura modular** | 11 modulos funcionales independientes | Organizacion clara, escalable | P0 |
|
|
| **Patron de modulo** | entities, dtos, services, controllers, routes | Consistencia en toda la aplicacion | P0 |
|
|
| **Path aliases** | @shared, @modules, @config, etc. | Imports limpios y mantenibles | P0 |
|
|
| **Middleware patterns** | auth, validation, error, logging | Separacion de responsabilidades | P0 |
|
|
| **Error handling** | Jerarquia de errores personalizados | Manejo consistente de errores | P0 |
|
|
| **Connection pool** | Singleton pool de conexiones PostgreSQL | Performance y gestion de conexiones | P0 |
|
|
| **Constants SSOT** | Backend como fuente de verdad | Eliminacion de hardcoding | P0 |
|
|
|
|
### 9.2 ADAPTAR / MEJORAR 🔧
|
|
|
|
| Patron | Estado Actual | Mejora Propuesta | Prioridad |
|
|
|--------|---------------|------------------|-----------|
|
|
| **Database access** | node-postgres directo | TypeORM o Prisma (type safety) | P1 |
|
|
| **Testing** | 15% coverage, 40 tests | 70%+ coverage, TDD | P0 CRITICO |
|
|
| **Validation** | Validacion manual | Zod o class-validator | P1 |
|
|
| **Documentation** | Comentarios en codigo | OpenAPI/Swagger specs | P1 |
|
|
|
|
### 9.3 EVITAR ❌
|
|
|
|
| Patron | Razon | Alternativa |
|
|
|--------|-------|-------------|
|
|
| **Coverage bajo** | 15% es inaceptable | 70%+ coverage desde el inicio |
|
|
| **Sin ORM** | Propenso a errores, sin type safety | TypeORM o Prisma |
|
|
| **Validacion manual** | Inconsistente, propenso a errores | Zod o class-validator |
|
|
|
|
---
|
|
|
|
## 10. PROPUESTA DE MODULOS PARA ERP GENERICO
|
|
|
|
Basado en el analisis de GAMILIT, se propone:
|
|
|
|
```
|
|
backend/src/modules/
|
|
├── core/ # Sistema core
|
|
│ ├── companies/ # Empresas (multi-tenant)
|
|
│ ├── users/ # Usuarios del sistema
|
|
│ ├── roles/ # Roles RBAC
|
|
│ └── currencies/ # Monedas
|
|
│
|
|
├── accounting/ # Contabilidad
|
|
│ ├── accounts/ # Catalogo de cuentas
|
|
│ ├── entries/ # Asientos contables
|
|
│ └── reports/ # Reportes financieros
|
|
│
|
|
├── budgets/ # Presupuestos
|
|
│ ├── budgets/ # Presupuestos maestros
|
|
│ ├── items/ # Partidas presupuestarias
|
|
│ └── tracking/ # Seguimiento de ejecucion
|
|
│
|
|
├── purchasing/ # Compras
|
|
│ ├── suppliers/ # Proveedores
|
|
│ ├── orders/ # Ordenes de compra
|
|
│ └── invoices/ # Facturas
|
|
│
|
|
├── inventory/ # Inventario
|
|
│ ├── products/ # Productos/Materiales
|
|
│ ├── warehouses/ # Almacenes
|
|
│ └── movements/ # Movimientos
|
|
│
|
|
├── projects/ # Proyectos
|
|
│ ├── projects/ # Proyectos/Obras
|
|
│ ├── phases/ # Fases de proyecto
|
|
│ └── team/ # Equipo del proyecto
|
|
│
|
|
├── hr/ # RRHH
|
|
│ ├── employees/ # Empleados
|
|
│ ├── payrolls/ # Nominas
|
|
│ └── attendance/ # Asistencia
|
|
│
|
|
├── reports/ # Reportes y Analytics
|
|
│ ├── financial/ # Reportes financieros
|
|
│ ├── operational/ # Reportes operacionales
|
|
│ └── dashboards/ # Dashboards
|
|
│
|
|
├── notifications/ # Notificaciones
|
|
│ └── multi-channel/ # Multi-canal (email, SMS, push)
|
|
│
|
|
└── admin/ # Administracion
|
|
├── audit/ # Auditoria
|
|
├── settings/ # Configuracion
|
|
└── bulk-ops/ # Operaciones bulk
|
|
```
|
|
|
|
**Total modulos propuestos:** 10 modulos
|
|
|
|
---
|
|
|
|
## 11. CONCLUSION Y RECOMENDACIONES
|
|
|
|
### 11.1 Hallazgos Clave
|
|
|
|
1. **Estructura modular excelente:** ⭐⭐⭐⭐⭐
|
|
- 11 modulos bien organizados
|
|
- Patron consistente por modulo
|
|
- Facil navegacion y mantenimiento
|
|
|
|
2. **Path aliases son criticos:** ⭐⭐⭐⭐⭐
|
|
- Imports limpios y semanticos
|
|
- Facil refactoring
|
|
|
|
3. **Middleware patterns bien implementados:** ⭐⭐⭐⭐⭐
|
|
- Auth, validation, error, logging
|
|
- Separacion de responsabilidades
|
|
|
|
4. **Testing es GAP CRITICO:** ❌❌❌
|
|
- 15% coverage es inaceptable
|
|
- Solo 40 tests para 45,000 LOC
|
|
- NO copiar este anti-patron
|
|
|
|
### 11.2 Recomendaciones Finales
|
|
|
|
#### ADOPTAR COMPLETAMENTE ✅ (Prioridad P0)
|
|
|
|
1. Estructura modular (10 modulos para ERP)
|
|
2. Patron de modulo (entities, dtos, services, controllers)
|
|
3. Path aliases (@shared, @modules, @config)
|
|
4. Middleware patterns (auth, validation, error)
|
|
5. Error handling con jerarquia de errores
|
|
6. Connection pool singleton
|
|
7. Constants SSOT (Backend como fuente de verdad)
|
|
|
|
#### MEJORAR RESPECTO A GAMILIT 🔧 (Prioridad P0-P1)
|
|
|
|
1. **Testing:** 70%+ coverage desde el inicio (P0 CRITICO)
|
|
2. **ORM:** Usar TypeORM o Prisma (P1)
|
|
3. **Validation:** Zod o class-validator (P1)
|
|
4. **Documentation:** OpenAPI/Swagger (P1)
|
|
5. **DevOps:** Docker, CI/CD completo (P0)
|
|
|
|
#### EVITAR ❌
|
|
|
|
1. Coverage bajo (15%)
|
|
2. Sin ORM (propenso a errores)
|
|
3. Validacion manual inconsistente
|
|
|
|
---
|
|
|
|
**Documento creado:** 2025-11-23
|
|
**Ultima actualizacion:** 2025-11-23
|
|
**Version:** 1.0
|
|
**Estado:** Completado
|
|
**Proximo documento:** `frontend-patterns.md`
|