- Configure workspace Git repository with comprehensive .gitignore - Add Odoo as submodule for ERP reference code - Include documentation: SETUP.md, GIT-STRUCTURE.md - Add gitignore templates for projects (backend, frontend, database) - Structure supports independent repos per project/subproject level Workspace includes: - core/ - Reusable patterns, modules, orchestration system - projects/ - Active projects (erp-suite, gamilit, trading-platform, etc.) - knowledge-base/ - Reference code and patterns (includes Odoo submodule) - devtools/ - Development tools and templates - customers/ - Client implementations template 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
21 KiB
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:
GET /api/teacher/dashboard/stats
Authorization: Bearer {token}
Response (200):
{
"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:
// 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:
GET /api/teacher/dashboard/activities?limit=10
Authorization: Bearer {token}
Response (200):
{
"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):
{
"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:
GET /api/teacher/dashboard/top-performers?limit=5
Response (200):
{
"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:
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):
{
"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:
// 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:
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):
{
"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:
GET /api/teacher/classrooms/uuid/students?page=1&limit=20&sort_by=progress&sort_order=desc
Response (200):
{
"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):
{
"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:
GET /api/teacher/students/uuid/progress?include_exercises=true&date_from=2025-01-01
Response (200):
{
"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):
{
"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:
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:
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):
{
"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:
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):
{
"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:
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):
{
"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):
{
"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):
{
"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):
{
"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:
GET /api/teacher/alerts?status=active&severity=high&classroom_id=uuid
Response (200):
{
"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:
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:
POST /api/teacher/students/uuid/bonus
Content-Type: application/json
{
"amount": 100,
"reason": "Excelente participacion en clase",
"category": "participation",
"notify_student": true
}
Response (201):
{
"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:
// 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:
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
{
"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
// 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:
// 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 |