Arquitectura
Estado: v1 completa. Todas las secciones tienen documentos de especificación detallados enlazados abajo.
Índice de documentos
| Documento | Qué cubre |
|---|---|
| vision.md | Fundamento filosófico — por qué SkillNet está construido así |
| architecture.md | Visión general del sistema, capas, aspectos transversales, decidido vs diferido |
| data-model.md | Esquema de PostgreSQL — 15+ tablas, índices, consultas clave |
| screens.md | 20 especificaciones de pantalla con rutas, secciones, datos, estados, acciones |
| design-system.md | Tokens visuales, patrones de componentes, anti-patrones |
| product.md | Qué es SkillNet, roles, tipos de contenido, adaptación, bucle de aprendizaje |
| content-generation.md | Pipeline de generación con LangGraph, 7 roles de agente, integración RAG |
| chat-agents.md | Agentes de chat de tutor y admin, patrón PageIndex, árbol de decisión RAG |
| rag-retrieval.md | Ingesta de documentos, chunking, búsqueda híbrida, reranking, embeddings |
| backend-api.md | Estructura del proyecto FastAPI, 73 endpoints, inyección de dependencias |
| llm-integration.md | Abstracción de proveedor, streaming, gestión de prompts, seguimiento de coste |
| background-processing.md | Persistencia de LangGraph + runner de trabajos en PostgreSQL, flujos de ciclo de vida |
| docker-deployment.md | Servicios de Docker Compose, Dockerfiles, dev/prod, primer arranque |
| security.md | Autenticación, compartimentos de agentes, RGPD, seguridad de API, secretos |
| mcp-external-api.md | Servidor MCP, API REST externa, webhooks, integraciones |
| frontend-backend-integration.md | TanStack Query, SSE, UI de Nivel 2/3, subida de ficheros |
| snml-spec.md | Formato de contenido SNML — Markdown + componentes interactivos, renderizado dual (doc/web) |
| ai-course-design.md | Endpoints de IA sin estado, commit-on-create, enrutamiento multimodelo para el diseño de cursos |
| adaptive-learning.md | Preferencias explícitas, estrategia pedagógica, medición y contrato con la librería de componentes |
| personalization-architecture.md | Separación objetivo, misión, representación, componente, apoyo y planificador en sombra |
| learning-experience-architecture.md | Contrato pedagógico neutral, variantes, proveedores, generación multiagente y evidencia común hacia mastery |
| audience-modes.md | Un núcleo de producto con modos organization e individual, sin separar clases ni verticales |
| conversational-modalities.md | Frontera entre audio en chat, Realtime, mascota y podcasts; propósito y alcance por audiencia |
| podcast-studio-plan.md | Plan de Podcast Studio tipo NotebookLM, modular, configurable y agnóstico de proveedor |
| future-product-directions.md | Índice de las direcciones futuras de producto acordadas y su estado |
| Cuaderno de experimentos | Hipótesis, resultados, reversiones y aprendizajes reproducibles de personalización |
Visión general del sistema
SkillNet toma el conocimiento interno de una organización (manuales, procesos, documentación) y lo convierte en un sistema de aprendizaje vivo. El flujo central:
Documentos internos ──→ Ingesta ──→ Capa de conocimiento ──→ Equipos de agentes ──→ Interfaz ──→ Aprendiz
↑ │
└────────────── progreso ────────────────────┘
El conocimiento fluye en una sola dirección: desde la documentación en bruto, pasando por conocimiento estructurado, hasta experiencias de aprendizaje generadas. El progreso del aprendiz retroalimenta la capa de conocimiento para impulsar la adaptación.
Capas
1. Ingesta
Toma la documentación interna en bruto de la empresa y la transforma en conocimiento estructurado sobre el que el sistema puede razonar.
- Entrada: Markdown, PDFs, wikis internas, documentos de proceso
- Salida: Unidades de conocimiento estructuradas e indexadas para su recuperación
(diferido) Estrategia de chunking. El enfoque condicional de RAG está documentado (los documentos pequeños van enteros, los grandes se trocean). El método concreto de chunking (semántico por secciones con reserva de tamaño fijo) se decidirá cuando se construya el pipeline de ingesta.
(diferido) Flujo de actualización. Cuando cambian los documentos fuente, ¿cómo se mantiene al día la capa de conocimiento? Reingesta completa frente a actualizaciones incrementales.
2. Capa de conocimiento
La memoria del sistema. Almacena conocimiento estructurado y lo pone a disposición de los agentes a través de la recuperación.
| Componente | Rol |
|---|---|
| PostgreSQL + pgvector | Una única base de datos para todos los datos: relacionales (usuarios, cursos, progreso) y vectoriales (embeddings). Una sola copia de seguridad, una sola conexión, joins transaccionales entre contenido y vectores. |
| Control de acceso | Determina qué conocimiento es visible para quién |
Lo que sabemos por la investigación:
- La clasificación de niveles de acceso basada en contenido se limita a un 78% de precisión (investigación sobre fronteras semánticas). La privacidad es una decisión humana, no una propiedad del contenido. El sistema debe hacer cumplir las decisiones de acceso de la organización, no adivinarlas.
- El acceso basado en compartimentos (necesidad de conocer) es el modelo más prometedor. Un agente arranca solo con los compartimentos que su tarea requiere. El control ocurre en el arranque (qué puede ver) y en la frontera (qué puede emitir), no dentro del agente.
Almacén vectorial: pgvector. Los embeddings viven dentro de PostgreSQL como una columna vector. Una sola base de datos para todo — consultas relacionales y búsqueda semántica en la misma transacción. A escala de MVP (decenas de documentos, cientos de empleados), pgvector es más que suficiente. Si el sistema alguna vez necesita manejar millones de vectores a miles de QPS, los embeddings pueden migrar a un almacén dedicado sin tocar el esquema relacional.
(abierto) Grafo de conocimiento. Si las relaciones entre unidades de conocimiento necesitan una estructura de grafo explícita o si la proximidad vectorial + metadatos es suficiente. El paper de G-SPEC sugiere que el 68% de las ganancias de seguridad provienen de la estructura de grafo.
3. Equipos de agentes
Agentes de IA especializados orquestados con LangGraph. Cada tipo de agente tiene un rol distinto:
| Agente | Responsabilidad |
|---|---|
| Agentes de ingesta | Procesan documentos en bruto en conocimiento estructurado |
| Agentes de contenido | Generan cursos, ejercicios, evaluaciones a partir del conocimiento |
| Agentes de tutoría | Guían a los aprendices por el contenido, adaptan el ritmo y responden preguntas bajo demanda — recuperan de la capa de conocimiento (RAG) contextualizado con el progreso del aprendiz |
Lo que sabemos por la investigación:
- La autoridad entre agentes sigue un modelo de mandato, no de propiedad (investigación sobre coordinación multiagente). Un agente actúa en nombre de alguien, con un propósito específico, con límites definidos. Cuando sirve a varios usuarios, sus permisos son la intersección de todos los mandatos activos.
- El aislamiento entre agentes permite una verificación fiable. Si el revisor y el autor no comparten contexto, las tasas de error se multiplican (verificación independiente).
Orquestación: LangGraph gestiona las máquinas de estados y transiciones de los agentes. Cada tipo de agente es un grafo con nodos y aristas definidos.
(abierto) Comunicación entre agentes. Cómo se pasan los resultados entre sí los agentes — traspaso de estado directo, memoria compartida, cola de mensajes.
(abierto) Implementación de mandatos. El concepto de mandato está claro (principal, agente, objetivo, permisos, límites) pero la representación en tiempo de ejecución y el mecanismo de cumplimiento todavía no están definidos.
4. Capa de interfaz
Cómo llega el contenido al aprendiz. Tres niveles de generación, usados donde corresponde:
| Nivel | Cómo | Cuándo usarlo |
|---|---|---|
| 1 — Estático | Componentes React preconstruidos, el agente envía datos | Login, ajustes, navegación, pantallas de admin |
| 2 — Declarativo | El agente emite una especificación compacta (A2TL-Web), el renderizador la expande a HTML | Dashboards, listados de cursos, informes, vistas de progreso |
| 3 — Generativo | El agente escribe HTML/CSS/JS completo | Lecciones personalizadas, tutoría adaptativa, respuestas de agente |
La mayor parte de SkillNet es de Nivel 1 y 2. El Nivel 3 se aplica solo donde el contenido, el contexto y la variabilidad del usuario son todos altos — los momentos en que las pantallas prediseñadas no son viables.
Lo que existe:
- Renderizador A2TL-Web — implementación de Nivel 2. Ahorro del 76% de tokens frente a HTML equivalente.
Latencia del Nivel 3: ya no está diferida, y es menor de lo que se asumía. v2 (cursos dinámicos) es la implementación de Nivel 3, y su latencia de generación se ha medido contra Groq real (2026-07-27): de menos de un segundo a ~3 s por render, ~0.0008 USD por render. El problema de “generación de 20-30 segundos” que esta sección se escribió para preocuparse no existe en esta pila — las cifras de 60-150 s de la investigación provenían de un modelo de 7B en CPU local.
El enfoque implementado combina esqueleto + streaming SSE con generación anticipatoria acotada. Al abrir
el curso se preparan las dos primeras lecciones disponibles; una vez que empieza el aprendizaje, el cliente mantiene
una ventana móvil de tres lecciones por delante. Son renders en tiempo de ejecución creados con el contexto actual
del aprendiz y cacheados de forma idempotente, no artefactos de presentación horneados en el curso publicado. Ver
learning-experience-architecture.md §2.1 y
v2-dynamic-courses.md §9 para el modelo de latencia.
Nótese también que el Nivel 3 tal como está construido no inyecta HTML generado por el agente: el modelo emite un dialecto tipado que se parsea a un UISpec, se reserializa, y se renderiza mediante componentes React nativos. Nunca HTML, así que el aislamiento shadow-DOM/iframe contemplado abajo no es necesario.
Arquitectura de frontend: una sola SPA. Una aplicación React con React Router. El Nivel 1 (estático) son componentes React normales. El Nivel 2 (declarativo) usa un componente renderizador que toma una especificación compacta y la pinta — el formato concreto (A2TL-Web u otro) no está fijado. El Nivel 3 (generativo) inyecta HTML generado por el agente en un contenedor aislado (shadow DOM o iframe) para evitar conflictos de CSS. El usuario no sabe qué nivel está viendo — la navegación es igual en todas partes.
Enrutamiento: rutas fijas con contenido dinámico. Cada pantalla tiene una URL predecible. Las rutas están en español, siguiendo el código (apps/skillnet-web/src/App.tsx): /empleado, /empleado/curso/:id, /empleado/curso/:id/nodo/:nodeId, /admin/empleados, /admin/curso/:id/esquema. La lista completa está en screens.md. Las URLs son compartibles y el avance/retroceso del navegador funciona. Cuando el Nivel 3 genera contenido, se renderiza dentro de la ruta fija — la URL no cambia, solo lo que hay dentro.
Gestión de estado: React Query (TanStack Query). El estado del servidor (cursos, progreso, skills, ejercicios) se obtiene y cachea con React Query — el backend es la única fuente de verdad. El estado local de UI (barra lateral abierta, filtro activo, modal visible) usa useState normal. No se necesita un store global. Si surge un caso más adelante, Zustand puede añadirse en minutos.
5. API
FastAPI sirve como la interfaz entre el frontend y el backend.
Estilo de API: REST pragmático. CRUD estándar para recursos de datos (GET/POST/PUT/DELETE /api/v1/courses) más endpoints de acción explícitos para operaciones (POST /courses/{id}/generate, POST /courses/{id}/publish, POST /exercises/{id}/attempt). Ni GraphQL, ni REST puro. Las rutas dicen lo que hacen.
(abierto) Detalles del contrato de la API. Endpoints concretos, esquemas de petición/respuesta, versionado.
Autenticación: cookies de sesión vía fastapi-users. El login envía email + contraseña, el backend crea una sesión en PostgreSQL y devuelve una cookie httpOnly (caducidad de 7 días). El navegador envía la cookie automáticamente en cada petición — sin gestión de tokens en el código de frontend. Cada dispositivo obtiene su propia sesión independiente. La creación de cuentas es solo para admins por defecto (el admin crea empleados desde el panel); el autorregistro puede habilitarse por despliegue como un flag de configuración. Construido sobre CookieTransport de fastapi-users.
Tiempo real: SSE (Server-Sent Events). Las respuestas del agente se transmiten token a token vía StreamingResponse en FastAPI. Unidireccional (servidor → cliente). El usuario envía una pregunta como un POST normal, luego abre una conexión SSE para recibir la respuesta en streaming. Estándar para streaming de LLM (ChatGPT, Claude). No se necesita infraestructura WebSocket.
Multi-tenancy: no aplicable. SkillNet es autoalojado — una instancia por empresa, una base de datos, un Docker Compose. La tabla organizations existe para el ámbito de los datos pero tiene una sola fila por despliegue. Si el SaaS llega a ser una necesidad futura (post-beca), el esquema ya delimita por org_id, así que la seguridad a nivel de fila puede añadirse sin reestructurar.
6. Infraestructura
| Decisión | Dirección actual |
|---|---|
| Despliegue | Docker, autoalojable |
| Base de datos | PostgreSQL |
| Sin dependencia de proveedor | La funcionalidad principal debe funcionar sin ningún proveedor de nube específico |
Proveedor de LLM: elección del usuario. SkillNet no se ata a ningún proveedor. El usuario configura su propia clave de API y endpoint. Cualquier API compatible con OpenAI funciona directamente (OpenAI, DeepSeek, Groq, Together, local vía Ollama/LM Studio, etc.). El backend habla con una única interfaz — URL base + clave de API + nombre de modelo — definida en variables de entorno. Sin código específico de proveedor en la lógica de negocio.
Procesamiento en segundo plano: híbrido. Persistencia de LangGraph para el pipeline de generación (ya es un grafo, con checkpointing integrado, interrupt/resume) + un runner de trabajos respaldado por PostgreSQL para todo lo demás (cero dependencias nuevas, SELECT FOR UPDATE SKIP LOCKED). No se necesita Redis para el MVP. Diseño completo en background-processing.md.
Aspectos transversales
Modelo de control de acceso
Basado en la investigación de fronteras semánticas y coordinación multiagente:
Arranque ──→ Agente (contexto compartimentado) ──→ Frontera ──→ Salida
│ │
│ "qué puede ver" │ "qué puede emitir"
│ Filtro determinista por etiquetas │ Capa dura (escáner) + capa blanda (agente de aduanas)
El control nunca está dentro del agente. El agente opera libremente dentro de su contexto compartimentado. El cumplimiento es estructural.
Bucle de adaptación
El sistema se adapta a cada aprendiz:
El aprendiz completa un ejercicio ──→ Se registra el progreso
│
┌────────────┴────────────┐
│ │
La dificultad del contenido El formato del contenido
se ajusta al nivel se ajusta al aprendiz
(diferido) Señales de adaptación. Qué datos impulsan la personalización (solo puntuaciones, puntuaciones + tiempo, patrones de comportamiento completos). El modelo de datos ya captura puntuaciones y timestamps en exercise_attempts, así que cualquier enfoque puede implementarse más adelante sin cambios de esquema. Se decidirá cuando haya datos reales de usuarios que analizar.
Qué está decidido y qué está diferido
| Decidido | Diferido |
|---|---|
| PostgreSQL + pgvector (una sola BD) | Estructura del grafo de conocimiento |
| FastAPI, REST pragmático | Señales de adaptación |
| Cookies de sesión + fastapi-users | |
| SSE para streaming en tiempo real | |
| SPA React, React Router, rutas fijas | |
| React Query para gestión de estado | |
| LangGraph para orquestación de agentes | |
| Control de acceso basado en compartimentos | |
| Modelo de mandato para la autoridad del agente | |
| Autoalojado, una instancia por empresa | |
| Proveedor de LLM agnóstico (API compatible con OpenAI) | |
| Modelo de datos definido (data-model.md) | |
| Patrones de comunicación entre agentes (ver content-generation.md, chat-agents.md) | |
| Procesamiento en segundo plano (ver background-processing.md) | |
| Implementación de mandatos (ver security.md) | |
| Estrategia de chunking (ver rag-retrieval.md) | |
| Latencia de Nivel 3 (ver frontend-backend-integration.md) |