# Portal Teacher - API Reference

**Fecha de creacion:** 2025-11-29
**Version:** 1.0.0
**Estado:** VIGENTE
**Complementa:** PORTAL-TEACHER-GUIDE.md

---

## 1. Resumen de Endpoints

El Portal Teacher expone **45+ endpoints** organizados en 7 controladores:

| Controller | Base Path | Endpoints | Descripcion |
|------------|-----------|-----------|-------------|
| TeacherController | `/teacher` | 20 | Dashboard, progress, analytics, grading |
| TeacherClassroomsController | `/teacher/classrooms` | 12 | CRUD de aulas, estudiantes |
| InterventionAlertsController | `/teacher/alerts` | 5 | Alertas de intervencion |
| TeacherCommunicationController | `/teacher/messages` | 6 | Mensajes y comunicacion |
| TeacherContentController | `/teacher/content` | 5 | Contenido personalizado |
| ExerciseResponsesController | `/teacher/exercise-responses` | 4 | Respuestas de ejercicios |
| TeacherGradesController | `/teacher/grades` | 3 | Calificaciones |

---

## 2. Dashboard APIs

### 2.1 GET /teacher/dashboard/stats

Obtiene estadisticas generales del dashboard del teacher.

**Request:**
```http
GET /api/teacher/dashboard/stats
Authorization: Bearer {token}
```

**Response (200):**
```json
{
  "total_classrooms": 5,
  "total_students": 127,
  "active_students": 98,
  "pending_submissions": 23,
  "average_completion": 72.5,
  "average_score": 85.3,
  "alerts_count": 4,
  "recent_activity_count": 15
}
```

**Frontend Hook:**
```typescript
// hooks/useTeacherDashboard.ts
export function useTeacherDashboard() {
  const { data: stats } = useQuery({
    queryKey: ['teacher', 'dashboard', 'stats'],
    queryFn: () => teacherApi.getDashboardStats(),
    staleTime: 60_000, // 1 minuto
  });

  return { stats };
}
```

### 2.2 GET /teacher/dashboard/activities

Obtiene actividades recientes.

**Request:**
```http
GET /api/teacher/dashboard/activities?limit=10
Authorization: Bearer {token}
```

**Response (200):**
```json
{
  "activities": [
    {
      "id": "uuid",
      "type": "submission",
      "student_id": "uuid",
      "student_name": "Juan Perez",
      "action": "submitted_exercise",
      "exercise_name": "Timeline - Marie Curie",
      "classroom_name": "5to A - Matematicas",
      "timestamp": "2025-11-29T10:30:00Z"
    }
  ]
}
```

### 2.3 GET /teacher/dashboard/alerts

Obtiene alertas de estudiantes en riesgo.

**Response (200):**
```json
{
  "alerts": [
    {
      "id": "uuid",
      "student_id": "uuid",
      "student_name": "Maria Garcia",
      "type": "declining_trend",
      "severity": "high",
      "message": "Desempeno en declive en ultimas 2 semanas",
      "classroom_name": "5to A",
      "created_at": "2025-11-28T15:00:00Z"
    }
  ]
}
```

### 2.4 GET /teacher/dashboard/top-performers

Obtiene top estudiantes por desempeno.

**Request:**
```http
GET /api/teacher/dashboard/top-performers?limit=5
```

**Response (200):**
```json
{
  "students": [
    {
      "id": "uuid",
      "name": "Ana Lopez",
      "avatar_url": "https://...",
      "classroom_name": "5to A",
      "total_xp": 15000,
      "maya_rank": "Arquitecto Maya",
      "completion_rate": 95.5,
      "average_score": 92.3
    }
  ]
}
```

---

## 3. Classrooms APIs

### 3.1 GET /teacher/classrooms

Lista todas las aulas del teacher.

**Request:**
```http
GET /api/teacher/classrooms?page=1&limit=10&status=active&search=matematicas
```

