# Guia de Desarrollo - Portal Teacher **Fecha de creacion:** 2025-11-29 **Version:** 1.0.0 **Estado:** VIGENTE **Aplica a:** apps/frontend/src/apps/teacher/ + apps/backend/src/modules/teacher/ --- ## 1. Vision General ### 1.1 Proposito El Portal Teacher es la interfaz principal para docentes en GAMILIT. Proporciona herramientas para: - **Gestion de Aulas:** Crear, administrar y monitorear classrooms - **Seguimiento de Estudiantes:** Progreso, desempeno, alertas - **Asignaciones:** Crear y gestionar tareas/ejercicios - **Comunicacion:** Mensajes y feedback a estudiantes - **Analitica:** Dashboards e insights de aprendizaje - **Gamificacion:** Bonificaciones, logros, economia de aula - **Reportes:** Generacion de informes PDF/Excel ### 1.2 Usuarios Objetivo | Rol | Acceso | Funcionalidades | |-----|--------|-----------------| | Teacher | Completo | Todas las funcionalidades del portal | | Admin | Supervision | Vista de todas las aulas + configuracion | --- ## 2. Arquitectura ### 2.1 Estructura de Carpetas #### Frontend (apps/frontend/src/apps/teacher/) ``` teacher/ ├── index.ts # Barrel export principal ├── layouts/ │ └── TeacherLayout.tsx # Layout principal con navegacion ├── pages/ # Paginas del portal (19 paginas) │ ├── TeacherDashboardPage.tsx │ ├── TeacherClassesPage.tsx │ ├── TeacherStudentsPage.tsx │ ├── TeacherAssignmentsPage.tsx │ ├── TeacherAlertsPage.tsx │ ├── TeacherAnalyticsPage.tsx │ ├── TeacherGamificationPage.tsx │ ├── TeacherReportsPage.tsx │ ├── TeacherCommunicationPage.tsx │ ├── TeacherContentPage.tsx │ ├── TeacherProgressPage.tsx │ ├── TeacherMonitoringPage.tsx │ ├── TeacherExerciseResponsesPage.tsx │ ├── TeacherResourcesPage.tsx │ └── TeacherSettingsPage.tsx # 🆕 Configuración del profesor ├── components/ # Componentes organizados por dominio │ ├── dashboard/ # Componentes del dashboard │ ├── assignments/ # Gestion de tareas │ ├── alerts/ # Alertas de intervencion │ ├── analytics/ # Graficas y metricas │ ├── progress/ # Progreso de estudiantes │ ├── monitoring/ # Monitoreo en tiempo real │ ├── reports/ # Generacion de reportes │ ├── responses/ # Respuestas de ejercicios │ ├── communication/ # Mensajes y anuncios │ ├── collaboration/ # Compartir recursos │ └── index.ts ├── hooks/ # Custom hooks (17 hooks) │ ├── useTeacherDashboard.ts │ ├── useClassrooms.ts │ ├── useAssignments.ts │ ├── useStudentProgress.ts │ ├── useAnalytics.ts │ ├── useInterventionAlerts.ts │ ├── useGrading.ts │ ├── useGrantBonus.ts │ ├── useEconomyAnalytics.ts │ ├── useStudentsEconomy.ts │ ├── useAchievementsStats.ts │ ├── useTeacherMessages.ts │ ├── useTeacherContent.ts │ ├── useExerciseResponses.ts │ └── index.ts ├── constants/ # Constantes centralizadas (P2-01, P2-02) │ ├── alertTypes.ts # Tipos y prioridades de alertas │ ├── manualReviewExercises.ts # Ejercicios de revision manual │ └── index.ts └── types/ └── index.ts # 40+ interfaces/types ``` #### Backend (apps/backend/src/modules/teacher/) ``` teacher/ ├── teacher.module.ts # Modulo NestJS principal ├── index.ts # Barrel exports ├── controllers/ # 7 controllers │ ├── teacher.controller.ts # Analytics, progress, insights │ ├── teacher-classrooms.controller.ts │ ├── teacher-grades.controller.ts │ ├── teacher-communication.controller.ts │ ├── teacher-content.controller.ts │ ├── intervention-alerts.controller.ts │ └── exercise-responses.controller.ts ├── services/ # 14 services │ ├── teacher-dashboard.service.ts │ ├── teacher-classrooms-crud.service.ts │ ├── student-progress.service.ts │ ├── analytics.service.ts │ ├── grading.service.ts │ ├── intervention-alerts.service.ts │ ├── student-risk-alert.service.ts # CRON job │ ├── ml-predictor.service.ts # Predicciones ML │ ├── reports.service.ts │ ├── bonus-coins.service.ts │ ├── teacher-messages.service.ts │ ├── teacher-content.service.ts │ ├── exercise-responses.service.ts │ └── student-blocking.service.ts ├── dto/ # Data Transfer Objects │ ├── analytics.dto.ts │ ├── classroom.dto.ts │ ├── classroom-response.dto.ts │ ├── classroom-progress.dto.ts │ ├── grades.dto.ts │ ├── grading.dto.ts │ ├── grant-bonus.dto.ts │ ├── teacher-messages.dto.ts │ ├── teacher-content.dto.ts │ ├── teacher-notes.dto.ts │ ├── reports.dto.ts │ ├── exercise-responses.dto.ts │ ├── intervention-alerts.dto.ts │ └── student-blocking/ ├── entities/ # Entidades TypeORM │ ├── student-intervention-alert.entity.ts │ ├── message.entity.ts │ ├── teacher-content.entity.ts │ └── teacher-report.entity.ts ├── guards/ # Guards de autorizacion │ ├── teacher.guard.ts │ └── classroom-ownership.guard.ts ├── interfaces/ │ └── ml-predictor.interface.ts └── __tests__/ # Tests unitarios ``` ### 2.2 Diagrama de Dependencias ``` ┌─────────────────────────────────────────────────────────────────┐ │ FRONTEND │ ├─────────────────────────────────────────────────────────────────┤ │ Pages ──────► Components ──────► Hooks ──────► API Services │ │ │ │ │ │ └───────────────────┼─────► Types │ └────────────────────────────────────────┼─────────────────────────┘ │ HTTP/REST │ ┌────────────────────────────────────────▼─────────────────────────┐ │ BACKEND │ ├──────────────────────────────────────────────────────────────────┤ │ Controllers ──────► Services ──────► Repositories ──────► DB │ │ │ │ │ │ └──────────────────┼─────► Guards │ │ │ │ │ └─────► External Modules │ │ (Auth, Social, Progress, etc.) │ └──────────────────────────────────────────────────────────────────┘ ``` --- ## 3. Patrones de Diseno ### 3.1 Frontend Patterns #### 3.1.1 Page + Hook Pattern Cada pagina tiene un hook correspondiente que encapsula la logica: ```typescript // Pattern: Page con Hook dedicado // TeacherDashboardPage.tsx export const TeacherDashboardPage: React.FC = () => { const { stats, classrooms, pendingSubmissions, alerts, isLoading, error, refetch, } = useTeacherDashboard(); if (isLoading) return ; if (error) return ; return ( ); }; // useTeacherDashboard.ts export function useTeacherDashboard(): UseTeacherDashboardReturn { const { data: stats, isLoading: statsLoading } = useQuery({ queryKey: ['teacher', 'dashboard', 'stats'], queryFn: () => teacherApi.getDashboardStats(), }); const { data: classrooms, isLoading: classroomsLoading } = useQuery({ queryKey: ['teacher', 'classrooms'], queryFn: () => classroomsApi.getTeacherClassrooms(), }); // ... mas queries return { stats, classrooms, isLoading: statsLoading || classroomsLoading, // ... }; } ``` #### 3.1.2 Component Composition Componentes organizados por dominio, compuestos desde componentes mas pequenos: ```typescript // dashboard/index.ts - Barrel export export { TeacherDashboardHero } from './TeacherDashboardHero'; export { ClassroomsGrid } from './ClassroomsGrid'; export { ClassroomCard } from './ClassroomCard'; export { PendingSubmissionsList } from './PendingSubmissionsList'; export { StudentAlerts } from './StudentAlerts'; export { QuickActionsPanel } from './QuickActionsPanel'; export { RecentAssignmentsList } from './RecentAssignmentsList'; export { CreateClassroomModal } from './CreateClassroomModal'; export { CreateAssignmentModal } from './CreateAssignmentModal'; export { GradeSubmissionModal } from './GradeSubmissionModal'; ``` #### 3.1.3 Modal Pattern Modales para acciones complejas: ```typescript // Pattern: Modal con form interno interface CreateClassroomModalProps { isOpen: boolean; onClose: () => void; onSuccess: (classroom: Classroom) => void; } export const CreateClassroomModal: React.FC = ({ isOpen, onClose, onSuccess, }) => { const { mutate: createClassroom, isPending } = useMutation({ mutationFn: classroomsApi.create, onSuccess: (data) => { onSuccess(data); onClose(); }, }); return ( ); }; ``` ### 3.2 Backend Patterns #### 3.2.1 Guard-Based Authorization ```typescript // Pattern: Guards para autorizacion @Controller('teacher') @UseGuards(JwtAuthGuard, TeacherGuard) // Requiere autenticacion + rol teacher @ApiTags('Teacher') export class TeacherController { @Get('classrooms/:classroomId/students') @UseGuards(ClassroomOwnershipGuard) // Verifica propiedad del aula async getClassroomStudents( @Param('classroomId') classroomId: string, @CurrentUser() teacher: User, ): Promise { return this.studentProgressService.getClassroomStudents(classroomId); } } ``` #### 3.2.2 TeacherGuard ```typescript // guards/teacher.guard.ts @Injectable() export class TeacherGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { const request = context.switchToHttp().getRequest(); const user = request.user; if (!user) return false; // Verificar rol teacher o admin const hasTeacherRole = user.roles?.some( (role: UserRole) => role.role?.name === 'teacher' || role.role?.name === 'admin' ); return hasTeacherRole; } } ``` #### 3.2.3 ClassroomOwnershipGuard ```typescript // guards/classroom-ownership.guard.ts @Injectable() export class ClassroomOwnershipGuard implements CanActivate { constructor( @InjectRepository(TeacherClassroom, 'social') private teacherClassroomRepo: Repository, ) {} async canActivate(context: ExecutionContext): Promise { const request = context.switchToHttp().getRequest(); const user = request.user; const classroomId = request.params.classroomId; if (!classroomId || !user?.id) return false; // Verificar que el teacher tiene acceso al classroom const teacherClassroom = await this.teacherClassroomRepo.findOne({ where: { teacher_id: user.id, classroom_id: classroomId, }, }); return !!teacherClassroom; } } ``` #### 3.2.4 Service Layer Pattern ```typescript // Pattern: Service con cache y multi-datasource @Injectable() export class AnalyticsService { constructor( @Inject(CACHE_MANAGER) private cacheManager: Cache, @InjectRepository(ModuleProgress, 'progress') private moduleProgressRepo: Repository, @InjectRepository(ExerciseSubmission, 'progress') private submissionRepo: Repository, ) {} async getClassroomAnalytics(classroomId: string): Promise { // Intentar cache primero const cacheKey = `classroom:${classroomId}:analytics`; const cached = await this.cacheManager.get(cacheKey); if (cached) return cached; // Calcular analytics const analytics = await this.calculateAnalytics(classroomId); // Guardar en cache (5 min TTL) await this.cacheManager.set(cacheKey, analytics, 300_000); return analytics; } } ``` #### 3.2.5 CRON Jobs para Alertas ```typescript // Pattern: Scheduled jobs para deteccion de riesgo @Injectable() export class StudentRiskAlertService { constructor( private readonly interventionAlertsService: InterventionAlertsService, private readonly mlPredictorService: MlPredictorService, ) {} @Cron('0 */6 * * *') // Cada 6 horas async checkStudentRisks(): Promise { const students = await this.getActiveStudents(); for (const student of students) { const riskLevel = await this.mlPredictorService.predictRisk(student.id); if (riskLevel === 'high') { await this.interventionAlertsService.createAlert({ student_id: student.id, type: 'declining_trend', priority: 'high', message: `Estudiante ${student.name} muestra patron de riesgo`, }); } } } } ``` --- ## 4. Buenas Practicas ### 4.1 Frontend #### 4.1.1 Hooks ```typescript // DO: Hooks especificos por funcionalidad export function useClassrooms() { ... } export function useClassroomStudents(classroomId: string) { ... } export function useCreateClassroom() { ... } // DON'T: Un hook gigante que hace todo export function useTeacher() { ... } // Evitar ``` #### 4.1.2 Types ```typescript // DO: Types especificos y documentados /** * Estado de un estudiante en el monitoreo * @see Backend: StudentMonitoringDto */ export type StudentStatus = 'active' | 'inactive' | 'offline'; // DO: Alineacion con backend export interface Classroom { id: string; name: string; student_count: number; // Backend: current_students_count created_at: string; // ISO string (JSON serialization) } ``` #### 4.1.3 Queries ```typescript // DO: Query keys descriptivas y anidadas const { data } = useQuery({ queryKey: ['teacher', 'classrooms', classroomId, 'students'], queryFn: () => api.getClassroomStudents(classroomId), enabled: !!classroomId, }); // DO: Invalidar queries relacionadas en mutations const { mutate } = useMutation({ mutationFn: api.createAssignment, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['teacher', 'assignments'] }); queryClient.invalidateQueries({ queryKey: ['teacher', 'dashboard'] }); }, }); ``` ### 4.2 Backend #### 4.2.1 Controllers ```typescript // DO: Decoradores completos para Swagger @Get('classrooms/:id') @UseGuards(ClassroomOwnershipGuard) @ApiOperation({ summary: 'Obtener detalle de aula' }) @ApiParam({ name: 'id', description: 'ID del classroom' }) @ApiOkResponse({ type: ClassroomDetailDto }) @ApiNotFoundResponse({ description: 'Aula no encontrada' }) async getClassroom(@Param('id') id: string): Promise { return this.classroomService.findById(id); } ``` #### 4.2.2 Services ```typescript // DO: Logging y error handling @Injectable() export class BonusCoinsService { private readonly logger = new Logger(BonusCoinsService.name); async grantBonus(teacherId: string, dto: GrantBonusDto): Promise { this.logger.log(`Teacher ${teacherId} granting ${dto.amount} coins to ${dto.studentId}`); try { await this.mlCoinsService.addTransaction({ user_id: dto.studentId, amount: dto.amount, type: 'teacher_bonus', description: dto.reason, granted_by: teacherId, }); } catch (error) { this.logger.error(`Failed to grant bonus: ${error.message}`); throw new InternalServerErrorException('Error al otorgar bonificacion'); } } } ``` #### 4.2.3 DTOs ```typescript // DO: Validacion completa con mensajes export class GrantBonusDto { @ApiProperty({ description: 'ID del estudiante' }) @IsUUID('4', { message: 'student_id debe ser UUID valido' }) student_id!: string; @ApiProperty({ description: 'Cantidad de ML Coins', minimum: 1, maximum: 1000 }) @IsNumber() @Min(1, { message: 'Minimo 1 ML Coin' }) @Max(1000, { message: 'Maximo 1000 ML Coins' }) amount!: number; @ApiPropertyOptional({ description: 'Razon de la bonificacion' }) @IsOptional() @IsString() @MaxLength(500) reason?: string; } ``` --- ## 5. APIs del Portal Teacher ### 5.1 Endpoints Principales | Metodo | Endpoint | Descripcion | Guard | |--------|----------|-------------|-------| | GET | `/teacher/dashboard/stats` | Estadisticas del dashboard | TeacherGuard | | GET | `/teacher/classrooms` | Lista de aulas del teacher | TeacherGuard | | POST | `/teacher/classrooms` | Crear nueva aula | TeacherGuard | | GET | `/teacher/classrooms/:id/students` | Estudiantes del aula | ClassroomOwnership | | GET | `/teacher/classrooms/:id/progress` | Progreso del aula | ClassroomOwnership | | GET | `/teacher/assignments` | Lista de tareas | TeacherGuard | | POST | `/teacher/assignments` | Crear tarea | TeacherGuard | | GET | `/teacher/alerts` | Alertas de intervencion | TeacherGuard | | PATCH | `/teacher/alerts/:id/resolve` | Resolver alerta | TeacherGuard | | GET | `/teacher/analytics/:classroomId` | Analytics del aula | ClassroomOwnership | | POST | `/teacher/bonus-coins` | Otorgar bonificacion | TeacherGuard | | GET | `/teacher/exercise-responses` | Respuestas de ejercicios | TeacherGuard | | POST | `/teacher/grades/:submissionId` | Calificar submission | TeacherGuard | | GET | `/teacher/messages` | Mensajes enviados | TeacherGuard | | POST | `/teacher/messages` | Enviar mensaje | TeacherGuard | ### 5.2 Frontend API Services ``` services/api/teacher/ ├── teacherApi.ts # Dashboard y general ├── classroomsApi.ts # CRUD de aulas ├── assignmentsApi.ts # Gestion de tareas ├── studentProgressApi.ts # Progreso estudiantes ├── analyticsApi.ts # Analiticas ├── interventionAlertsApi.ts # Alertas ├── gradingApi.ts # Calificaciones ├── bonusCoinsApi.ts # Bonificaciones ├── exerciseResponsesApi.ts # Respuestas ├── teacherMessagesApi.ts # Comunicacion ├── teacherContentApi.ts # Contenido └── index.ts # Barrel export ``` --- ## 6. Seguridad ### 6.1 Autorizacion 1. **JwtAuthGuard:** Verifica token JWT valido 2. **TeacherGuard:** Verifica rol teacher/admin 3. **ClassroomOwnershipGuard:** Verifica acceso al aula especifica ### 6.2 Reglas de Acceso ```yaml Teacher puede: - Ver/editar SOLO sus propias aulas - Ver estudiantes SOLO de sus aulas - Calificar submissions SOLO de sus aulas - Otorgar bonificaciones SOLO a estudiantes de sus aulas Teacher NO puede: - Ver aulas de otros teachers - Acceder a datos de estudiantes fuera de sus aulas - Modificar configuracion del sistema - Crear/eliminar usuarios ``` ### 6.3 Validacion de Datos ```typescript // Siempre validar pertenencia antes de operaciones async gradeSubmission(teacherId: string, submissionId: string, grade: number) { const submission = await this.getSubmission(submissionId); // Verificar que el submission pertenece a un aula del teacher const hasAccess = await this.verifyTeacherOwnership( teacherId, submission.classroom_id ); if (!hasAccess) { throw new ForbiddenException('No tiene acceso a esta submission'); } // Proceder con calificacion } ``` --- ## 7. Testing ### 7.1 Tests Unitarios Backend ```typescript // teacher-classrooms.controller.spec.ts describe('TeacherClassroomsController', () => { let controller: TeacherClassroomsController; let service: TeacherClassroomsCrudService; beforeEach(async () => { const module = await Test.createTestingModule({ controllers: [TeacherClassroomsController], providers: [ { provide: TeacherClassroomsCrudService, useValue: mockService }, ], }).compile(); controller = module.get(TeacherClassroomsController); }); it('should return classrooms for teacher', async () => { mockService.findByTeacher.mockResolvedValue([mockClassroom]); const result = await controller.getClassrooms(mockUser); expect(result).toHaveLength(1); expect(mockService.findByTeacher).toHaveBeenCalledWith(mockUser.id); }); }); ``` ### 7.2 Tests Frontend ```typescript // useTeacherDashboard.test.ts describe('useTeacherDashboard', () => { it('should fetch dashboard data', async () => { const { result } = renderHook(() => useTeacherDashboard(), { wrapper: QueryClientProvider, }); await waitFor(() => { expect(result.current.isLoading).toBe(false); }); expect(result.current.stats).toBeDefined(); expect(result.current.classrooms).toBeDefined(); }); }); ``` --- ## 8. Checklist de Desarrollo ### 8.1 Nueva Funcionalidad - [ ] Definir tipos en `teacher/types/index.ts` - [ ] Crear DTO en backend `teacher/dto/` - [ ] Implementar service en `teacher/services/` - [ ] Crear/modificar controller - [ ] Agregar guards si necesario - [ ] Crear API service en frontend - [ ] Implementar hook en `teacher/hooks/` - [ ] Crear componentes necesarios - [ ] Integrar en pagina correspondiente - [ ] Agregar tests unitarios - [ ] Documentar en Swagger (decoradores) ### 8.2 Code Review - [ ] Guards aplicados correctamente - [ ] Validacion de DTOs completa - [ ] Error handling implementado - [ ] Logs apropiados en services - [ ] Types alineados frontend/backend - [ ] Query keys descriptivas - [ ] Invalidacion de cache correcta --- ## 9. Troubleshooting ### 9.1 Problemas Comunes | Problema | Causa | Solucion | |----------|-------|----------| | 403 Forbidden | Guard rechaza | Verificar rol y ownership | | Data desactualizada | Cache | Invalidar queries manualmente | | Types mismatch | Desync FE/BE | Regenerar types con OpenAPI | | Performance lenta | Queries N+1 | Usar relations en TypeORM | ### 9.2 Debugging ```typescript // Habilitar logs en development if (process.env.NODE_ENV === 'development') { apiClient.interceptors.request.use((config) => { console.log(`[Teacher API] ${config.method?.toUpperCase()} ${config.url}`); return config; }); } ``` --- ## 10. Referencias ### Documentos Complementarios del Portal Teacher | Documento | Descripcion | |-----------|-------------| | [PORTAL-TEACHER-API-REFERENCE.md](./PORTAL-TEACHER-API-REFERENCE.md) | Referencia completa de 45+ APIs con ejemplos | | [PORTAL-TEACHER-FLOWS.md](./PORTAL-TEACHER-FLOWS.md) | Flujos de datos, diagramas e integracion | | [API-TEACHER-MODULE.md](../90-transversal/api/API-TEACHER-MODULE.md) | Documentacion de endpoints del modulo teacher | | [TEACHER-PAGES-SPECIFICATIONS.md](../frontend/teacher/pages/TEACHER-PAGES-SPECIFICATIONS.md) | Especificaciones de paginas del portal | | [TEACHER-CONSTANTS-REFERENCE.md](../frontend/teacher/constants/TEACHER-CONSTANTS-REFERENCE.md) | Referencia de constantes centralizadas | ### Guias Generales - [COMPONENT-PATTERNS.md](./frontend/COMPONENT-PATTERNS.md) - Patrones de componentes - [HOOK-PATTERNS.md](./frontend/HOOK-PATTERNS.md) - Patrones de hooks - [DTO-CONVENTIONS.md](./backend/DTO-CONVENTIONS.md) - Convenciones de DTOs - [ESTRUCTURA-MODULOS.md](./backend/ESTRUCTURA-MODULOS.md) - Estructura de modulos - [ESTANDARES-API-ROUTES.md](../../orchestration/directivas/ESTANDARES-API-ROUTES.md) - Rutas API --- ## Changelog | Version | Fecha | Cambios | |---------|-------|---------| | 1.2.0 | 2025-12-26 | Agregada carpeta constants/ (alertTypes.ts, manualReviewExercises.ts), referencias actualizadas | | 1.1.0 | 2025-11-29 | Agregada TeacherSettingsPage (/teacher/settings) | | 1.0.0 | 2025-11-29 | Creacion inicial |