Mapa de dependencias — línea base¶
Generado a partir del código (bin/convoca-inventario.py) y verificado a mano en los
puntos que se marcan como comprobado. Complementa al
inventario de funcionalidades.
1. Capas reales¶
┌──────────────────────────────┐
presentación │ theme (patrones, estilos) │
│ shortcodes y bloques │
└──────────────┬───────────────┘
│ hooks y options
dominio ┌──────────────┴───────────────┐
│ members enroll shifts │
│ courses publisher gateway │
└──────────────┬───────────────┘
│ \Convoca\Core\*
infraestructura ┌──────────────┴───────────────┐
│ core: Logger, Utils, Mailer, │
│ PDF, Upgrade, License, │
│ Webhook, Hour_Ledger, │
│ Module_Registry, Features │
└──────────────────────────────┘
gateway es un caso híbrido: por debajo es infraestructura de cobro (lo usan
enroll, members y courses), por arriba tiene su propio dominio (pagos, Redsys,
recibos). Se queda como plugin propio; lo que no debe crecer es su superficie de
infraestructura.
2. Dependencias declaradas (Requires Plugins)¶
| Plugin | Declara | Comprobado |
|---|---|---|
| core | — | — |
| enroll | convoca-core |
sí |
| members | convoca-core |
sí |
| gateway | convoca-core |
sí |
| shifts | convoca-core |
sí |
| publisher | convoca-core |
sí |
| courses | convoca-core |
sí |
| license-generator | convoca-core, woocommerce |
sí |
| assistant | nada | usa \Convoca\Core\Logger y \Convoca\Core\Utils |
| ext-gateway (demo) | nada | usa Convoca\Core, Gateway y Members; es una demo, no se distribuye |
| theme | — | depende de core vía hooks, sin cabecera |
Hallazgo D1: convoca-assistant no declara Requires Plugins: convoca-core pero
llama a \Convoca\Core\Utils::check_rate_limit() en REST_Controller sin guarda.
Con Core desactivado, esa ruta REST produce error fatal. Arreglo de una línea, sin
cambio de comportamiento.
3. Dependencias reales por código (quién usa qué de Core)¶
| Plugin | Clases de Convoca\Core que referencia |
|---|---|
| enroll | Admin, Email_Copy, Email_Layout, Event_Style_Registry, Features, Hour_Ledger, License_Manager, Logger, Mailer, Member_Identity, Signature, Upgrade_Manager, Utils, Webhook_Manager |
| members | Admin, Email_Copy, Email_Layout, Email_Links, Features, Installer, License_Manager, Logger, Notifications, Signature, Upgrade_Manager, Utils, Webhook_Manager |
| gateway | Admin, License_Manager, Logger, Mailer, Payments, Upgrade_Manager, Utils |
| shifts | Admin, Hour_Ledger, License_Manager, Logger, Mailer, Upgrade_Manager, Utils |
| courses | Features, License_Manager, Logger, Mailer, Payments, Utils |
| publisher | License_Manager, Mailer, Utils |
| assistant | Logger, Utils |
| theme | ninguna |
| health-check | License_Manager, Logger, Migration_History, Module_Registry, Utils, Webhook_Manager |
Logger, Utils y License_Manager son el contrato de facto de Core: los usan 9, 8 y
6 plugins respectivamente. Esas tres clases son API pública congelada: se pueden
ampliar, no se pueden romper.
Referencias cruzadas entre plugins de dominio¶
| Origen | Destino | Qué usa | Guarda |
|---|---|---|---|
| enroll | gateway | Payment_Handler::create_payment() / build_payment_url() |
Features::is_gateway_active() (comprobado) |
| members | gateway | CPT_Pago, Payment_Handler, Receipt_Generator |
pendiente de comprobar caso a caso |
| courses | gateway | Receipt_Generator |
pendiente de comprobar |
| ext-gateway | gateway + members | Payment_Handler, CPT_Pago, CPT_Miembro |
demo |
| health-check | enroll + gateway + members | lectura para diagnóstico | es su función |
No hay dependencia circular de código entre enroll y members: lo que había era un
class_exists comentado en Motor_Inscripcion. La comunicación va por hooks, que es
lo correcto.
4. Contratos por hook¶
59 enlaces entre plugins, todos con prefijo convoca_. Los que importan:
| Hook | Emite | Escuchan | Crítico |
|---|---|---|---|
convoca_gateway_payment_completed |
gateway (y ext-gateway) | enroll, members, courses, core | sí: cierra la inscripción y activa la cuota |
convoca_gateway_payment_failed |
gateway | enroll, members, courses | sí |
convoca_gateway_payment_refunded |
gateway | courses | sí |
convoca_members_estado_changed |
members | core (auditoría) | sí |
convoca_member_created |
members | core | no |
convoca_voluntario_aprobado |
members | shifts | sí: habilita turnos |
convoca_voluntario_revocado |
members | shifts | sí |
convoca_enroll_inscripcion_nueva |
enroll | core | no |
convoca_can_credit_hours |
core | members | sí: filtro de decisión |
convoca_member_identity / _plans / _priority / _states |
core | members | sí: Core pregunta, Members responde |
convoca_payment_backend / _reader / _receipt |
core | gateway | sí |
convoca_register_module |
core | ext-gateway | extensión |
convoca_license_create_api_token |
license-generator | mu-plugins | no |
Patrón bueno ya establecido: Core pregunta por filtros, el plugin de dominio responde. Así Core no necesita conocer a Members ni a Gateway. Se debe conservar.
Patrón a vigilar: los do_action de pago los emite Gateway pero también los emite
health-check para simular cobros. Es intencionado (diagnóstico), pero significa que
un do_action de pago no prueba que haya habido un cobro real.
5. Acoplamiento oculto por opciones¶
9 opciones las lee más de un plugin sin pasar por un filtro:
| Opción | Dueño natural | La leen |
|---|---|---|
convoca_gateway_settings |
gateway | gateway, members, core, health-check |
convoca_members_settings |
members | members, enroll, core |
convoca_members_plans |
members | members, core |
convoca_pdf_templates |
core | core, enroll, members |
convoca_document_theme |
core | core, members |
convoca_shifts_hora_apertura / _cierre |
shifts | shifts, core |
convoca_publisher_auto_publish |
publisher | publisher, health-check |
convoca_uninstall_keep_data |
cada plugin | 7 plugins (convención compartida, correcto) |
Hallazgo D2: leer la opción de otro plugin funciona, pero convierte una decisión interna en contrato público sin documentarlo. No se debe romper (hay instalaciones leyéndola), pero toda lectura nueva debería ir por filtro. Documentar las 8 primeras como API de facto en la fase 6.
6. Librerías de terceros¶
| Librería | Dónde | Copias | Comentario |
|---|---|---|---|
dompdf/dompdf ^3.0 |
core | 1 | correcto: infraestructura común |
chillerlan/php-qrcode ^6.0 |
enroll, members, courses | 3 | cada plugin la vendoriza por separado |
eluceo/ical ^2.9 |
enroll | 1 | dominio de enroll (calendario), correcto |
| stubs de PHPStan de Core | members, shifts, courses, assistant | 4 | copias mantenidas a mano |
Hallazgo D3: las cuatro copias de stubs de Core se desincronizan con cada cambio de API de Core. No afectan a producción (no se despliegan), pero cuestan mantenimiento y dan falsos verdes/falsos rojos en PHPStan. Candidato a script generador único.
Hallazgo D4: tres copias de chillerlan/php-qrcode. Moverla a Core ahorra ~3
copias en los paquetes, pero solo es seguro si los tres plugins declaran ya
Requires Plugins: convoca-core (lo hacen). Requiere verificar el tamaño real de los
paquetes antes de decidir: si el .distignore ya excluye vendor, el ahorro es cero y
no se toca.
7. Regla de la casa (decidida por JC)¶
| Capa | Contenido | No entra aquí |
|---|---|---|
| Core | fechas, utilidades, PDF, logging, licencias, upgrades, webhooks, infraestructura común | reglas de negocio de socios, inscripciones, pagos o turnos |
| Members | socios, modalidades, cuotas, renovaciones, voluntariado | generación de PDF genérica, transporte de correo |
| Enroll | inscripciones, actividades, evaluaciones, check-in | cobro, estados de socio |
| Gateway | pagos, Redsys, recibos, conciliación | creación de socios o de inscripciones |
| Shifts | turnos, disponibilidad, horas de turno | contabilidad de horas (vive en Core: Hour_Ledger) |
| Publisher | publicación y distribución | generación de carteles (vive en Enroll: media/) |
| Theme | presentación, patrones, estilos | lógica de negocio |
Dos fronteras que hoy están borrosas y no se tocan sin plan de migración:
Hour_Ledgerestá en Core pero su semántica es de dominio (horas de voluntariado). Se queda: lo usan members y shifts y moverlo rompe ambos.enroll/media/yenroll/social/(carteles, cuentas, cola social) son capacidades de publicación viviendo en Enroll. Moverlas a Publisher es un rediseño, no una refactorización: requiere migración de tablas y de opciones. No se ejecuta en esta fase.
8. Qué no se puede romper (contratos congelados)¶
- Los 38 shortcodes y su salida pública.
- Los 8 tipos de contenido y sus metadatos (
_convoca_*). - Las 21 rutas REST y sus permisos.
- Los 35 eventos cron y sus nombres (están agendados en instalaciones vivas).
- Las 111 opciones existentes, incluidas las compartidas.
- Los hooks de la tabla del punto 4, en nombre y firma de argumentos.
- Las 8 tablas propias y su esquema actual (los cambios van con
dbDeltaaditivo).
Bibliotecas compartidas: una sola copia¶
chillerlan/php-qrcode (548 KB con su php-settings-container) la usaban tres plugins —
Members (carné y certificado), Courses (certificado) y Enroll (QR de los correos)— y viajaba
tres veces en cada sitio: 1.644 KB para el mismo código.
Desde Core 2.3.55 vive sólo en Core, que ya es el plugin del que dependen los demás y el que
ya trae Dompdf. Los tres plugins la llaman igual (class_exists + new QRCode), pero quien la
resuelve es el autoloader de Core, que se carga antes.
En los tres repos la dependencia queda en require-dev: así PHPStan y las pruebas la resuelven,
y el empaquetado (composer install --no-dev) no la incluye. El paquete no lleva código que
no se ejecuta.
Suelo de PHP: 8.2¶
La librería exige 8.2, y desde 2.3.55 Core lo declara. Los plugins que declaran
Requires Plugins: convoca-core no pueden prometer menos: todo el ecosistema pasa a 8.2,
salvo Enroll, que ya estaba en 8.4 por su librería de iCal. El tema se queda en 8.1 a propósito:
su código corre ahí y degrada sin Core con function_exists.
Lo que costó y lo que ahorró: subir el suelo cierra la puerta a PHP 8.0/8.1 —que ningún sitio de Convoca usa— y ahorra 1,1 MB por instalación. Se decidió con el dato delante, no por gusto.