Skip to content

Documentación Técnica

Daniel Nicolas Paez edited this page Oct 16, 2025 · 6 revisions

📊 Informe de Carga Docente - Documentación Técnica


📋 Descripción General

El Informe de Carga Docente es una funcionalidad que permite visualizar información detallada sobre la distribución de materias y estudiantes asignados a cada docente del sistema ProfeSort.

Características principales:

  • Visualización de estadísticas generales (totales y promedios)
  • Tabla detallada por docente con información de carga
  • Datos en tiempo real mediante API REST
  • Manejo robusto de errores y estados de carga
  • Interfaz responsive con Bootstrap

🏗️ Arquitectura del Sistema

graph TD
  A[Componente AdminDocente] --> B[AdminDocenteService]
  B --> C[HttpClient]
  C --> D[Mock API Server]
  D --> E[JSON Database]

  F[Usuario] --> G[Click 'Ver Informe']
  G --> H[toggleInformeCarga()]
  H --> I[cargarInformeCarga()]
  I --> J[getDocentesCarga()]
  J --> K[HTTP GET /carga]
  K --> L[Procesar Respuesta]
  L --> M[Actualizar UI]

Componentes involucrados:

  • Frontend: Angular 17 con Reactive Forms
  • Servicio: AdminDocenteService para comunicación HTTP
  • Mock API: JSON Server para simular backend
  • Base de datos: Archivo JSON con datos mock

🔄 Flujo de Generación del Informe

1. Activación del Informe

// Usuario hace clic en "Ver Informe de Carga"

toggleInformeCarga(): void {
  this.mostrarInformeCarga = !this.mostrarInformeCarga;
  if (this.mostrarInformeCarga && this.docentesCarga.length === 0) {
    this.cargarInformeCarga(); // Cargar datos si no existen
  }
}

2. Solicitud de Datos

// Llamada al servicio para obtener datos

cargarInformeCarga(): void {
  this.cargandoDatos = true;
  this.errorCarga = '';

  this.adminDocenteService.getDocentesCarga().subscribe({
    next: (data: DocenteCarga[]) => {
      this.docentesCarga = data;
      this.cargandoDatos = false;
    },
    error: (error) => {
      this.errorCarga = error.message;
      this.cargandoDatos = false;
    }
  });
}

3. Procesamiento de Datos

// Cálculo de estadísticas en tiempo real

obtenerEstadisticas() {
  const totalDocentes = this.docentesCarga.length;
  const docentesActivos = this.docentesCarga.filter(d => d.estado === 'Activo').length;
  const totalMaterias = this.docentesCarga.reduce((sum, d) => sum + d.cantidadMaterias, 0);
  const totalEstudiantes = this.docentesCarga.reduce((sum, d) => sum + d.cantidadEstudiantes, 0);
  return { totalDocentes, docentesActivos, totalMaterias, totalEstudiantes };
}

4. Renderización de la UI

  • Estadísticas generales: Cards con totales
  • Tabla detallada: Información por docente
  • Estados visuales: Loading, error, datos vacíos

📄 Formato de Datos

Estructura de datos esperada (DocenteCarga):

interface DocenteCarga {
  id: number;                    // Identificador único del docente
  nombre: string;                // Nombre completo del docente
  email: string;                 // Correo electrónico
  legajo: string;                // Número de legajo institucional
  estado: 'Activo' | 'Inactivo'; // Estado del docente
  cantidadMaterias: number;      // Número de materias asignadas
  cantidadEstudiantes: number;   // Total de estudiantes a cargo
  materias: string[];            // Array con nombres de materias
  fechaIngreso?: string;         // Fecha de ingreso (opcional)
  departamento?: string;         // Departamento (opcional)
}

Ejemplo de datos JSON:

{
  "carga": [
    {
      "id": 1,
      "nombre": "Karina del Valle Quinteros",
      "email": "karinaq38@gmail.com",
      "legajo": "DOC001",
      "estado": "Activo",
      "cantidadMaterias": 3,
      "cantidadEstudiantes": 45,
      "materias": ["Matemática", "Física", "Química"],
      "fechaIngreso": "2020-03-15",
      "departamento": "Ciencias Exactas"
    },
    {
      "id": 2,
      "nombre": "Juan Pablo Sanchez Brandán",
      "email": "sanchezbrandan@gmail.com",
      "legajo": "DOC002",
      "estado": "Activo",
      "cantidadMaterias": 2,
      "cantidadEstudiantes": 38,
      "materias": ["Historia", "Geografía"],
      "fechaIngreso": "2019-08-10",
      "departamento": "Ciencias Sociales"
    }
  ]
}


🌐 API Endpoints

GET /carga
Descripción: Obtiene la lista completa de docentes con información de carga
URL: http://localhost:3001/carga
Método: GET
Headers: Content-Type: application/json

Respuesta exitosa (200):

