Repositorio del plugin mod_exelearning (Moodle 4.5 LTS → 5.x). Fase actual:
plugin funcional end-to-end — instala, extrae .elpx, sirve con sidebar nativa,
guarda calificaciones en gradebook vía SCORM 1.2 bridge → track.php → grade_update
multi-itemnumber. Demo Docker + Moodle Playground operativos.
Reglas operativas de investigación: research/AGENTS.md
(append-only, evidencia citable, español, no vendorar externos).
[ACTUALIZACION 2026-06-17] El plugin es STABLE (DEC-0057, PR 77). El "snapshot" original era de 2026-05-28; el detalle de abajo es histórico (se mantiene por trazabilidad). El estado canónico vivo es el código +
docs/ARCHITECTURE.md+ el índice completo de decisionesresearch/docs/indices/adrs.yaml(DEC-0001..0063). La tabla "Decisiones clave" de más abajo solo llega hasta DEC-0050.
- Esqueleto plugin + multi-grade-items (
classes/grades/gradeitems.php, MAX=100). - Parser
content.xml(classes/local/package.php,GRADABLE_IDEVICE_TYPES×20). - Bridge SCORM 1.2:
view.phpshim +exelearning_inject_scorm_loader(pipwerks auto-init en<head>) +track.phpcon parseo decmi.suspend_data(regex^(\d+)\. "([^"]*)"; [^:]+: ([\d.]+)%; [^:]+: ([\d.]+)%). - Modos preview/grading (DEC-0006, verificado).
- Intentos (DEC-0007, Aceptada): tabla
exelearning_attempt+ agregacióngrademethod(highest/average/first/last/lowest) enclasses/local/attempts.phpreport.php+ privacy provider + backup/restore. Agrupación porsessiontoken(1 intento por carga de página). Verificado en Docker.
- Finalización estilo SCORM (DEC-0010, Aceptada):
gradepass+ condición corecompletionpassgrade("aprobar para completar").track.phprefuerzacompletion->update_statetras grabar nota. - Self-heal de subidas programáticas:
view.phpre-extrae el paquete y re-detecta iDevices si faltan (arregla eladdModuledel Playground, que no pasa porexelearning_add_instance).exelearning_extract_stored_package()separada para reusarla sin draft. Verificado. - Editor embebido portado de
mod_exeweb(instalador GitHub + external API). - Demo seeder idempotente (
scripts/setup_demo.php) con 3 actividades evaluables (exelearning +mod_scorm+mod_h5pactivity, todas con finalización por aprobado) +blueprint.json(Playground). Verificado. - Docker compose
erseco/alpine-moodle:v5.0.7+ MariaDB. - Icono
pix/monologo.svg(X sin hamburguesa). - README estilo
mod_exeweb, dependabot, composer.json.
- TAREA-016 / DEC-0033 (Propuesta → impl): reemplazo visible del paquete + origen
por URL con sincronización (patrón
mod_scorm:packagesource+ columnareference+create_file_from_url+ gating porcontenthash+curl_security_helper+ adminallowexternalurlopt-in) + botón "Actualizar ahora" (Fase 1);updatefreq+db/tasks.php- token REST eXe v4 (Fase 2 opcional). El reemplazo YA funciona vía
update_instance.
- token REST eXe v4 (Fase 2 opcional). El reemplazo YA funciona vía
- TAREA-015 / DEC-0032 (Propuesta → impl): ingesta xAPI dual (listener AMD + endpoint + normalizador) reutilizando la tubería existente; gated a que el PR upstream #1867 congele el contrato.
- Auditorías de cumplimiento: licencias, privacidad y accesibilidad.
- TAREA-013 / RIE-001 (M8): investigar sandboxing de JS en cliente (ShadowRealm, SES/
Compartments, Web Worker + DOM proxy, QuickJS-WASM, librerías tipo
sandboxjs) como mitigación que mantiene el servido same-origin. Ver DEC-0019 (M8). - (Futuro, documentado, sin priorizar) RIE-001 hardening del
.elpx: roadmap en DEC-0019 — Tier 1 (Permissions-Policy + CSP estricto-con-toggle + quitarallow-popups-to-escape-sandbox) → Tier 2 (bridgepostMessage→ origen opaco/subdominio).
Cerradas: TAREA-012 / RIE-001 investigación (DEC-0019); TAREA-009 / RIE-011
maxattempt aceptado por paridad con core (DEC-0018, commit f6e8ec8).
- DEC-0008
grademodel(selector peritem [default] / overall; modo both eliminado en rev. 2026-05-29). - DEC-0007 fase 2:
maxattempt+reviewmode+ borrar intento enreport.php(capmod/exelearning:deleteattempt) + recálculoexelearning_recalculate_user_grades. - Editor embebido inline en settings + estilos definidos portados de
exelearning/mod_exeweb(DEC-0009: sin modo online). Página rota eliminada. - CI
ci.ymlcon matriz moodle-plugin-ci (DEC-0004).
- Detección por
isScorm(DEC-0022):package.phpdetecta calificables por el flagisScorm>0del iDevice (no por lista de tipos) → resuelve issue #13 #2 (solo marcados) y #5 (10 tipos nuevos) a la vez.track.phpsin cambios (enruta porobjectid). - Crear desde cero (DEC-0024):
packageopcional enmod_form.php;view.phpmuestra CTA de edición en vez de error; el editor embebido crea proyecto nuevo (issue #13 #1). - Deep-link gradebook (DEC-0023): nuevo
grade.phpmapeaitemnumber→objectidy redirige aview.php?idevice=…(ancla nativa); helperexelearning_grade_item_view_url()(issue #13 #4). - UI (DEC-0024): botón "Editar con eXe" a la derecha + botón pantalla completa;
amd/src/fullscreen.jsreescrito (ES6, Fullscreen API sobre el iframe) (issue #13 #6). - Migración masiva (DEC-0026, reescribe DEC-0025; PR stacked): herramienta en Ajustes
(
admin/migrate.php, capmod/exelearning:migrate) que copia TODAS las actividadesmod_exeweb/mod_exescormdel sitio a nuevas actividades eXeLearning (add_moduleinfo), con barra de progreso y avisos; no destructiva; exescorm→calificación general; idempotente (tablaexelearning_migration). Motorimport_service::import_packagereutilizado de DEC-0025 (issue #13 #3). Completa el issue #13.
- Ingesta dual SCORM 1.2 + xAPI (DEC-0032, Propuesta): PR1 documental; xAPI ingiere
reutilizando la tubería existente (
exelearning_attempt+objectid→itemnumber). Implementación → TAREA-015. - Actualización de contenido (DEC-0033, Propuesta): el reemplazo del
.elpxYA está soportado porexelearning_update_instance(revision++, re-extrae, re-sync, aviso de notas obsoletas DEC-0021). Para origen por URL se descarta el file picker URL de Moodle (repository_urlse oculta para.zip/.elpxy haría copia única sin sync) y se adopta el patrónmod_scorm(packagesource+reference+create_file_from_url+updatefreq), añadiendo un botón "Actualizar ahora" (lo que amod_scormle falta). eXe v4 no tiene permalink público (export REST con Bearer JWT, sin versionado). Implementación → TAREA-016.
- Categoría de calificación (DEC-0034, Aceptada): columna
exelearning.gradecat+ selector estándar (gradecategoryonmodform+grade_get_categories_menu) aplicado a TODOS los grade items víagrade_item::set_parent(grade_updateignoracategoryid, FTE-012) enexelearning_apply_grade_category. Petición usabilidad INTEF #1. - Visibilidad de notas del alumno (DEC-0035, Aceptada): en
peritemel overall oculto seguía agregando → Moodle vaciaba el total del alumno (defaultgrade_report_user_showtotalsifcontainhidden=0). Fix: excluir la nota overall de la agregación congrade_grade::set_excluded(exelearning_exclude_overall_gradedesdetrack.phpyexelearning_recalculate_user_grades) + migración enupgrade.php(stage2026060401).get_hiding_affectedsalta las excluidas → total visible;finalgrade/gradepassintactos (completion OK). Petición usabilidad INTEF #2. Verificado en Docker (Moodle 5.0.7):COURSE TOTAL blanked_by_hidden=NO.
- Parser
content.xmlhíbrido (DEC-0039):classes/local/package.phppasa aDOMDocumentporlocal-name()para la estructura (robusto a namespaces/entidades/ CDATA/orden de atributos); se reutilizan intactosextract_isscorm/decrypt_datagame/hash_idevice_block; fallback al escáner regex (detect_gradable_idevices_regex) con log si el XML está malformado. Bug crítico cazado por fixtures reales: los.elpxdeclaran<!DOCTYPE ode SYSTEM "content.dtd">→ se acepta el DTD externo (LIBXML_NONETsinDTDLOAD/NOENT) y solo se rechazan entidades internas. 22 tests. - Mobile/External API (DEC-0040): 6 funciones en
classes/external/registradas enMOODLE_OFFICIAL_MOBILE_SERVICE;save_trackreusa la nuevatrack::ingest()(extraída detrack.php) con salvaguardas server-side (objectid routing, recálculo overall, filtro deitemscoresa objectids registrados). 14 tests. - Eventos (DEC-0041):
attempt_deleted+report_viewed+course_module_instance_list_viewed. - Test roundtrip backup/restore (P2). Suite completa 99/99 verde,
phpcs --standard=moodle0/0. version.phpintacto (centinela DEC-0030). README con sección "Web services (Mobile API)".
| ADR | Estado | Resumen |
|---|---|---|
| DEC-0001 | Aceptada | Metodología evidencia + ADRs |
| DEC-0002 | Aceptada | Política clones externos (no vendorar) |
| DEC-0003 | Aceptada (2026-05-29) | SCORM 1.2 estándar de tracking vigente y suficiente; xAPI sólo hoja de ruta |
| DEC-0004 | Aceptada (2026-05-29) | CI matriz Moodle 4.5/5.0/5.1/5.2 × PHP 8.1-8.4 × pgsql/mariadb; version.php soporta Moodle [405, 502] |
| DEC-0005 | Superseded by DEC-0009 | Editor embebido (versión con online) |
| DEC-0006 | Aceptada | Modos preview/grading |
| DEC-0007 | Aceptada | Intentos: tabla plana exelearning_attempt + grademethod (implementado) |
| DEC-0008 | Aceptada (rev. 2026-05-29) | Selector grademodel peritem (default) / overall; modo both eliminado |
| DEC-0009 | Aceptada | Sólo editor embebido; eliminado eXeLearning Online / hmac |
| DEC-0010 | Aceptada | Finalización estilo SCORM = core completionpassgrade + gradepass |
| DEC-0011 | Aceptada | Presentación intentos en portada: resumen profesor (Tarea) + línea alumno; detalle en Informes |
| DEC-0012 | Aceptada | editor/save.php re-extrae + re-sincroniza libro tras guardar (RIE-006: estabilidad objectid) |
| DEC-0013 | Aceptada | Editor Online vs embebido: confirma solo-embebido (DEC-0009); reapertura futura iría por opción D (enlace, sin HMAC) |
| DEC-0014 | Aceptada (2026-05-29) | Soporte xAPI A+C: SCORM 1.2 vigente + diseño de referencia; sin empuje upstream (analítica LRS no prioritaria) |
| DEC-0015 | Aceptada (2026-05-29) | Justificación de la multicalificación: DAFO + comparativa (exeweb/exescorm/scorm/h5p); veredicto: merece la pena con matices (deuda = shim SCORM, hoja de ruta = xAPI DEC-0014) |
| DEC-0016 | Aceptada (2026-06-01) | Auditoría de seguridad multi-agente: 21 hallazgos (18 corregidos, 3 diferidos) |
| DEC-0017 | Aceptada (2026-06-01) | Ruteo de calificaciones por objectid estable (mis-ruteo N→itemnumber, RIE-007) |
| DEC-0018 | Aceptada (2026-06-01) | Recálculo del overall desde itemscores (cierre RIE-007) + hardening menor |
| DEC-0019 | Aceptada (2026-06-02) | Aislamiento del .elpx (RIE-001): análisis, paridad con core y roadmap (NO implementado por decisión) |
| DEC-0020 | Aceptada (2026-06-02) | Traducciones es/ca/eu/gl: reuso de hermanos + marca «~» para auto-traducción pendiente de revisión |
| DEC-0021 | Aceptada (2026-06-02) | Edición de contenido calificable: semántica snapshot + aviso al profesor (estilo SCORM) |
| DEC-0022 | Aceptada (2026-06-03) | Detección de calificables por isScorm>0 (no por lista de tipos) → issue #13 #2 y #5 |
| DEC-0023 | Aceptada (2026-06-03) | Deep-link del gradebook al iDevice vía grade.php (itemnumber→objectid→ancla) → issue #13 #4 |
| DEC-0024 | Aceptada (2026-06-03) | Crear .elpx desde cero (paquete opcional) + pantalla completa → issue #13 #1 y #6 |
| DEC-0025 | Superseded by DEC-0026 | Importar por-actividad desde mod_exeweb/mod_exescorm (motor reutilizado por DEC-0026) |
| DEC-0026 | Aceptada (2026-06-03) | Migración masiva desde Ajustes (admin, site-wide, no destructiva, progreso, exescorm→nota general) → issue #13 #3 |
| DEC-0027 | Aceptada (2026-06-03) | Aceptar .zip (con content.xml) además de .elpx en la subida |
| DEC-0028 | Aceptada (2026-06-03) | Enlaces del gradebook: análisis y destino del 'grade analysis' → issue #13 #4 |
| DEC-0029 | Aceptada (2026-06-03) | Interruptor 'Calificable' por actividad (gradeenabled) → issue #13 |
| DEC-0030 | Aceptada (2026-06-03) | Versión 'sentinela' (9999999999/dev) en main; la real la inyecta make package |
| DEC-0031 | Aceptada (2026-06-03) | Separar el formulario en 'Grading' y 'Attempts management' → issue #13 |
| DEC-0032 | Propuesta (2026-06-04) | Ingesta dual de tracking: shim SCORM 1.2 + xAPI (exe_xapi.js) sobre tubería común → TAREA-015 |
| DEC-0033 | Propuesta (2026-06-04) | Actualización de contenido: reemplazo del .elpx + origen por URL con sincronización (patrón mod_scorm) → TAREA-016 |
| DEC-0034 | Aceptada (2026-06-04) | Selector de categoría de calificación (gradecat) aplicado a todos los grade items vía grade_item::set_parent (grade_update ignora categoryid) → petición usabilidad INTEF #1 |
| DEC-0035 | Aceptada (2026-06-04) | Coherencia profesor/alumno en peritem: excluir la nota overall oculta de la agregación (grade_grade::set_excluded) para que Moodle no vacíe el total del alumno → petición usabilidad INTEF #2 |
| DEC-0036 | Aceptada (2026-06-08) | contenttype_exelearning (banco de contenidos, REPO-006) como plugin separado; mirroring intencional de extracción/sandbox .elpx (RIE-013) |
| DEC-0037 | Aceptada (2026-06-08) | Detección de isScorm también en el div *-DataGame cifrado (unescape + XOR 146) → issue #13 "solo 12 de 30 detectados" |
| DEC-0038 | Aceptada (2026-06-08) | Sin columna overall oculta en peritem: completion estilo workshop sobre un item por-iDevice (supersede de DEC-0035) |
| DEC-0039 | Aceptada (2026-06-09) | Parser content.xml híbrido: DOMDocument por local-name() para la estructura + descifrado/hash conservados + fallback regex; acepta <!DOCTYPE SYSTEM> externo, rechaza entidades internas |
| DEC-0040 | Aceptada (2026-06-09) | API externa/móvil: 6 funciones en MOODLE_OFFICIAL_MOBILE_SERVICE (incl. save_track reusando track::ingest() con salvaguardas server-side) |
| DEC-0041 | Aceptada (2026-06-09) | Eventos selectivos: attempt_deleted + report_viewed + course_module_instance_list_viewed (sin evento por commit de tracking, sería ruido) |
| DEC-0042 | Aceptada (2026-06-09) | Parchear al servir el guard de guardado de form/scrambled-list (quitar body.exe-scorm) → issue #13 "form/scrambled reportan 0" |
| DEC-0043 | Aceptada (2026-06-10) | Detectar GeoGebra calificable por la clase auto-geogebra-scorm (issue #29, PR #30) |
| DEC-0044 | Aceptada (2026-06-10) | Auditoría de bugs críticos (workflow multi-agente, 9 confirmados + 2 rechazados): B1 destrucción de paquete, B2/B2b pérdida de notas + update_grades, B3 items fantasma, B5 clamp DML, B6 save_track 0-score, B7 finalización por nota, B8 XSS informe; BETA tras críticos |
| DEC-0045 | Propuesta (2026-06-10) | Transformación del paquete en tiempo de servido (content_transformer + pluginfile): elimina la reescritura del HTML en extracción (deuda nº1 del informe); diferida, salida definitiva es xAPI DEC-0032 |
| DEC-0046 | Aceptada (2026-06-10) | Inyecciones SCORM-loader (inject_scorm_loader) y teacher-mode (require_teacher_mode_hider): análisis plugin vs upstream eXeLearning (ventajas/inconvenientes); híbrido = fix plugin-side DEC-0045 (amplía alcance al teacher-mode) + opción upstream documentada (sin abrir issues); conservar workaround para .elpx heredados |
| DEC-0047 | Aceptada (2026-06-11) | Clasificación funcional: mantener MOD_ARCHETYPE_ASSIGNMENT + MOD_PURPOSE_ASSESSMENT (sin cambio de código); supports() no ve la instancia → el archetype/purpose no puede variar por gradeenabled (DEC-0029); gradeenabled=0 es "modo recurso" dentro de un módulo evaluable. Cierra la observación del informe comparativo (docs/AUDIT_FOLLOWUP.md) |
| DEC-0048 | Aceptada (2026-06-12) | Estrategia de cobertura de tests: mockear la red con \curl::mock_response() + mock parcial de download_to_temp() en vez de excluir; no excluir del scope código testeable (excludelistfiles vacío); xdebug/Codecov es la medida autoritativa (pcov local subacredita llamadas anidadas — artefacto, no límite); gate codecov project: target: auto (trinquete). Cobertura honesta 85.71%→87.2% (PR #65) |
| DEC-0049 | Aceptada (2026-06-12) | Auditoría estándar de repositorio (2026-06-11, tras DEC-0016/DEC-0044): 9 mejoras P1–P3 implementadas (PRs #46–#54: hardening XML de estilos, thirdpartylibs en el ZIP, fidelidad backup/restore, lock de intentos, participación vs grademethod, recálculo de notas en lote, zip_utils, descarga del informe, Behat) + registro de hallazgos descartados y opciones de dirección para no re-auditar |
| DEC-0050 | Aceptada (2026-06-12) | La herramienta de migración exeweb/exescorm vive en mod_exelearning (destino, dueño de los internals); orígenes como fuentes legacy de solo lectura tras source_interface. Endurecimiento de la rama issue #13: fix mod_exeweb itemid=revision (antes leía 0 → todo nosource); clasificación mod_exescorm (.elpx directo / 1 embebido / 0=nosource / >1=ambiguous / external+aiccurl+localsync=unsupported, localsync excluido por sincronización aunque tenga snapshot local); limpieza compensatoria con course_delete_module ante fallo parcial (sin transacción, caveat recycle bin); preservación de metadatos del cm (idnumber nunca se copia); validación post-extracción anti shell-vacío (migrateextractfailed); eventos (started/migrated/skipped/failed, patrón DEC-0041); columnas userid/timemodified (upgrade 2026061201); preflight + \core\progress\display. Refactor a classes/local/migration/ (elimina import_service). CLI diferido |
| DEC-0051..0063 | (varias, 2026-06-12 → 2026-06-17) | Ver índice completo en research/docs/indices/adrs.yaml. Resumen: DEC-0051 eventos selectivos · DEC-0052 completion por estado · DEC-0053 búsqueda global · DEC-0054 refactor lib.php (extracción a clases) · DEC-0055 auditoría post-refactor · DEC-0056 tests JS (Vitest) · DEC-0057 extracción no-destructiva (BETA→STABLE) · DEC-0058 fijar tag del editor en release · DEC-0063 validación canónica del endpoint xAPI + política de versión (1.0.3 tolerante a 2.0). (DEC-0059..0062 = iframe seguro en rama feature/secure-iframe-scorm-bridge, aún no en main.) |
- Sólo paquete v4 ODE 2.0 (con
content.xml), aceptado como.elpxo.zip(DEC-0027). NO.elplegacy, NOiteexe_online. - NO vendorar repos externos.
- NO integración eXeLearning Online (DEC-0009): no tocar
editormode,exeonlinebaseuri,hmackey1,APP_SECRET,EXELEARNING_WEB_*. - Sidebar nativa siempre preservada (técnica iframe de
mod_exeweb). - Repo público:
github.com/exelearning/mod_exelearning. - Organización: ATE = Área de Tecnología Educativa (no "Asistencia Técnica").
itemnumber_mapping: Moodle 5 itera el mapeo entero → requiere stringsgrade_overall_name+grade_idevice1..100_nameenlang/en/exelearning.php(loop generado, MAX=100 porquetest22.elpxtenía 29 iDevices).- Pipwerks lazy: eXeLearning v4 sólo llama
pipwerks.SCORM.init()si lo inyectamos manualmente en el<head>de cada HTML (exelearning_inject_scorm_loader). lesson_status=passed: NO ponerlo en feedback (no es estándar; ya eliminado).enrol_manual->add_default_instance: falla enerseco/alpine-moodle:v5.0.7por defaults globales ausentes → usaradd_instance($course, [...status => ENROL_INSTANCE_ENABLED...])explícito.forum_announcementsubscriptionundefined: workaround ensetup_demo.phpsetea$CFG->forum_announcementsubscription=1yforum_announcementmaxattachments=9antes decreate_course.- Blueprint Playground:
setLandingPagerequiere?id=N, NO?shortname=. monologo.svg: viewBox0 0 78 78, X ocupa todo, sin hamburguesa. Moodle 4+ prefiere SVG → no recrear PNGs.- Sandbox iframe:
allow-scripts allow-same-origin allow-popups allow-forms allow-popups-to-escape-sandbox(sinallow-top-navigationniallow-modals). - Switch-to-student: en modo grading silencioso, no romper.
- SIEMPRE añadir tests con cada cambio. Todo cambio de comportamiento (feature,
fix, refactor) DEBE llegar con tests unitarios que cubran el caso feliz y los
bordes/regresiones (p.ej. fallo de extracción que preserva el estado previo). PHP →
PHPUnit en
tests/(junto a@covers); JS → Vitest entests/js/. Preferir TDD donde sea unit-testable. Correr localmente conmake test ARGS=mod/exelearning/tests/<archivo>.php(varios archivos separados por espacio; no apuntar al directorio entero —elvendor/phpunitdel plugin colisiona) ymake test-js. Si el entorno PHPUnit dice "initialised for different version", ejecutardocker compose exec moodle php /var/www/html/admin/tool/phpunit/cli/init.php. NOTA: los tests del editor embebido (embedded_editor_installer_test,manage_embedded_editor_test) extraen un tarball-fixture que corrompe/etc/passwddel contenedor (openat etc/passwd) — si pasa,docker compose up -d --force-recreate moodley re-init; correrlos aislados. - Comentarios de código en INGLÉS. Todo
.php/.jsdel plugin. La carpetaresearch/(ADRs, fichas, diario, notas) va en español. Las librerías de terceros vendoradas (assets/scorm/*, wrappers SCORM/pipwerks) no se tocan. - Documentar cada funcionalidad en el código fuente con base en la
investigación (en inglés): cada función/área no trivial lleva un docblock que
explica qué hace y por qué, citando la decisión/fuente que la justifica
(p.ej.
(DEC-0008),(see FTE-006),(RIE-006)). El "porqué" vive junto al código, no solo enresearch/. phpcs --standard=moodledebe quedar limpio (0/0). Validar SIEMPRE convendor/bin/phpcs --standard=moodle <archivos>, NO con el ruleset local.phpcs.xml.dist(enmascara errores que la CI sí detecta).- PHPDoc completo (
moodle-plugin-ci phpdoc):@param/@returnen cada función. - AMD: tras tocar
amd/src/*.jshay que regeneraramd/build/con elgrunt amdde Moodle (rollup), no a mano. - Tests JS (DEC-0056): el tracker SCORM crítico para notas vive en
js/scorm_tracker.js(fuente única;view.phplo inyecta inline para mantenerwindow.APIsíncrono antes del iframe). Se testea con Vitest entests/js/(make test-js), NO con el Jest de Moodle (solo ESM). La UI (amd/src/fullscreen.js,resize.js, …) y los wrappers pipwerks (assets/scorm/*) quedan fuera de alcance. La cobertura sube a Codecov bajo el flagjavascript(jobjsunit). lang/en/exelearning.php: strings en orden alfabético ESTRICTO por clave, sin código (for/variables) —moodle.Files.LangFilesOrderinglo rechaza.
mod_exelearning/
├── lib.php # API pública + sync_grade_items + update_grades + inject_scorm_loader
├── view.php # iframe + SCORM 1.2 shim (autocommit 500ms)
├── track.php # AJAX endpoint (sesskey + mode preview/grading)
├── mod_form.php
├── settings.php # 1 toggle (embeddededitor) + link a manage page
├── manage_embedded_editor.php # Página admin (instalar/borrar/actualizar editor)
├── editor/index.php # Página bootstrap del editor embebido por actividad
├── classes/
│ ├── grades/gradeitems.php # itemnumber_mapping (MAX 100)
│ ├── local/package.php # Parser content.xml
│ └── event/course_module_viewed.php
├── db/{install.xml,access.php,upgrade.php}
├── lang/en/exelearning.php
├── pix/ # monologo.svg (sin hamburguesa)
├── scripts/setup_demo.php # Idempotente
├── dist/static/ # Editor embebido (build de exelearning v4)
├── blueprint.json # Playground (?id=2)
├── docker-compose.yml # erseco/alpine-moodle:v5.0.7
├── .env.dist
├── composer.json # require-dev: moodlehq/moodle-cs, phpmd, phpunit
├── .github/dependabot.yml
└── research/ # ADRs, fuentes, fixtures (append-only)
The .agents/skills/ directory contains Claude Code project skills — reusable prompt workflows invoked with /skill-name in the Claude Code CLI. They are development tooling only and are excluded from release packages (covered by the .* rule in .distignore).
| Skill | File | Purpose |
|---|---|---|
changelog |
.agents/skills/changelog/SKILL.md |
Draft a CHANGELOG entry from merged GitHub PRs since the last release |
docker compose up -d && docker compose logs -f moodle
docker compose exec moodle php /var/www/html/mod/exelearning/scripts/setup_demo.php
python3 research/tools/build_indexes.py
python3 research/tools/test_schema_validation.pyCredenciales demo: admin user/1234, teacher teacher_demo/Demo!2026,
estudiantes alumno1, alumno2/Demo!2026. Curso EXEDEMO (id=2).