# 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('ExerciseRepository', { useClass: ExerciseRepository }); container.register('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