# API Documentation ## Base URL ``` Development: http://localhost:3001/api Production: https://api.mathplatform.com/api ``` ## Autenticación Todas las rutas (excepto auth) requieren header: ``` Authorization: Bearer {jwt_token} ``` ### Flujo de Autenticación 1. **Registro/Login**: Obtiene access token (15 min) + refresh token (7 días) 2. **API Calls**: Usa access token en header 3. **Refresh**: Cuando expira, usa refresh token para obtener nuevo access token 4. **Logout**: Invalida refresh token (agregado a blacklist en Redis) ## Endpoints ### Auth #### POST /auth/register Registra nuevo usuario. **Request:** ```json { "email": "user@example.com", "password": "SecurePass123!", "firstName": "John", "lastName": "Doe" } ``` **Response:** ```json { "success": true, "data": { "token": "eyJhbGciOiJIUzI1NiIs...", "refreshToken": "eyJhbGciOiJIUzI1NiIs...", "user": { "id": "550e8400-e29b-41d4-a716-446655440000", "email": "user@example.com", "firstName": "John", "lastName": "Doe", "role": "USER", "createdAt": "2024-03-30T12:00:00.000Z" } } } ``` #### POST /auth/login Autentica usuario existente. **Request:** ```json { "email": "user@example.com", "password": "SecurePass123!" } ``` **Response:** ```json { "success": true, "data": { "token": "eyJhbGciOiJIUzI1NiIs...", "refreshToken": "eyJhbGciOiJIUzI1NiIs...", "user": { "id": "550e8400-e29b-41d4-a716-446655440000", "email": "user@example.com", "firstName": "John", "lastName": "Doe", "role": "USER" } } } ``` #### POST /auth/refresh Renueva access token usando refresh token. **Request:** ```json { "refreshToken": "eyJhbGciOiJIUzI1NiIs..." } ``` **Response:** ```json { "success": true, "data": { "token": "eyJhbGciOiJIUzI1NiIs...", "refreshToken": "eyJhbGciOiJIUzI1NiIs..." } } ``` #### POST /auth/logout Invalida tokens (agrega refresh token a blacklist). **Headers:** ``` Authorization: Bearer {access_token} ``` **Request:** ```json { "refreshToken": "eyJhbGciOiJIUzI1NiIs..." } ``` **Response:** ```json { "success": true, "message": "Logout successful" } ``` #### GET /auth/me Obtiene perfil del usuario autenticado. **Response:** ```json { "success": true, "data": { "id": "550e8400-e29b-41d4-a716-446655440000", "email": "user@example.com", "firstName": "John", "lastName": "Doe", "role": "USER", "createdAt": "2024-03-30T12:00:00.000Z", "lastLoginAt": "2024-03-30T12:00:00.000Z" } } ``` ### Modules #### GET /modules Lista todos los módulos pedagógicos. **Response:** ```json { "success": true, "data": [ { "id": "mod-1", "name": "Fundamentos", "description": "Conceptos básicos de álgebra lineal", "type": "FUNDAMENTOS", "order": 1, "topicCount": 5, "exerciseCount": 25 }, { "id": "mod-2", "name": "Sistemas y Espacios", "description": "Sistemas de ecuaciones y espacios vectoriales", "type": "SISTEMAS_ESPACIOS", "order": 2, "topicCount": 4, "exerciseCount": 30 }, { "id": "mod-3", "name": "Aplicaciones", "description": "Aplicaciones prácticas de álgebra lineal", "type": "APLICACIONES", "order": 3, "topicCount": 3, "exerciseCount": 20 } ] } ``` #### GET /modules/:id Obtiene detalle de un módulo específico. **Response:** ```json { "success": true, "data": { "id": "mod-1", "name": "Fundamentos", "description": "Conceptos básicos de álgebra lineal", "type": "FUNDAMENTOS", "order": 1, "topics": [ { "id": "topic-1", "name": "Vectores", "description": "Operaciones con vectores", "order": 1 } ], "progress": { "completedExercises": 10, "totalExercises": 25, "percentage": 40 } } } ``` ### Topics #### GET /topics Lista todos los temas. **Query Parameters:** - `moduleId` (optional): Filtrar por módulo **Response:** ```json { "success": true, "data": [ { "id": "topic-1", "name": "Vectores", "description": "Operaciones con vectores", "moduleId": "mod-1", "type": "VECTORES", "order": 1, "exerciseCount": 8 } ] } ``` #### GET /topics/:id/theory Obtiene contenido teórico de un tema. **Response:** ```json { "success": true, "data": { "id": "topic-1", "name": "Vectores", "content": { "introduction": "Los vectores son...", "formulas": [ { "name": "Magnitud", "latex": "\\|\\vec{v}\\| = \\sqrt{x^2 + y^2}" } ], "examples": [ { "problem": "Calcular la magnitud del vector...", "solution": "Usando la fórmula...", "latex": "\\vec{v} = (3, 4)" } ] } } } ``` ### Exercises #### GET /exercises Lista ejercicios con filtros. **Query Parameters:** - `moduleId` (optional): Filtrar por módulo - `topicId` (optional): Filtrar por tema - `difficulty` (optional): BASIC | INTERMEDIATE | ADVANCED | EXPERT - `type` (optional): MULTIPLE_CHOICE | OPEN_RESPONSE | CALCULATION | PROOF | TRUE_FALSE - `limit` (optional): Número de resultados (default: 20) - `offset` (optional): Paginación (default: 0) **Response:** ```json { "success": true, "data": { "exercises": [ { "id": "ex-1", "title": "Suma de vectores", "description": "Calcular la suma de dos vectores", "type": "CALCULATION", "difficulty": "BASIC", "topicId": "topic-1", "latex": "\\vec{a} = (1, 2), \\vec{b} = (3, 4)", "points": 10, "hints": ["Recuerda sumar componente a componente"], "createdAt": "2024-03-30T12:00:00.000Z" } ], "pagination": { "total": 100, "limit": 20, "offset": 0, "hasMore": true } } } ``` #### GET /exercises/:id Obtiene detalle de un ejercicio. **Response:** ```json { "success": true, "data": { "id": "ex-1", "title": "Suma de vectores", "description": "Calcular la suma de dos vectores", "type": "CALCULATION", "difficulty": "BASIC", "topic": { "id": "topic-1", "name": "Vectores" }, "module": { "id": "mod-1", "name": "Fundamentos" }, "latex": "\\vec{a} = (1, 2), \\vec{b} = (3, 4)", "questions": [ { "id": "q-1", "text": "¿Cuál es la suma de los vectores?", "options": [ "(4, 6)", "(3, 4)", "(1, 2)", "(5, 8)" ] } ], "points": 10, "hints": ["Suma las componentes x", "Suma las componentes y"], "timeEstimate": 300 } } ``` #### POST /exercises/:id/attempt Envía respuesta a ejercicio. **Request:** ```json { "answer": "(4, 6)", "timeSpent": 120, "showHints": true } ``` **Response:** ```json { "success": true, "data": { "attemptId": "att-123", "isCorrect": true, "score": 10, "feedback": "¡Correcto! La suma de vectores se realiza componente a componente.", "solution": { "steps": [ "\\vec{a} + \\vec{b} = (1+3, 2+4)", "= (4, 6)" ], "latex": "\\vec{a} + \\vec{b} = (4, 6)" }, "progress": { "moduleCompleted": false, "newAchievements": ["first-step"] } } } ``` ### Progress #### GET /progress Obtiene progreso general del usuario. **Response:** ```json { "success": true, "data": { "overall": { "totalExercises": 75, "completedExercises": 25, "percentage": 33.3, "totalScore": 250, "averageScore": 10 }, "modules": [ { "moduleId": "mod-1", "moduleName": "Fundamentos", "completedExercises": 15, "totalExercises": 25, "percentage": 60, "score": 150 } ], "streak": { "current": 5, "longest": 12, "lastActivity": "2024-03-30T10:00:00.000Z" } } } ``` #### GET /progress/module/:moduleId Obtiene progreso de un módulo específico. **Response:** ```json { "success": true, "data": { "moduleId": "mod-1", "moduleName": "Fundamentos", "completedExercises": 15, "totalExercises": 25, "percentage": 60, "score": 150, "topics": [ { "topicId": "topic-1", "topicName": "Vectores", "completedExercises": 5, "totalExercises": 8, "percentage": 62.5 } ], "recentAttempts": [ { "exerciseId": "ex-1", "exerciseTitle": "Suma de vectores", "isCorrect": true, "score": 10, "attemptedAt": "2024-03-30T10:00:00.000Z" } ] } } ``` ### Ranking #### GET /ranking/global Obtiene ranking global. **Query Parameters:** - `limit` (optional): Resultados por página (default: 50) - `offset` (optional): Paginación (default: 0) **Response:** ```json { "success": true, "data": { "rankings": [ { "position": 1, "user": { "id": "user-1", "firstName": "Alice", "lastName": "Smith" }, "score": 1250, "completedExercises": 75, "accuracy": 92.5 } ], "pagination": { "total": 150, "limit": 50, "offset": 0, "hasMore": true } } } ``` #### GET /ranking/my-position Obtiene posición del usuario actual. **Response:** ```json { "success": true, "data": { "globalPosition": 25, "score": 450, "completedExercises": 35, "accuracy": 85.2, "modulePositions": [ { "moduleId": "mod-1", "moduleName": "Fundamentos", "position": 15, "score": 200 } ] } } ``` ### Achievements #### GET /achievements Lista todos los logros disponibles. **Response:** ```json { "success": true, "data": { "achievements": [ { "id": "ach-1", "name": "Primer Paso", "description": "Completa tu primer ejercicio", "category": "EXERCISES", "rarity": "COMMON", "icon": "🎯", "requirement": { "type": "EXERCISE_COUNT", "value": 1 } } ] } } ``` #### GET /achievements/my Obtiene logros desbloqueados del usuario. **Response:** ```json { "success": true, "data": { "unlocked": [ { "id": "ach-1", "name": "Primer Paso", "description": "Completa tu primer ejercicio", "category": "EXERCISES", "rarity": "COMMON", "icon": "🎯", "unlockedAt": "2024-03-30T12:00:00.000Z" } ], "progress": [ { "achievementId": "ach-2", "name": "En Marcha", "progress": 5, "required": 10, "percentage": 50 } ] } } ``` ### AI Generation #### POST /ai/generate-exercise Genera ejercicio usando AI. **Request:** ```json { "topicId": "topic-1", "difficulty": "INTERMEDIATE", "type": "CALCULATION", "context": "Vectores en 3D" } ``` **Response:** ```json { "success": true, "data": { "exercise": { "title": "Producto cruz en 3D", "description": "Calcular el producto cruz de dos vectores en 3D", "latex": "\\vec{a} = (1, 2, 3), \\vec{b} = (4, 5, 6)", "solution": { "steps": [ "\\vec{a} \\times \\vec{b} = (2\\cdot6 - 3\\cdot5, 3\\cdot4 - 1\\cdot6, 1\\cdot5 - 2\\cdot4)", "= (12-15, 12-6, 5-8)", "= (-3, 6, -3)" ], "latex": "\\vec{a} \\times \\vec{b} = (-3, 6, -3)" }, "difficulty": "INTERMEDIATE", "points": 15 } } } ``` #### POST /ai/validate-answer Valida respuesta usando AI. **Request:** ```json { "exerciseId": "ex-1", "userAnswer": "(4, 6)", "context": "Suma de vectores 2D" } ``` **Response:** ```json { "success": true, "data": { "isCorrect": true, "confidence": 0.95, "feedback": "Respuesta correcta. La suma de vectores (1,2) + (3,4) = (4,6)", "explanation": "Se sumaron correctamente las componentes x (1+3=4) y y (2+4=6)" } } ``` ## Códigos de Error | Código | HTTP | Descripción | |--------|------|-------------| | `BAD_REQUEST` | 400 | Datos inválidos o faltantes | | `UNAUTHORIZED` | 401 | Token inválido o expirado | | `FORBIDDEN` | 403 | Sin permisos para el recurso | | `NOT_FOUND` | 404 | Recurso no existe | | `VALIDATION_ERROR` | 422 | Error de validación de datos | | `RATE_LIMIT` | 429 | Rate limit excedido | | `INTERNAL_ERROR` | 500 | Error interno del servidor | | `SERVICE_UNAVAILABLE` | 503 | Servicio temporalmente no disponible | ### Formato de Error ```json { "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Datos de entrada inválidos", "details": { "field": "email", "issue": "Email inválido" } }, "meta": { "timestamp": "2024-03-30T12:00:00.000Z", "requestId": "req_abc123" } } ``` ## Rate Limiting - **Auth endpoints**: 5 requests / 15 min / IP - **API general**: 100 requests / 15 min / user - **AI generation**: 10 requests / hour / user - **Exercise attempts**: Sin limitación Headers de respuesta: ``` X-RateLimit-Limit: 100 X-RateLimit-Remaining: 95 X-RateLimit-Reset: 1711802400 ``` ## Versionado La API usa versionado en URL: - `/api/v1/...` - Versión actual - `/api/...` - Alias a v1 (default) ## Webhooks (Admin) ### POST /webhooks/telegram Endpoint para recibir actualizaciones de Telegram. ### POST /webhooks/pdf-processed Notificación cuando un PDF es procesado. ## Health Check ### GET /health Verifica estado del servicio. **Response:** ```json { "status": "healthy", "timestamp": "2024-03-30T12:00:00.000Z", "version": "1.0.0", "services": { "database": "connected", "redis": "connected", "ai": "available" } } ``` ## Paginación Todas las listas soportan paginación con: - `limit`: Número de items (max: 100) - `offset`: Índice inicial (0-based) - `cursor`: Para paginación basada en cursor (alternativa) Formato de respuesta paginada: ```json { "data": [...], "pagination": { "total": 150, "limit": 20, "offset": 0, "hasMore": true, "nextCursor": "eyJpZCI6..." } } ```