[
  {
    "id": 1,
    "nombre": "Karina del Valle Quinteros",
    "email": "karinaq38@gmail.com",
    "legajo": "DOC001",
    "estado": "Activo",
    "cantidadMaterias": 3,
    "cantidadEstudiantes": 45,
    "materias": ["Matemática", "Física", "Química"],
    "fechaIngreso": "2020-03-15",
    "departamento": "Ciencias Exactas"
  }
]

Códigos de error:

  • 404: Recurso no encontrado
  • 500: Error interno del servidor
  • 0: Error de conexión

💻 Implementación Frontend

Servicio AdminDocenteService:

@Injectable({ providedIn: 'root' })
export class AdminDocenteService {
  private apiUrl = 'http://localhost:3001/carga';
  constructor(private http: HttpClient) {}

  getDocentesCarga(): Observable<DocenteCarga[]> {
    return this.http.get<DocenteCarga[]>(this.apiUrl)
      .pipe(
        retry(1),                  // Reintentar una vez
        catchError(this.handleError) // Manejo de errores
      );
  }

  private handleError(error: HttpErrorResponse) {
    // Lógica de manejo de errores...
  }
}

Componente AdminDocente

Propiedades principales:

  • docentesCarga: DocenteCarga[] = [] // Array de datos de carga
  • cargandoDatos = false // Estado de carga
  • errorCarga = '' // Mensaje de error
  • mostrarInformeCarga = false // Visibilidad del informe

Métodos principales:

  • toggleInformeCarga(): Alternar visibilidad
  • cargarInformeCarga(): Obtener datos del API
  • obtenerEstadisticas(): Calcular estadísticas

🔧 Configuración del Mock Server

Puertos Múltiples

El proyecto utiliza dos instancias del mock-api para diferentes propósitos:

  • Puerto 3000: API general del sistema
  • Puerto 3001: API específica para Informe de Carga Docente

Estructura del Proyecto Mock API

ProfeSort/
├── mock-api/
│   ├── db.json              # Datos generales (puerto 3000)
│   ├── db-carga.json        # Datos de carga docente (puerto 3001)
│   ├── routes.json          # Configuración de rutas personalizadas  
│   ├── middleware.js        # Middlewares personalizados (CORS, etc.)
│   └── package.json         # Configuración del proyecto mock

Instalación y Configuración

Instalación de dependencias

cd mock-api
npm install json-server@0.17.4 concurrently --save

Configuración del package.json

{
  "name": "profesort-mock-api",
  "version": "1.0.0",
  "description": "Mock API para ProfeSort",
  "scripts": {
    "start": "concurrently \"npm run api-general\" \"npm run api-carga\"",
    "api-general": "npx json-server@0.17.4 --watch db.json --routes routes.json --middlewares middleware.js --port 3000",
    "api-carga": "npx json-server@0.17.4 --watch db-carga.json --routes routes.json --middlewares middleware.js --port 3001",
    "dev": "npm start"
  },
  "dependencies": {
    "json-server": "^0.17.4",
    "concurrently": "^8.2.0"
  }
}

Ejecución

Opción 1: Ambos servidores simultáneamente

cd mock-api
npm install
npm start  # Levanta puerto 3000 y 3001 a la vez

Opción 2: Servidores individuales

# Terminal 1 - API General (puerto 3000)
cd mock-api
npm run api-general

# Terminal 2 - API Carga (puerto 3001)  
cd mock-api
npm run api-carga

Opción 3: Comandos directos

# Terminal 1 - API General
cd mock-api
npx json-server@0.17.4 --watch db.json --routes routes.json --middlewares middleware.js --port 3000

# Terminal 2 - API Carga Docente
cd mock-api
npx json-server@0.17.4 --watch db-carga.json --routes routes.json --middlewares middleware.js --port 3001

URLs de Acceso

  • API General: http://localhost:3000
  • API Carga Docente: http://localhost:3001/carga

Verificación

Para comprobar que ambos servidores están funcionando:

# Verificar puerto 3000
curl http://localhost:3000

# Verificar puerto 3001
curl http://localhost:3001/carga

⚠️ Manejo de Errores

Tipos de errores manejados:

  • Error de conexión (Status 0): "No se puede conectar al servidor. Verifique que el mock API esté ejecutándose en el puerto 3001."
  • Recurso no encontrado (Status 404): "Recurso no encontrado."
  • Error del servidor (Status 500): "Error interno del servidor."

Estrategia:

  • Retry automático (1 reintento)
  • Mensajes descriptivos
  • Logging (console.error)
  • Botón de reintento en UI

📖 Ejemplos de Uso

Ejemplo 1: Carga exitosa

  1. Usuario hace clic en "Ver Informe de Carga"
  2. toggleInformeCarga()
  3. cargarInformeCarga()
  4. GET http://localhost:3001/carga
  5. Respuesta procesada → tabla + estadísticas

Ejemplo 2: Manejo de error

  1. Mock server apagado
  2. HTTP request falla con status 0
  3. Mensaje: "No se puede conectar al servidor..."
  4. Botón "Reintentar"
  5. Nuevo intento con cargarInformeCarga()