**Query Parameters:**
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| page | number | No | Pagina (default: 1) |
| limit | number | No | Items por pagina (default: 10) |
| search | string | No | Buscar por nombre |
| status | string | No | active, inactive, archived, all |
| grade_level | string | No | Filtrar por nivel |
| subject | string | No | Filtrar por materia |

**Response (200):**
```json
{
  "data": [
    {
      "id": "uuid",
      "name": "5to A - Matematicas",
      "code": "5A-MAT-2025",
      "grade_level": "5to",
      "subject": "Matematicas",
      "student_count": 28,
      "active_students": 25,
      "average_progress": 72.5,
      "status": "active",
      "is_owner": true,
      "created_at": "2025-01-15T10:00:00Z"
    }
  ],
  "total": 5,
  "page": 1,
  "limit": 10,
  "total_pages": 1
}
```

**Frontend Hook:**
```typescript
// hooks/useClassrooms.ts
export function useClassrooms(filters?: GetClassroomsQueryDto) {
  const query = useQuery({
    queryKey: ['teacher', 'classrooms', filters],
    queryFn: () => classroomsApi.getAll(filters),
  });

  const createMutation = useMutation({
    mutationFn: classroomsApi.create,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['teacher', 'classrooms'] });
    },
  });

  return {
    classrooms: query.data?.data ?? [],
    isLoading: query.isLoading,
    createClassroom: createMutation.mutate,
    isCreating: createMutation.isPending,
  };
}
```

### 3.2 POST /teacher/classrooms

Crea una nueva aula.

**Request:**
```http
POST /api/teacher/classrooms
Content-Type: application/json
Authorization: Bearer {token}

{
  "name": "6to B - Ciencias",
  "grade_level": "6to",
  "subject": "Ciencias",
  "description": "Clase de ciencias naturales",
  "max_students": 35,
  "settings": {
    "allow_late_submissions": true,
    "auto_grade_enabled": false
  }
}
```

**Response (201):**
```json
{
  "id": "uuid",
  "name": "6to B - Ciencias",
  "code": "6B-CIE-2025-ABC123",
  "grade_level": "6to",
  "subject": "Ciencias",
  "student_count": 0,
  "status": "active",
  "is_owner": true,
  "created_at": "2025-11-29T10:00:00Z"
}
```

### 3.3 GET /teacher/classrooms/:id/students

Obtiene estudiantes de un aula.

**Request:**
```http
GET /api/teacher/classrooms/uuid/students?page=1&limit=20&sort_by=progress&sort_order=desc
```

**Response (200):**
```json
{
  "data": [
    {
      "id": "uuid",
      "user_id": "uuid",
      "name": "Juan Perez",
      "email": "juan@example.com",
      "avatar_url": "https://...",
      "status": "active",
      "enrolled_at": "2025-02-01T10:00:00Z",
      "progress": {
        "completion_percentage": 75.5,
        "average_score": 85.3,
        "total_xp": 12500,
        "maya_rank": "Constructor Maya",
        "exercises_completed": 45,
        "exercises_total": 60
      },
      "last_activity": "2025-11-28T15:30:00Z",
      "is_blocked": false
    }
  ],
  "total": 28,
  "page": 1,
  "limit": 20,
  "total_pages": 2
}
```

### 3.4 GET /teacher/classrooms/:id/progress

Obtiene progreso detallado del aula por modulo.

**Response (200):**
```json
{
  "classroomData": {
    "id": "uuid",
    "name": "5to A - Matematicas",
    "student_count": 28,
    "active_students": 25,
    "average_completion": 72.5,
    "average_score": 85.3,
    "total_exercises": 60,
    "completed_exercises": 45
  },
  "moduleProgress": [
    {
      "module_id": "uuid",
      "module_name": "Modulo 1: Marie Curie - Primera Exploracion",
      "module_order": 1,
      "completion_percentage": 85.5,
      "average_score": 88.3,
      "students_completed": 22,
      "students_in_progress": 4,
      "students_not_started": 2,
      "average_time_minutes": 120.5,
      "exercises": [
        {
          "exercise_id": "uuid",
          "exercise_name": "Timeline - Vida de Marie Curie",
          "mechanic_type": "timeline",
          "completion_rate": 92.0,
          "average_score": 87.5,
          "average_attempts": 1.3
        }
      ]
    }
  ]
}
```

