Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/carlosgomezc7/plataforma_aprendizaje/llms.txt

Use this file to discover all available pages before exploring further.

La Plataforma Educativa Personalizada combina tres estructuras de datos distintas para modelar aspectos fundamentalmente diferentes de un sistema de aprendizaje. Cada estructura fue elegida porque su forma natural se ajusta al problema que resuelve: una cola lineal para el flujo ordenado de eventos de progreso, un grafo dirigido y ponderado para las relaciones entre módulos y sus tasas de abandono, y un árbol implícito de dependencias para representar jerarquías de prerrequisitos. Entender cómo interactúan estas tres estructuras es clave para comprender la arquitectura del sistema.

Cola Lineal (FIFO)

Caso de uso

La ColaProgreso actúa como un búfer en memoria que captura eventos de progreso estudiantil en tiempo real antes de que sean confirmados y escritos en db_local.json. Esto desacopla la velocidad de la interfaz gráfica (que responde instantáneamente) de la operación de I/O del disco, que puede ser más lenta o bloqueante.

Complejidad temporal

OperaciónComplejidad
Encolar (encolar)O(1)
Desencolar (desencolar)O(1)

Implementación

La cola usa una lista de Python con insert(0, ...) para agregar al frente y pop() para extraer del final, garantizando el orden FIFO (primero en entrar, primero en salir):
class ColaProgreso:
    def __init__(self):
        self.items = []

    def encolar(self, progreso):
        self.items.insert(0, progreso)  # Inserta al principio

    def desencolar(self):
        if not self.esta_vacia():
            return self.items.pop()  # Saca del final (el más antiguo)
        return None

    def esta_vacia(self):
        return len(self.items) == 0
El elemento más antiguo siempre se encuentra al final de la lista interna items, mientras que el más reciente está al principio. Al llamar a desencolar, se extrae el elemento del final mediante pop(), respetando estrictamente el orden de llegada.

Grafo de Adyacencia (No Lineal)

Caso de uso

GrafoRendimiento modela las transiciones entre módulos del curso y la tasa de abandono asociada a cada transición. Cada módulo es un nodo y cada transición es una arista dirigida y ponderada, donde el peso representa el porcentaje de estudiantes que abandonan antes de llegar al módulo siguiente. Esto permite detectar automáticamente cuellos de botella académicos.

Estructura

El grafo se representa como un diccionario de diccionarios anidados:
{
    modulo_origen: {
        modulo_destino: tasa_abandono
    }
}
Por ejemplo, la instancia inicializada en la aplicación contiene:
self.grafo_rendimiento.agregar_transicion("Módulo 1", "Módulo 2", 10)
self.grafo_rendimiento.agregar_transicion("Módulo 2", "Módulo 3", 65)  # Cuello de botella
self.grafo_rendimiento.agregar_transicion("Módulo 3", "Módulo 4", 15)
La transición de Módulo 2 a Módulo 3 tiene una tasa de abandono del 65 %, superando el umbral configurable del 50 %, por lo que dispara una alerta.

Tipo

El grafo es dirigido (las aristas tienen dirección, de origen a destino) y ponderado (cada arista lleva el valor numérico de la tasa de abandono).

Implementación — clase GrafoRendimiento

class GrafoRendimiento:
    def __init__(self):
        self.grafo = {}

    def agregar_transicion(self, modulo_origen, modulo_destino, tasa_abandono):
        if modulo_origen not in self.grafo:
            self.grafo[modulo_origen] = {}
        self.grafo[modulo_origen][modulo_destino] = tasa_abandono

    def detectar_cuellos_botella(self, umbral=50):
        alertas = []
        for origen, destinos in self.grafo.items():
            for destino, abandono in destinos.items():
                if abandono >= umbral:
                    alertas.append(
                        f"Alerta: {abandono}% de abandono entre '{origen}' y '{destino}'"
                    )
        return alertas

Árbol de Dependencias (Implícito)

Caso de uso

El árbol de dependencias representa la jerarquía de prerrequisitos de los módulos completados por un estudiante. No está implementado como una clase de árbol explícita, sino como un diccionario que mapea cada módulo a la lista de sub-módulos que lo componen, recorrido de forma recursiva por recuperar_historial_recursivo.

Estructura

{
    "Proyecto Final": ["Desarrollo Backend", "Desarrollo Frontend"],
    "Desarrollo Backend": ["Bases de Datos", "Lógica de Programación"],
    "Desarrollo Frontend": ["Diseño UI/UX"]
}
Cada clave es un nodo padre y su valor es la lista de nodos hijos directos. Los nodos hoja (módulos sin sub-módulos) simplemente no aparecen como claves en el diccionario, constituyendo el caso base de la recursión.

Implementación — función recuperar_historial_recursivo

def recuperar_historial_recursivo(modulo_actual, historial_completo, nivel=0):
    resultado = "  " * nivel + f"- Módulo Completado: {modulo_actual}\n"
    if modulo_actual in historial_completo:
        for sub_modulo in historial_completo[modulo_actual]:
            resultado += recuperar_historial_recursivo(sub_modulo, historial_completo, nivel + 1)
    return resultado
La profundidad del árbol controla la indentación visual (dos espacios por nivel), y la ausencia del módulo como clave en historial_completo termina la rama de recursión.

Comparativa de estructuras

EstructuraTipoComplejidad de accesoCaso de uso
Cola (ColaProgreso)LinealO(1)Progreso en tiempo real
Grafo (GrafoRendimiento)No linealO(V+E)Detección de abandono
Árbol de dependenciasNo linealO(n)Historial de módulos
  • V = número de módulos (vértices), E = número de transiciones (aristas).
  • La complejidad O(n) del árbol refleja un recorrido completo de todos los nodos en el peor caso.

Elige la estructura según la naturaleza del problema, no por familiaridad. Una cola es perfecta cuando el orden de llegada importa y las operaciones son en los extremos. Un grafo es necesario cuando los datos tienen relaciones cruzadas arbitrarias. Un árbol (explícito o implícito) modela jerarquías padre-hijo de forma natural y se recorre elegantemente con recursión. Usar la estructura equivocada para el problema correcto incrementa la complejidad del código sin ganar ninguna ventaja en rendimiento.

Build docs developers (and LLMs) love