SPEC-MOODLE-MS · v1.0 Confidencial — Equipo de desarrollo
SPEC-MOODLE-MS · VERSIÓN 1.0 · 10 JUL 2026

Sistema distribuido de integración Moodle

Planeación y especificación técnica: API Gateway con autenticación JWT y tres microservicios (Usuarios, Calificaciones, Cursos) que consumen la REST API de Moodle.

EstadoBorrador para revisión del equipo
StackPython 3.12 · FastAPI · MySQL 8 · Docker / Kubernetes
AutenticaciónJWT propio (HS256 en dev, RS256 en prod), emitido por el Gateway
Sistema origenMoodle ≥ 4.1 con Web Services REST habilitados
AudienciaEquipo de desarrollo backend / DevOps

1. Resumen y alcance

Este documento define la arquitectura, los contratos REST, los modelos de datos, los flujos de autenticación, la estrategia de despliegue y el plan de trabajo para un sistema distribuido que expone la información académica de Moodle a servicios externos a través de una fachada REST propia.

Objetivos:

Fuera de alcance (v1): escritura de calificaciones hacia Moodle, mensajería/foros, SSO hacia la interfaz web de Moodle, multi-tenancy.

2. Arquitectura general

App móvil
Portal web
Servicios externos
│ HTTPS + JWT ▼
API Gateway :8000
Autenticación JWT · Enrutamiento · Rate limiting · CORS · Logging
MS Usuarios :8001
FastAPI · CRUD e identidad de usuarios
MySQL db_usuarios
MS Calificaciones :8002
FastAPI · Consulta y sincronización de notas
MySQL db_calif
MS Cursos :8003
FastAPI · Catálogo, contenidos e inscripciones
MySQL db_cursos
└──────────── REST (wstoken) ────────────┘
Moodle LMS
/webservice/rest/server.php · moodlewsrestformat=json
Fig. 1 — Vista de contexto: clientes → Gateway → microservicios (BD propia) → REST API de Moodle.

2.1 Principios de diseño

2.2 Decisiones técnicas

DecisiónJustificación
FastAPI + Uvicorn en los 4 serviciosTipado con Pydantic para contratos, OpenAPI generado automáticamente, soporte async para llamadas a Moodle sin bloquear.
MySQL 8 en cada servicioAlineado con la infraestructura existente de Moodle; una instancia lógica por servicio (esquemas o servidores separados).
JWT propio emitido por el GatewayLos clientes nunca ven el wstoken de Moodle; permite claims de rol propios y revocación mediante expiración corta + refresh.
SQLAlchemy 2 + AlembicORM async y migraciones versionadas por servicio.
httpx (async) como cliente MoodleTimeouts y reintentos configurables; se envuelve en un paquete interno moodle_client compartido.
Docker Compose (dev) / Kubernetes (prod)Paridad de entornos; escalado horizontal independiente por servicio.

3. API Gateway

Servicio FastAPI en el puerto :8000, único componente expuesto a Internet. Responsabilidades:

Prefijo públicoDestino internoAutenticación
POST /auth/loginGateway (local)Credenciales
POST /auth/refreshGateway (local)Refresh token
/api/v1/usuarios/**http://svc-usuarios:8001JWT requerido
/api/v1/calificaciones/**http://svc-calificaciones:8002JWT requerido
/api/v1/cursos/**http://svc-cursos:8003JWT requerido
GET /healthAgregado de los 3 serviciosPública

Los microservicios no validan JWT: confían en las cabeceras X-User-* porque solo son alcanzables desde la red interna (NetworkPolicy en K8s / red privada en Compose).

4. Microservicio Usuarios

Dominio: identidad y perfil de usuarios (alumnos, docentes, administradores). Fuente de verdad: Moodle (core_user_*).

4.1 Endpoints

EndpointDescripciónFunción Moodle
GET /api/v1/usuariosLista paginada; filtros ?q=, ?rol=, ?page=— (BD local)
GET /api/v1/usuarios/{id}Detalle de usuario— (BD local)
POST /api/v1/usuariosAlta; crea primero en Moodle, luego localcore_user_create_users
PUT /api/v1/usuarios/{id}Actualización de perfilcore_user_update_users
DELETE /api/v1/usuarios/{id}Baja lógica (suspende en Moodle)core_user_update_users
POST /api/v1/usuarios/syncSincronización total/incremental (solo rol admin)core_user_get_users

4.2 Modelo de datos — db_usuarios

ColumnaTipoNotas
idBIGINT PK AIIdentificador propio
moodle_idBIGINT UNIQUEId del usuario en Moodle
usernameVARCHAR(100) UNIQUEIgual al de Moodle
nombre, apellidosVARCHAR(120)
emailVARCHAR(255) UNIQUE
rolENUM('alumno','docente','admin')Mapeado desde roles de Moodle
activoTINYINT(1)Baja lógica
sincronizado_enDATETIMEÚltima sync con Moodle
creado_en, actualizado_enDATETIME

4.3 Contrato de ejemplo

POST /api/v1/usuarios            HTTP 201 Created
{                                {
  "username": "ana.perez",         "id": 412,
  "nombre": "Ana",                 "moodle_id": 5872,
  "apellidos": "Pérez",            "username": "ana.perez",
  "email": "[email protected]",          "rol": "alumno",
  "rol": "alumno"                  "activo": true,
}                                  "creado_en": "2026-07-10T09:14:02Z"
                                 }

5. Microservicio Calificaciones

Dominio: ítems de calificación y notas por curso/usuario. Solo lectura hacia los clientes en v1; la escritura de notas permanece en Moodle.

5.1 Endpoints

EndpointDescripciónFunción Moodle
GET /api/v1/calificaciones/usuario/{uid}Todas las notas del usuario, agrupadas por curso— (BD local)
GET /api/v1/calificaciones/curso/{cid}Notas del curso (solo docente/admin)— (BD local)
GET /api/v1/calificaciones/curso/{cid}/usuario/{uid}Desglose por ítem de un alumno en un curso— (BD local)
POST /api/v1/calificaciones/syncSincroniza por curso o global (admin)gradereport_user_get_grade_items

Si una lectura local tiene sincronizado_en más antiguo que el TTL configurado (default 15 min), el servicio dispara una re-sincronización del curso en segundo plano y responde con los datos locales más la cabecera X-Data-Stale: true.

5.2 Modelo de datos — db_calif

Tabla / columnaTipoNotas
item_calificacionÍtems evaluables por curso
· id, moodle_item_idBIGINTmoodle_item_id único
· curso_moodle_idBIGINT INDEXReferencia lógica (sin FK cruzada)
· nombre, tipoVARCHARtarea, examen, total…
· nota_maxima, pesoDECIMAL(10,2)
calificacionNota de un usuario en un ítem
· idBIGINT PK AI
· item_idBIGINT FKitem_calificacion.id
· usuario_moodle_idBIGINT INDEXReferencia lógica al MS Usuarios
· notaDECIMAL(10,2) NULLNULL = sin calificar
· retroalimentacionTEXT
· sincronizado_enDATETIME

6. Microservicio Cursos

Dominio: catálogo de cursos, estructura de contenidos e inscripciones.

6.1 Endpoints

EndpointDescripciónFunción Moodle
GET /api/v1/cursosCatálogo paginado; filtros ?categoria=, ?visible=— (BD local)
GET /api/v1/cursos/{id}Detalle del curso— (BD local)
GET /api/v1/cursos/{id}/contenidosSecciones y módulos del cursocore_course_get_contents*
POST /api/v1/cursosAlta de curso (admin)core_course_create_courses
PUT /api/v1/cursos/{id}Actualización (admin/docente)core_course_update_courses
POST /api/v1/cursos/{id}/inscripcionesInscribe un usuario con un rolenrol_manual_enrol_users
GET /api/v1/cursos/{id}/inscripcionesUsuarios inscritoscore_enrol_get_enrolled_users
POST /api/v1/cursos/syncSincronización del catálogo (admin)core_course_get_courses

* Los contenidos se cachean localmente 15 min; pasado el TTL se consulta Moodle en línea.

6.2 Modelo de datos — db_cursos

Tabla / columnaTipoNotas
curso
· id, moodle_idBIGINTmoodle_id único
· nombre_corto, nombre_completoVARCHAR
· categoriaVARCHAR(120)
· fecha_inicio, fecha_finDATE NULL
· visibleTINYINT(1)
· sincronizado_enDATETIME
inscripcion
· idBIGINT PK AI
· curso_idBIGINT FKcurso.id
· usuario_moodle_idBIGINT INDEXReferencia lógica al MS Usuarios
· rolENUM('alumno','docente')
· inscrito_enDATETIME

7. Autenticación y autorización (JWT)

7.1 Emisión

El Gateway valida credenciales contra el MS Usuarios (hash bcrypt local; opcionalmente delega a login/token.php de Moodle para validar la contraseña) y emite dos tokens:

TokenVigenciaUso
access_token15 minutosCabecera Authorization: Bearer … en cada request
refresh_token7 díasSolo válido en POST /auth/refresh; rotación en cada uso

7.2 Claims del access token

{
  "sub": "412",              // id interno del usuario
  "mid": 5872,               // moodle_id
  "rol": "alumno",           // alumno | docente | admin
  "iss": "gw.moodle-ms",
  "iat": 1783075200,
  "exp": 1783076100,
  "jti": "b4f1…"             // id único, para auditoría
}

7.3 Reglas de autorización

El wstoken de Moodle vive únicamente como secreto de cada microservicio (variable de entorno / K8s Secret) con una cuenta de servicio dedicada y permisos mínimos por servicio.

7.4 Diagrama de secuencia — login

Cliente
Gateway
MS Usuarios
1  Cliente ──▶ Gateway   POST /auth/login {username, password}
2  Gateway ──▶ Usuarios  GET /internal/credenciales?username=…
3  Usuarios ─▶ Gateway   200 {id, moodle_id, rol, password_hash}
4  Gateway    ⟲ verifica bcrypt · firma JWT (RS256)
5  Gateway ──▶ Cliente   200 {access_token, refresh_token, expira_en}
Fig. 2 — Autenticación y emisión de JWT.

7.5 Diagrama de secuencia — consulta de calificaciones con sync

Cliente
Gateway
MS Calificaciones
Moodle
1  Cliente ──▶ Gateway   GET /api/v1/calificaciones/usuario/412 + Bearer JWT
2  Gateway    ⟲ valida firma y exp · autoriza (sub == 412)
3  Gateway ──▶ Calif     proxy + X-User-Id: 412, X-User-Role: alumno
4  Calif      ⟲ lee BD local · detecta datos > TTL
5  Calif ───▶ Moodle    gradereport_user_get_grade_items (wstoken, async)
6  Moodle ──▶ Calif     200 JSON → upsert en db_calif
7  Calif ───▶ Cliente    200 notas (vía Gateway) · X-Data-Stale si aplica
Fig. 3 — Lectura con re-sincronización perezosa contra Moodle.

8. Integración con Moodle y manejo de errores

9. Estrategia de despliegue

9.1 Desarrollo — Docker Compose

ServicioImagenPuertoNotas
gatewaybuild local8000:8000Único puerto publicado al host
svc-usuariosbuild localinterno 8001Red privada backend
svc-calificacionesbuild localinterno 8002
svc-cursosbuild localinterno 8003
mysql-usuarios / -calif / -cursosmysql:8internos 3306Un contenedor por servicio + volumen
moodle (opcional)bitnami/moodle8080Entorno de pruebas local

9.2 Producción — Kubernetes

10. Plan de trabajo

FaseEntregableDuraciónCriterio de salida
F0Setup: repos, Compose base, Moodle de pruebas con WS habilitados, CI1 semanadocker compose up levanta el esqueleto de los 4 servicios
F1Gateway: auth JWT, routing, rate limiting2 semanasLogin + proxy a un servicio stub con tests e2e
F2MS Usuarios: CRUD + sync con core_user_*2 semanasAlta de usuario visible en Moodle; sync incremental probada
F3MS Cursos: catálogo, contenidos, inscripciones2 semanasInscripción vía API reflejada en Moodle
F4MS Calificaciones: lectura + sync perezosa + circuit breaker2 semanasNotas consistentes con el gradebook de Moodle
F5Integración: pruebas e2e, carga (k6), hardening de seguridad2 semanasP95 < 300 ms en lecturas locales; auditoría de auth
F6Despliegue a producción: manifiestos K8s, observabilidad, runbook1 semanaSistema en prod con alertas y documentación operativa

Total estimado: 12 semanas con un equipo de 2–3 desarrolladores backend + 1 DevOps parcial.

10.1 Riesgos principales

RiesgoImpactoMitigación
Límites de tasa / rendimiento de la WS API de MoodleAltoRéplica local + sync perezosa; sync masiva en horario valle
Cambios de contrato entre versiones de MoodleMedioAislar todo en moodle_client; tests de contrato contra el Moodle de staging
Inconsistencia local ↔ Moodle en escriturasAltoWrite-through estricto + job de reconciliación nocturno
Filtración del wstokenAltoCuentas de servicio con permisos mínimos por microservicio; rotación trimestral
Deriva de esquemas entre serviciosBajoContratos OpenAPI versionados y validados en CI