---

## 4. Student Progress APIs

### 4.1 GET /teacher/students/:studentId/progress

Obtiene progreso completo de un estudiante.

**Request:**
```http
GET /api/teacher/students/uuid/progress?include_exercises=true&date_from=2025-01-01
```

**Response (200):**
```json
{
  "student": {
    "id": "uuid",
    "name": "Juan Perez",
    "email": "juan@example.com"
  },
  "summary": {
    "total_xp": 15000,
    "ml_coins_balance": 2500,
    "maya_rank": "Arquitecto Maya",
    "level": 12,
    "completion_percentage": 78.5,
    "average_score": 86.2,
    "total_time_minutes": 1250,
    "streak_days": 15
  },
  "modules": [
    {
      "module_id": "uuid",
      "module_name": "Modulo 1",
      "status": "completed",
      "completion_percentage": 100,
      "average_score": 92.5,
      "time_spent_minutes": 180,
      "completed_at": "2025-11-15T10:00:00Z"
    }
  ],
  "achievements": [
    {
      "id": "uuid",
      "name": "Primera Victoria",
      "description": "Completar primer ejercicio",
      "icon_url": "https://...",
      "unlocked_at": "2025-02-01T15:00:00Z"
    }
  ],
  "activity_timeline": [
    {
      "date": "2025-11-28",
      "exercises_completed": 3,
      "xp_earned": 450,
      "time_spent_minutes": 45
    }
  ]
}
```

### 4.2 GET /teacher/students/:studentId/insights

Obtiene insights AI del estudiante.

**Response (200):**
```json
{
  "student_id": "uuid",
  "generated_at": "2025-11-29T10:00:00Z",
  "risk_level": "low",
  "strengths": [
    "Excelente en ejercicios de comprension literal",
    "Alta consistencia en entregas",
    "Buen manejo del tiempo"
  ],
  "weaknesses": [
    "Dificultad en inferencias complejas",
    "Tendencia a respuestas apresuradas en critica"
  ],
  "predictions": {
    "completion_probability": 0.92,
    "estimated_completion_date": "2025-12-15",
    "risk_of_dropout": 0.05
  },
  "recommendations": [
    {
      "type": "exercise",
      "priority": "high",
      "message": "Recomendar mas ejercicios de inferencia",
      "suggested_exercises": ["uuid1", "uuid2"]
    },
    {
      "type": "intervention",
      "priority": "medium",
      "message": "Programar sesion de retroalimentacion"
    }
  ]
}
```

### 4.3 POST /teacher/students/:studentId/note

Agrega nota de teacher sobre estudiante.

**Request:**
```http
POST /api/teacher/students/uuid/note
Content-Type: application/json

{
  "classroom_id": "uuid",
  "content": "Estudiante muestra mejora notable en ultimas semanas",
  "is_private": true,
  "tags": ["mejora", "seguimiento"]
}
```

---

## 5. Grading APIs

### 5.1 GET /teacher/submissions

Obtiene submissions pendientes de calificar.

**Request:**
```http
GET /api/teacher/submissions?status=pending&classroom_id=uuid&page=1&limit=20
```

**Query Parameters:**
| Param | Type | Description |
|-------|------|-------------|
| status | string | pending, graded, all |
| classroom_id | string | Filtrar por aula |
| assignment_id | string | Filtrar por tarea |
| student_id | string | Filtrar por estudiante |
| module_id | string | Filtrar por modulo |
| date_from | string | Fecha desde (ISO) |
| date_to | string | Fecha hasta (ISO) |
| sort_by | string | submitted_at, score, student_name |
| sort_order | string | asc, desc |

