ADR 025: Composición por caso de uso (patrón producto ensamblado)¶
Estado¶
Aceptado — 2026-07 (reclasificado: decisión de producto, no SPI de plataforma)
Relacionado con ADR 023, ADR 024 y ADR 021.
Contexto¶
Cortex HIVE es una plataforma genérica para ensamblar productos (unosportclub, coworking, etc.) mediante plugins instalables. El SPI (requires, optional_requires, provides) vive en cortex-core; el framework valida descriptores en boot (validate_plugin_dependencies) sin conocer grafos de producto.
core/cortex_core/plugin_graph.py expone solo tipos genéricos (PluginGraphNode, BundleProfile) y utilidades (transitive_requires, validate_bundle_closure, detect_requires_cycles). No contiene PLUGIN_GRAPH ni perfiles de UnoSportClub.
Esta ADR fija el patrón de ensamblado (paquete products/* como extensibilidad esperada, grafo, bundles, CI). El loader no lee composition.py en runtime. Los verticales concretos se documentan en casos de uso:
- Reservas — sandbox PMV en
cortex-product-unosportclub(UnoSportClub); valida el framework hacia el PMV, no producto comercial terminado. - Proptech — diseño desde PropTech Platform.
Documentación: casos-de-uso/ (Reservas, Proptech).
Árbol por capas¶
| Capa | Plugins |
|---|---|
| Fundación | clients, resources, payments, discounts |
| Catálogo | pricing |
| Operaciones | booking, sales |
| Extensión | events, store, subscriptions |
| Finanzas | accounting, billing |
| Plataforma | ai-agents |
Grafo de dominio (caso Reservas — UnoSportClub)¶
Fuente machine-readable: products/unosportclub/cortex_product_unosportclub/composition.py (REFERENCE_GRAPH).
| plugin_id | requires (hard) | optional_requires | provides |
|---|---|---|---|
| clients | — | — | clients |
| resources | — | — | resources |
| pricing | resources | — | pricing |
| booking | resources | clients, pricing, payments, discounts | booking |
| payments | — | — | payments |
| sales | clients, payments | pricing, discounts | sales |
| events | booking, clients | sales | events |
| discounts | — | — | discounts |
| accounting | — | payments, sales | accounting |
| store | — | sales | store |
| subscriptions | clients | payments | subscriptions |
| billing | clients | payments, accounting | billing |
| ai-agents | — | booking, clients, payments | ai-agents |
Leyenda:
- requires: boot falla en
CORTEX_PLUGIN_DEPS=strictsi el proveedor no está enabled. - optional_requires: el plugin carga; UI y flujos consultan capabilities y degradan (patrón reservation-flow).
- provides: capability indexada en
GET /api/v1/control/capabilities.
Namespaces UI vs plugins de dominio¶
Los namespaces operations y admin son generativos (mecanismo de plataforma): el framework los materializa con ensure_panel() cuando plugins habilitados registran módulos con ese panel_id.
La convención de qué módulos van en cada namespace para el caso Reservas (UnoSportClub) es decisión del caso de uso — ver bundles.
panel_id | Origen | Rol (sandbox Reservas — ilustrativo) |
|---|---|---|
operations | Generativo | Operación diaria |
admin | Generativo | Parametrización y finanzas |
accounting | Plugin + cortex.panels | Contabilidad — módulo home (resumen) + ledger (operación vía register_resources) |
control | Framework embebido | Plataforma (siempre activo) |
trainer | Plugin dedicado | Portal entrenador |
Un producto ensambla pip extras del paquete cortex-product-unosportclub + plugins activos en state store.
Integración permitida¶
| Mecanismo | Uso |
|---|---|
HTTP /api/v1/{namespace} | Lectura/escritura entre dominios |
| Capabilities API | UI condicional y degradación graceful |
| Events / listeners (ADR 021) | Reacción desacoplada (ej. booking.confirmed → accounting) |
| MCP tools | Agentes y automatización |
Prohibido: import Python entre paquetes cortex_plugin_* de distintos plugins.
Recetas de producto (bundle profiles)¶
Definidas en BUNDLE_PROFILES del paquete cortex-product-unosportclub:
| Perfil | Propósito |
|---|---|
| operations-core | Operación diaria: clientes, recursos, reservas, pagos, tarifas |
| operations-full | operations-core + descuentos + eventos |
| admin-finance | Finanzas admin: clientes, recursos, pagos, tarifas, ventas, facturación |
| sports-club-full | Producto deportivo completo (perfil de referencia) |
| coworking-minimal | Segundo producto demo: solo recursos + reservas (genericidad) |
Extras pip: pip install "cortex-product-unosportclub[sports-club-full]". El meta-paquete cortex re-exporta alias deprecados (cortex[operations-core]).
Activación en caliente y paneles host¶
Los paneles dedicados (accounting, trainer, …) registran en boot:
configure_panel()→ módulohome(y metadata del shell).register_resources()→ módulos operativos (ej.ledgeren Contabilidad).
Si el superadmin activa el plugin sin reiniciar el API, activate_pending_plugins() debe repetir el paso 2 (y register_forms si aplica). De lo contrario el panel muestra solo Inicio en el sidebar. Implementación: framework/cortex_framework/control/runtime_activation.py.
Validación¶
| Capa | Qué valida |
|---|---|
CI products/unosportclub/tests | Descriptores == REFERENCE_GRAPH; bundles cerrados; sin ciclos; sin imports cruzados |
Boot validate_plugin_dependencies | requires hard según CORTEX_PLUGIN_DEPS (framework, agnóstico de producto) |
| Boot (warn) | optional_requires ausentes — log, no fail |
| Hot enable panel host | register_resources + register_forms vía activate_pending_plugins |
Consecuencias¶
- Nuevo plugin en caso Reservas: actualizar
REFERENCE_GRAPH, descriptor, tests de composición y dependency-contracts. - Segundo producto (coworking-minimal) demuestra que UnoSportClub no es blueprint de arquitectura de plataforma.
- accounting y billing pueden evolucionar hacia integración por events sin
requirescircular.