Ejemplo 3: Datos vacíos

  1. Mock responde []
  2. Se ocultan estadísticas
  3. Mensaje: "No hay datos disponibles"

🔍 Troubleshooting

**Problema: "Error de conexión" ** Solución:

**Problema: "Property does not exist" ** Solución:

  • Revisar métodos implementados
  • Comprobar imports
  • Revisar interfaces

**Problema: "JSON Server options not supported" ** Solución:

  • Instalar versión: npm install -g json-server@0.17.4
  • Usar JSON simplificado

**Problema: "Datos no se muestran" ** Solución:

  • Revisar estructura de db.json
  • Comprobar URL del servicio
  • Confirmar HttpClient en app.config.ts

🧩 Aplicación del Principio de Inversión de Dependencias (DIP)

📘 Definición

El Principio de Inversión de Dependencias dice básicamente que:

“Los módulos de alto nivel no deberían depender directamente de los módulos de bajo nivel.
Ambos deberían depender de abstracciones.
Las abstracciones no deben depender de los detalles; los detalles deben depender de las abstracciones.”

En palabras más simples: tu código no debería estar atado a implementaciones concretas. Es mejor trabajar sobre interfaces o capas intermedias para que puedas cambiar cómo se hacen las cosas sin romper todo lo demás.


🔍 Cómo lo aplicamos en el proyecto

En nuestro backend con Django REST Framework, este principio aparece sobre todo en cómo las vistas (views) interactúan con los serializers y con nuestro sistema centralizado de respuestas HTTP.

Esto nos permite:

  • No depender directamente de cómo se serializan los datos.
  • Cambiar la lógica de serialización o de respuesta sin afectar la vista.
  • Mantener el código limpio y fácil de mantener.

📂 Fragmento de código de ejemplo

Ubicación: backend/apps/gestion_academica/views.py

class MateriaListCreateView(APIView):
    def get(self, request):
        materias = Materia.objects.all()
        serializer = MateriaSerializer(materias, many=True)
        return success_response(data=serializer.data)
    
    def post(self, request):
        serializer = MateriaSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return success_response(data=serializer.data, status_code=status.HTTP_201_CREATED)
        return error_response(
            error=serializer.errors,
            message="Error al crear materia",
            status_code=status.HTTP_400_BAD_REQUEST
        )

---

## 🔍 Análisis del Principio DIP

### ¿Por qué este código cumple con DIP?

#### 1. Abstracción de Respuestas HTTP
La vista **no construye manualmente las respuestas HTTP**, sino que usa las funciones `success_response()` y `error_response()`.  
Esto **desacopla la vista de los detalles de la respuesta**, cumpliendo DIP.

## 2. Abstracción de Serialización
La vista **no conoce cómo se transforma un objeto Materia a JSON**. Eso lo hace `MateriaSerializer`.  
Cambiar la estructura del JSON solo requiere modificar el serializer, **sin tocar la vista**.

---

## 3. Uso de la clase base `APIView`
Heredamos de `APIView`, que abstrae detalles de bajo nivel como:
- Parseo de requests  
- Manejo de diferentes tipos de contenido  
- Autenticación y permisos  

Así, la vista se enfoca solo en **la lógica de negocio**, mientras los detalles técnicos quedan manejados por la abstracción.

**Resumen:** La vista depende de **abstracciones, no de implementaciones concretas**, logrando flexibilidad, menor acoplamiento y fácil mantenimiento.

---

## 📝 Notas Adicionales

### ⚙️ Rendimiento
- Carga inicial solo al abrir el informe  
- Estadísticas en tiempo real (lado cliente)  
- Considerar **caché** si los datasets son grandes  

---

### 🚀 Futuras mejoras
- Filtros por **departamento, estado y fechas**  
- Exportación: **PDF, Excel, CSV**  
- Paginación de resultados  
- Gráficos dinámicos con **Chart.js o D3**  
- Actualización en **tiempo real** usando **WebSockets**  

---

### 🔒 Seguridad
- Usar **JWT** en producción  
- Validar todos los datos en backend  
- Sanitización de inputs para evitar inyecciones  
- Aplicar **rate limiting** en la API  

---

### 📚 Referencias
- [Angular HttpClient Documentation](https://angular.io/guide/http)  
- [JSON Server Documentation](https://github.com/typicode/json-server)  
- [RxJS Operators](https://rxjs.dev/guide/operators)  
- [Bootstrap Documentation](https://getbootstrap.com/docs/)  

---

**Última actualización:** Octubre 2025  
**Versión:** 1.0  
**Autor:** Equipo de Desarrollo ProCoders

📚 Wiki Proyecto ProfeSort

🏠 Home


💻 Desarrollo


👥 Equipo de Desarrolladores


🛠️ Stack Tecnológico


📘 Documentación Técnica


🎨 Maquetado Figma


✅ Definición of Done


📐Modelado y Arquitectura


📌 Especificación de Requerimientos


🌳 Sistema de Ramas


📰 Ceremonias y artefactos Scrum

Clone this wiki locally