**Response (200):**
```json
{
  "data": [
    {
      "id": "uuid",
      "student": {
        "id": "uuid",
        "name": "Juan Perez",
        "avatar_url": "https://..."
      },
      "exercise": {
        "id": "uuid",
        "name": "Timeline - Marie Curie",
        "mechanic_type": "timeline"
      },
      "classroom": {
        "id": "uuid",
        "name": "5to A"
      },
      "submitted_at": "2025-11-28T15:30:00Z",
      "auto_score": 85.5,
      "final_score": null,
      "status": "pending",
      "attempt_number": 1,
      "time_spent_seconds": 320,
      "answers": { /* respuestas del estudiante */ }
    }
  ],
  "total": 23,
  "page": 1,
  "limit": 20
}
```

### 5.2 POST /teacher/submissions/:id/feedback

Califica y proporciona feedback.

**Request:**
```http
POST /api/teacher/submissions/uuid/feedback
Content-Type: application/json

{
  "score": 90,
  "feedback": "Excelente trabajo en la organizacion cronologica",
  "strengths": ["Precision en fechas", "Conexiones logicas"],
  "areas_to_improve": ["Agregar mas contexto historico"],
  "xp_bonus": 50,
  "requires_revision": false
}
```

**Response (200):**
```json
{
  "id": "uuid",
  "status": "graded",
  "final_score": 90,
  "feedback": "Excelente trabajo...",
  "graded_at": "2025-11-29T10:30:00Z",
  "graded_by": "uuid",
  "xp_awarded": 150
}
```

### 5.3 POST /teacher/submissions/bulk-grade

Califica multiples submissions.

**Request:**
```http
POST /api/teacher/submissions/bulk-grade
Content-Type: application/json

{
  "submissions": [
    { "id": "uuid1", "score": 85, "feedback": "Buen trabajo" },
    { "id": "uuid2", "score": 92, "feedback": "Excelente" },
    { "id": "uuid3", "score": 78, "feedback": "Puede mejorar" }
  ],
  "apply_auto_xp": true
}
```

**Response (200):**
```json
{
  "processed": 3,
  "successful": 3,
  "failed": 0,
  "results": [
    { "id": "uuid1", "status": "success" },
    { "id": "uuid2", "status": "success" },
    { "id": "uuid3", "status": "success" }
  ]
}
```

---

## 6. Analytics APIs

### 6.1 GET /teacher/analytics/classroom/:id

Analiticas detalladas de un aula.

**Response (200):**
```json
{
  "classroom_id": "uuid",
  "period": {
    "from": "2025-01-01",
    "to": "2025-11-29"
  },
  "overview": {
    "total_students": 28,
    "active_students": 25,
    "average_completion": 72.5,
    "average_score": 85.3,
    "total_submissions": 1250,
    "total_time_hours": 450
  },
  "performance_distribution": {
    "excellent": 8,    // 90-100
    "good": 12,        // 80-89
    "average": 5,      // 70-79
    "below_average": 2, // 60-69
    "struggling": 1    // <60
  },
  "completion_trend": [
    { "week": "2025-W45", "completion_rate": 68.5 },
    { "week": "2025-W46", "completion_rate": 71.2 },
    { "week": "2025-W47", "completion_rate": 72.5 }
  ],
  "engagement_metrics": {
    "average_sessions_per_week": 3.5,
    "average_session_duration_minutes": 35,
    "peak_activity_hour": 16,
    "most_active_day": "Tuesday"
  },
  "at_risk_students": [
    {
      "student_id": "uuid",
      "name": "Maria Garcia",
      "risk_level": "high",
      "reason": "No activity in 7 days"
    }
  ]
}
```

### 6.2 GET /teacher/analytics/economy

Analiticas de economia ML Coins.

