🎓 Initial commit: Math2 Platform - Plataforma de Álgebra Lineal PRO
✨ Características: - 45 ejercicios universitarios (Basic → Advanced) - Renderizado LaTeX profesional - IA generativa (Z.ai/DashScope) - Docker 9 servicios - Tests 123/123 pasando - Seguridad enterprise (JWT, XSS, Rate limiting) 🐳 Infraestructura: - Next.js 14 + Node.js 20 - PostgreSQL 15 + Redis 7 - Docker Compose completo - Nginx + SSL ready 📚 Documentación: - 5 informes técnicos completos - README profesional - Scripts de deployment automatizados Estado: Producción lista ✅
This commit is contained in:
511
docs/ARCHITECTURE.md
Normal file
511
docs/ARCHITECTURE.md
Normal file
@@ -0,0 +1,511 @@
|
||||
# Arquitectura del Sistema
|
||||
|
||||
## Stack Tecnológico
|
||||
|
||||
### Frontend
|
||||
- **Framework**: Next.js 14 (App Router)
|
||||
- **Lenguaje**: TypeScript 5.4 (strict mode)
|
||||
- **Estilos**: Tailwind CSS 3.4 + shadcn/ui
|
||||
- **State Management**: Zustand 4.5
|
||||
- **HTTP Client**: Axios 1.6
|
||||
- **Validación**: Zod 3.22 + react-hook-form
|
||||
- **Testing**: Vitest 1.3 + React Testing Library 14
|
||||
- **Math Rendering**: KaTeX 0.16 + react-katex
|
||||
|
||||
### Backend
|
||||
- **Runtime**: Node.js 20 LTS
|
||||
- **Framework**: Express.js 4.18
|
||||
- **Lenguaje**: TypeScript 5.4
|
||||
- **ORM**: Prisma 5.11
|
||||
- **Database**: PostgreSQL 15
|
||||
- **Cache/Queue**: Redis 7
|
||||
- **Auth**: JWT (jsonwebtoken) + bcrypt
|
||||
- **Validation**: Zod 3.22
|
||||
- **Logging**: Winston 3.12 (JSON structured)
|
||||
- **Rate Limiting**: express-rate-limit + rate-limit-redis
|
||||
- **Security**: Helmet.js, CORS, DOMPurify
|
||||
- **Testing**: Vitest 1.3 + Supertest 6.3
|
||||
|
||||
### Infrastructure
|
||||
- **Container**: Docker 24 + Docker Compose
|
||||
- **Reverse Proxy**: Nginx 1.24
|
||||
- **Queue System**: Bull 4.12 + Redis
|
||||
- **AI Service**: MiniMax-M2.5 (Aliyun DashScope)
|
||||
- **Notifications**: Telegram Bot API
|
||||
- **PDF Processing**: pdf-parse + pdf2pic
|
||||
|
||||
## Patrones de Diseño
|
||||
|
||||
### 1. Repository Pattern
|
||||
|
||||
```
|
||||
Controller → Service → Repository → Database
|
||||
```
|
||||
|
||||
**Flujo de datos:**
|
||||
1. **Controller**: Maneja HTTP requests/responses, validación de entrada
|
||||
2. **Service**: Lógica de negocio, coordinación entre repositorios
|
||||
3. **Repository**: Acceso a datos, queries Prisma
|
||||
4. **Database**: PostgreSQL con Prisma ORM
|
||||
|
||||
**Ejemplo:**
|
||||
```typescript
|
||||
// ExerciseController.ts
|
||||
async getExercise(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
const exercise = await this.exerciseService.getById(id);
|
||||
res.json({ success: true, data: exercise });
|
||||
}
|
||||
|
||||
// ExerciseService.ts
|
||||
async getById(id: string) {
|
||||
const exercise = await this.exerciseRepository.findById(id);
|
||||
if (!exercise) throw new NotFoundError('Exercise not found');
|
||||
return exercise;
|
||||
}
|
||||
|
||||
// ExerciseRepository.ts
|
||||
async findById(id: string) {
|
||||
return prisma.exercise.findUnique({
|
||||
where: { id },
|
||||
include: { topic: true, module: true }
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Dependency Injection
|
||||
|
||||
Usando TSyringe para inversión de control:
|
||||
|
||||
```typescript
|
||||
// Container setup
|
||||
container.register<IExerciseRepository>('ExerciseRepository', {
|
||||
useClass: ExerciseRepository
|
||||
});
|
||||
|
||||
container.register<ExerciseService>('ExerciseService', {
|
||||
useClass: ExerciseService
|
||||
});
|
||||
|
||||
// Controller injection
|
||||
@injectable()
|
||||
class ExerciseController {
|
||||
constructor(
|
||||
@inject('ExerciseService') private service: ExerciseService
|
||||
) {}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Middleware Pipeline
|
||||
|
||||
```
|
||||
Request → Security → Auth → Validation → Rate Limit → Handler → Response
|
||||
```
|
||||
|
||||
**Orden de middlewares:**
|
||||
1. **Helmet** - Security headers
|
||||
2. **CORS** - Cross-origin handling
|
||||
3. **Compression** - gzip/deflate
|
||||
4. **Request ID** - Correlation ID injection
|
||||
5. **Logging** - Request/response logging
|
||||
6. **Auth** - JWT verification
|
||||
7. **Rate Limit** - Throttling
|
||||
8. **Validation** - Zod schema validation
|
||||
9. **Handler** - Route controller
|
||||
10. **Error Handler** - Centralized error handling
|
||||
|
||||
## Estructura de Módulos
|
||||
|
||||
### Backend Modules
|
||||
|
||||
```
|
||||
src/modules/
|
||||
├── auth/ # Autenticación y autorización
|
||||
│ ├── controllers/
|
||||
│ ├── services/
|
||||
│ ├── repositories/
|
||||
│ ├── middleware/
|
||||
│ └── types/
|
||||
├── exercise/ # Gestión de ejercicios
|
||||
│ ├── controllers/
|
||||
│ ├── services/
|
||||
│ ├── repositories/
|
||||
│ └── types/
|
||||
├── module/ # Módulos pedagógicos
|
||||
├── topic/ # Temas de estudio
|
||||
├── progress/ # Progreso del usuario
|
||||
├── ranking/ # Sistema de rankings
|
||||
├── achievement/ # Logros y gamificación
|
||||
├── pdf/ # Procesamiento de PDFs
|
||||
├── notification/ # Notificaciones (Telegram)
|
||||
└── ai/ # Integración con AI
|
||||
```
|
||||
|
||||
### Frontend Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── app/ # Next.js App Router
|
||||
│ ├── layout.tsx # Root layout
|
||||
│ ├── page.tsx # Home page
|
||||
│ ├── auth/ # Auth routes
|
||||
│ ├── dashboard/ # Dashboard routes
|
||||
│ ├── modules/ # Module routes
|
||||
│ ├── exercises/ # Exercise routes
|
||||
│ └── api/ # API routes
|
||||
├── components/
|
||||
│ ├── ui/ # shadcn/ui components
|
||||
│ ├── math/ # Math components (KaTeX)
|
||||
│ ├── auth/ # Auth components
|
||||
│ ├── exercises/ # Exercise components
|
||||
│ └── layout/ # Layout components
|
||||
├── lib/
|
||||
│ ├── api.ts # API client
|
||||
│ ├── utils.ts # Utilities
|
||||
│ ├── validators.ts # Zod schemas
|
||||
│ └── constants.ts # App constants
|
||||
├── store/
|
||||
│ ├── useAuthStore.ts # Auth state
|
||||
│ ├── useModuleStore.ts # Module state
|
||||
│ └── useExerciseStore.ts # Exercise state
|
||||
├── hooks/
|
||||
│ ├── useAuth.ts # Auth hook
|
||||
│ └── useProgress.ts # Progress hook
|
||||
└── types/
|
||||
└── index.ts # TypeScript definitions
|
||||
```
|
||||
|
||||
## Seguridad
|
||||
|
||||
### Autenticación
|
||||
|
||||
1. **Login Flow**:
|
||||
- Client envía credentials
|
||||
- Server valida con bcrypt
|
||||
- Genera access token (15 min) + refresh token (7 días)
|
||||
- Refresh tokens almacenados en Redis blacklist
|
||||
- JWT firmado con HS256 y secret seguro
|
||||
|
||||
2. **Token Refresh**:
|
||||
- Access token expira después de 15 minutos
|
||||
- Client usa refresh token para obtener nuevo access token
|
||||
- Refresh token rota en cada uso
|
||||
- Tokens antiguos agregados a blacklist
|
||||
|
||||
3. **Logout**:
|
||||
- Agrega refresh token a Redis blacklist
|
||||
- Client elimina tokens del storage
|
||||
- TTL en Redis coincide con expiración del token
|
||||
|
||||
### Autorización
|
||||
|
||||
1. **RBAC (Role-Based Access Control)**:
|
||||
- Roles: USER, TEACHER, ADMIN
|
||||
- Permisos definidos por rol
|
||||
- Middleware `requireAdmin` para rutas sensibles
|
||||
|
||||
2. **Resource Ownership**:
|
||||
- Verificación de ownership en recursos
|
||||
- Usuarios solo acceden a sus propios datos
|
||||
- Teachers pueden ver datos de sus estudiantes
|
||||
|
||||
### Protección Web
|
||||
|
||||
1. **XSS Protection**:
|
||||
- DOMPurify para sanitización de LaTeX
|
||||
- Helmet.js headers (CSP, X-Frame-Options)
|
||||
- Escape de output en templates
|
||||
|
||||
2. **CSRF Protection**:
|
||||
- Tokens CSRF en formularios
|
||||
- Validación de Origin header
|
||||
- SameSite cookies
|
||||
|
||||
3. **SQL Injection**:
|
||||
- Uso exclusivo de Prisma ORM
|
||||
- No queries raw sin validación
|
||||
- Prepared statements automáticos
|
||||
|
||||
4. **Input Validation**:
|
||||
- Zod schemas en todos los endpoints
|
||||
- Validación de tipo y formato
|
||||
- Sanitización de input
|
||||
|
||||
## Escalabilidad
|
||||
|
||||
### Horizontal Scaling
|
||||
|
||||
- **Docker Swarm / Kubernetes ready**
|
||||
- **Stateless backend design** - No session state en servidor
|
||||
- **Redis Cluster** para sessions y cache
|
||||
- **PostgreSQL Read Replicas** para queries de lectura
|
||||
|
||||
### Database Optimization
|
||||
|
||||
1. **Connection Pooling**:
|
||||
- PgBouncer para pooling de conexiones
|
||||
- Prisma connection limits configurados
|
||||
- Min/Max connections según carga
|
||||
|
||||
2. **Query Optimization**:
|
||||
- Índices en campos de búsqueda frecuente
|
||||
- Select fields específicos (no SELECT *)
|
||||
- Caching de queries frecuentes en Redis
|
||||
|
||||
3. **Read Replicas**:
|
||||
- Replicas para queries de lectura
|
||||
- Master para writes
|
||||
- Prisma read replica strategy
|
||||
|
||||
### Caching Strategy
|
||||
|
||||
1. **Redis Cache**:
|
||||
- Session storage (JWT blacklist)
|
||||
- Exercise data (TTL: 1 hora)
|
||||
- Progress data (TTL: 5 minutos)
|
||||
- Rankings (TTL: 1 minuto)
|
||||
|
||||
2. **CDN**:
|
||||
- Assets estáticos en CDN
|
||||
- KaTeX fonts y CSS
|
||||
- Imágenes y PDFs
|
||||
|
||||
## Workers y Queue System
|
||||
|
||||
### Bull Queue Configuration
|
||||
|
||||
```typescript
|
||||
const exerciseQueue = new Bull('exercise-generation', {
|
||||
redis: { host: REDIS_HOST, port: REDIS_PORT },
|
||||
defaultJobOptions: {
|
||||
attempts: 3,
|
||||
backoff: { type: 'exponential', delay: 2000 },
|
||||
removeOnComplete: 100,
|
||||
removeOnFail: 50
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Workers
|
||||
|
||||
1. **PDF Worker**:
|
||||
- Procesa PDFs de /app/pdfs
|
||||
- Extrae texto con pdf-parse
|
||||
- Genera imágenes con pdf2pic
|
||||
- Almacena metadata en ProcessedPdf
|
||||
|
||||
2. **Exercise Worker**:
|
||||
- Genera ejercicios con AI
|
||||
- Conecta a MiniMax-M2.5 API
|
||||
- Valida notación matemática
|
||||
- Guarda en database
|
||||
|
||||
3. **Notification Worker**:
|
||||
- Envía notificaciones Telegram
|
||||
- Procesa cola de notificaciones
|
||||
- Rate limiting para bot API
|
||||
|
||||
### Escalado de Workers
|
||||
|
||||
```bash
|
||||
# Escalar a 3 workers
|
||||
docker-compose up -d --scale exercise-worker=3
|
||||
|
||||
# Load balancing automático por Bull
|
||||
# Cada worker procesa jobs de la cola
|
||||
```
|
||||
|
||||
## Observabilidad
|
||||
|
||||
### Logging
|
||||
|
||||
**Winston Configuration**:
|
||||
```typescript
|
||||
const logger = winston.createLogger({
|
||||
level: process.env.LOG_LEVEL || 'info',
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp(),
|
||||
winston.format.json()
|
||||
),
|
||||
defaultMeta: {
|
||||
service: 'math-platform-api',
|
||||
version: process.env.npm_package_version
|
||||
},
|
||||
transports: [
|
||||
new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
|
||||
new winston.transports.File({ filename: 'logs/combined.log' })
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
**Correlation IDs**:
|
||||
- UUID generado en middleware
|
||||
- Propagado a todos los servicios
|
||||
- Incluido en logs y respuestas de error
|
||||
|
||||
### Health Checks
|
||||
|
||||
```typescript
|
||||
// Health check endpoint
|
||||
app.get('/health', async (req, res) => {
|
||||
const checks = {
|
||||
database: await checkDatabase(),
|
||||
redis: await checkRedis(),
|
||||
ai: await checkAIService()
|
||||
};
|
||||
|
||||
const healthy = Object.values(checks).every(c => c.status === 'up');
|
||||
|
||||
res.status(healthy ? 200 : 503).json({
|
||||
status: healthy ? 'healthy' : 'unhealthy',
|
||||
timestamp: new Date().toISOString(),
|
||||
version: process.env.npm_package_version,
|
||||
checks
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Docker Health Checks
|
||||
|
||||
```yaml
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3001/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
```
|
||||
|
||||
## Flujo de Datos
|
||||
|
||||
### Autenticación
|
||||
|
||||
```
|
||||
┌─────────┐ ┌──────────┐ ┌────────────┐ ┌──────────┐
|
||||
│ Client │────▶│ Nginx │────▶│ Backend │────▶│ PostgreSQL│
|
||||
└─────────┘ └──────────┘ └────────────┘ └──────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────┐
|
||||
│ Redis │
|
||||
│ Blacklist│
|
||||
└──────────┘
|
||||
```
|
||||
|
||||
### Ejercicio Attempt
|
||||
|
||||
```
|
||||
┌─────────┐ ┌──────────┐ ┌─────────────┐
|
||||
│ Client │────▶│ Backend │────▶│ Validation │
|
||||
└─────────┘ └──────────┘ └─────────────┘
|
||||
│
|
||||
┌─────────────────┼─────────────────┐
|
||||
▼ ▼ ▼
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
│ PostgreSQL│ │ Redis │ │ AI API │
|
||||
│ Score │ │ Progress │ │ Validate │
|
||||
└──────────┘ └──────────┘ └──────────┘
|
||||
```
|
||||
|
||||
### AI Exercise Generation
|
||||
|
||||
```
|
||||
┌─────────┐ ┌──────────┐ ┌───────────────┐
|
||||
│ Client │────▶│ Backend │────▶│ Bull Queue │
|
||||
└─────────┘ └──────────┘ └───────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ Exercise Worker │
|
||||
│ (MiniMax-M2.5 API) │
|
||||
└─────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ PostgreSQL │
|
||||
│ (Store Exercise) │
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
## Configuración de Entorno
|
||||
|
||||
### Variables de Entorno
|
||||
|
||||
```bash
|
||||
# Database
|
||||
DATABASE_URL="postgresql://user:pass@localhost:5432/mathdb"
|
||||
DB_PASSWORD="secure_password"
|
||||
|
||||
# Redis
|
||||
REDIS_HOST="redis"
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD="redis_password"
|
||||
|
||||
# JWT
|
||||
JWT_SECRET="your-super-secret-jwt-key-min-32-chars"
|
||||
JWT_EXPIRES_IN="15m"
|
||||
JWT_REFRESH_EXPIRES_IN="7d"
|
||||
|
||||
# AI
|
||||
AI_API_BASE_URL="https://api.example.com/v1"
|
||||
AI_API_KEY="your-ai-api-key"
|
||||
AI_MODEL="MiniMax-M2.5"
|
||||
|
||||
# Telegram
|
||||
TELEGRAM_BOT_TOKEN="your-bot-token"
|
||||
TELEGRAM_ADMIN_CHAT_ID="admin-chat-id"
|
||||
|
||||
# App
|
||||
NODE_ENV="production"
|
||||
PORT=3001
|
||||
LOG_LEVEL="info"
|
||||
```
|
||||
|
||||
### Perfiles de Entorno
|
||||
|
||||
1. **Development**:
|
||||
- Hot reload habilitado
|
||||
- Logging detallado
|
||||
- Prisma Studio disponible
|
||||
- Mock services
|
||||
|
||||
2. **Staging**:
|
||||
- Docker containers
|
||||
- SSL/TLS habilitado
|
||||
- CI/CD deployment
|
||||
- Test data
|
||||
|
||||
3. **Production**:
|
||||
- Multi-stage Docker builds
|
||||
- SSL/TLS con Let's Encrypt
|
||||
- Read replicas
|
||||
- CDN activo
|
||||
- Monitoring completo
|
||||
|
||||
## Convenciones de Código
|
||||
|
||||
### TypeScript
|
||||
|
||||
- ✅ Siempre tipos explícitos (no `any`)
|
||||
- ✅ Interfaces para objetos complejos
|
||||
- ✅ Enums para valores fijos
|
||||
- ✅ Never usar `console.log` (usar logger)
|
||||
- ✅ Strict mode enabled
|
||||
- ✅ Path aliases (`@/components`, `@/lib`)
|
||||
|
||||
### Nomenclatura
|
||||
|
||||
- **Components**: PascalCase (`ExerciseSolver.tsx`)
|
||||
- **Hooks**: camelCase con use (`useAuth.ts`)
|
||||
- **Utils**: camelCase (`formatDate.ts`)
|
||||
- **Constants**: UPPER_SNAKE_CASE
|
||||
- **Types/Interfaces**: PascalCase con sufijo Type (`UserType`)
|
||||
- **Enums**: PascalCase (`ExerciseDifficulty`)
|
||||
|
||||
### Testing
|
||||
|
||||
- Cada feature necesita tests
|
||||
- Cobertura mínima: 70%
|
||||
- E2E para flows críticos
|
||||
- Mock de servicios externos
|
||||
- Tests de integración para DB
|
||||
Reference in New Issue
Block a user