**Response (200):**
```json
{
  "overview": {
    "total_circulation": 125000,
    "average_balance": 980,
    "median_balance": 850,
    "gini_coefficient": 0.32
  },
  "distribution": {
    "ranges": [
      { "range": "0-500", "count": 15, "percentage": 12.0 },
      { "range": "501-1000", "count": 45, "percentage": 36.0 },
      { "range": "1001-2000", "count": 40, "percentage": 32.0 },
      { "range": "2001-5000", "count": 20, "percentage": 16.0 },
      { "range": "5001+", "count": 5, "percentage": 4.0 }
    ]
  },
  "top_earners": [
    {
      "student_id": "uuid",
      "name": "Ana Lopez",
      "balance": 8500,
      "weekly_earnings": 450,
      "maya_rank": "Arquitecto Maya"
    }
  ],
  "spending_patterns": {
    "comodines": 35000,
    "customizations": 15000,
    "power_ups": 8000
  }
}
```

### 6.3 GET /teacher/analytics/achievements

Estadisticas de logros por aula.

**Response (200):**
```json
{
  "classroom_id": "uuid",
  "total_achievements": 45,
  "total_unlocks": 892,
  "achievements": [
    {
      "id": "uuid",
      "name": "Primera Victoria",
      "description": "Completar primer ejercicio",
      "category": "progress",
      "unlock_count": 28,
      "unlock_percentage": 100,
      "average_unlock_time_days": 2.5
    },
    {
      "id": "uuid",
      "name": "Maestro del Tiempo",
      "description": "Completar Timeline perfecto",
      "category": "mastery",
      "unlock_count": 12,
      "unlock_percentage": 42.8,
      "average_unlock_time_days": 15.3
    }
  ],
  "rarest_achievements": [
    {
      "id": "uuid",
      "name": "Leyenda Maya",
      "unlock_count": 2,
      "unlock_percentage": 7.1
    }
  ]
}
```

---

## 7. Intervention Alerts APIs

### 7.1 GET /teacher/alerts

Lista alertas de intervencion.

**Request:**
```http
GET /api/teacher/alerts?status=active&severity=high&classroom_id=uuid
```

**Response (200):**
```json
{
  "data": [
    {
      "id": "uuid",
      "student": {
        "id": "uuid",
        "name": "Carlos Mendez",
        "avatar_url": "https://..."
      },
      "classroom": {
        "id": "uuid",
        "name": "5to A"
      },
      "type": "declining_trend",
      "severity": "high",
      "status": "active",
      "message": "Desempeno en declive: -15% en ultimas 2 semanas",
      "details": {
        "previous_average": 85.5,
        "current_average": 70.2,
        "trend_period_days": 14
      },
      "suggested_actions": [
        "Programar reunion con estudiante",
        "Revisar ejercicios con dificultad",
        "Contactar a padres si persiste"
      ],
      "created_at": "2025-11-27T10:00:00Z"
    }
  ],
  "total": 4,
  "by_severity": {
    "critical": 1,
    "high": 2,
    "medium": 1,
    "low": 0
  }
}
```

### 7.2 PATCH /teacher/alerts/:id/resolve

Resuelve una alerta.

**Request:**
```http
PATCH /api/teacher/alerts/uuid/resolve
Content-Type: application/json

{
  "resolution_notes": "Reunion realizada, estudiante comprometido a mejorar",
  "actions_taken": ["Reunion con estudiante", "Plan de recuperacion"],
  "follow_up_date": "2025-12-05"
}
```

---

## 8. Bonus Coins APIs

### 8.1 POST /teacher/students/:studentId/bonus

Otorga bonificacion de ML Coins.

**Request:**
```http
POST /api/teacher/students/uuid/bonus
Content-Type: application/json

{
  "amount": 100,
  "reason": "Excelente participacion en clase",
  "category": "participation",
  "notify_student": true
}
```

**Response (201):**
```json
{
  "success": true,
  "transaction": {
    "id": "uuid",
    "amount": 100,
    "type": "teacher_bonus",
    "reason": "Excelente participacion en clase",
    "granted_by": "uuid",
    "granted_at": "2025-11-29T10:30:00Z"
  },
  "student_new_balance": 1850
}
```

**Frontend Hook:**
```typescript
// hooks/useGrantBonus.ts
export function useGrantBonus() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: ({ studentId, data }: { studentId: string; data: GrantBonusDto }) =>
      bonusCoinsApi.grantBonus(studentId, data),
    onSuccess: (_, { studentId }) => {
      // Invalidar queries relacionadas
      queryClient.invalidateQueries({ queryKey: ['teacher', 'students', studentId] });
      queryClient.invalidateQueries({ queryKey: ['teacher', 'analytics', 'economy'] });
      toast.success('Bonificacion otorgada exitosamente');
    },
  });
}
```

---

## 9. Reports APIs

### 9.1 POST /teacher/reports/generate

Genera reporte PDF/Excel.

**Request:**
```http
POST /api/teacher/reports/generate
Content-Type: application/json

{
  "format": "pdf",
  "report_type": "student_insights",
  "classroom_id": "uuid",
  "student_ids": ["uuid1", "uuid2"],
  "include_sections": [
    "summary",
    "progress",
    "achievements",
    "insights",
    "recommendations"
  ],
  "date_range": {
    "from": "2025-01-01",
    "to": "2025-11-29"
  }
}
```

**Response (200):**
- Content-Type: application/pdf
- Content-Disposition: attachment; filename="student-insights-report.pdf"
- Binary PDF content

---

## 10. Error Handling

### 10.1 Codigos de Error Comunes

| Code | Description | Resolution |
|------|-------------|------------|
| 400 | Bad Request | Validar datos de entrada |
| 401 | Unauthorized | Token invalido o expirado |
| 403 | Forbidden | Sin acceso al recurso |
| 404 | Not Found | Recurso no existe |
| 409 | Conflict | Duplicado o conflicto |
| 429 | Too Many Requests | Rate limit excedido |
| 500 | Internal Error | Contactar soporte |

### 10.2 Formato de Error

```json
{
  "statusCode": 403,
  "message": "Teacher does not have access to this classroom",
  "error": "Forbidden",
  "timestamp": "2025-11-29T10:30:00Z",
  "path": "/api/teacher/classrooms/uuid"
}
```

### 10.3 Manejo en Frontend

```typescript
// hooks/useErrorHandler.ts
export function useApiError() {
  const handleError = useCallback((error: AxiosError) => {
    const status = error.response?.status;
    const message = (error.response?.data as any)?.message;

    switch (status) {
      case 401:
        // Redirigir a login
        window.location.href = '/login';
        break;
      case 403:
        toast.error('No tienes acceso a este recurso');
        break;
      case 404:
        toast.error('Recurso no encontrado');
        break;
      case 429:
        toast.error('Demasiadas solicitudes. Intenta de nuevo en un momento.');
        break;
      default:
        toast.error(message || 'Error inesperado');
    }
  }, []);

  return { handleError };
}
```

---

## 11. Rate Limiting

| Endpoint Category | Rate Limit | Window |
|-------------------|------------|--------|
| Dashboard | 60 req | 1 min |
| Analytics | 30 req | 1 min |
| Grading | 100 req | 1 min |
| Reports | 10 req | 1 min |
| Bonus Coins | 20 req | 1 min |

---

## 12. Websocket Events

El Portal Teacher puede suscribirse a eventos en tiempo real:

```typescript
// Suscribirse a eventos
socket.on('student:submission', (data) => {
  // Nueva submission recibida
  queryClient.invalidateQueries({ queryKey: ['teacher', 'submissions'] });
});

socket.on('student:alert', (data) => {
  // Nueva alerta de estudiante
  queryClient.invalidateQueries({ queryKey: ['teacher', 'alerts'] });
  toast.warning(`Alerta: ${data.message}`);
});

socket.on('student:progress', (data) => {
  // Estudiante completo ejercicio
  queryClient.invalidateQueries({
    queryKey: ['teacher', 'classrooms', data.classroom_id, 'progress']
  });
});
```

---

## Changelog

| Version | Fecha | Cambios |
|---------|-------|---------|
| 1.0.0 | 2025-11-29 | Creacion inicial |
