Saltar a contenido

Integración con el framework

Cómo un plugin pasa del código fuente a rutas HTTP, manifests CUS y navegación en el shell React.

Flujo end-to-end

sequenceDiagram
  participant Dev as Desarrollador
  participant EP as EntryPoint_cortex.plugins
  participant Store as PluginStateStore
  participant Loader as plugins_loader
  participant Panel as ensure_panel
  participant API as FastAPI_api_v1

  Dev->>EP: pyproject.toml + create_plugin
  EP->>Loader: discovery al arranque
  Store->>Loader: ids activos desde PG
  Loader->>Loader: register_* hooks por plugin
  Loader->>Panel: materializa panel_id
  Loader->>API: monta api_router por plugin

Discovery

El framework encuentra plugins por (orden de precedencia; sideload gana):

  1. Entry points cortex.plugins en paquetes instalados (uv sync, pip).
  2. Workspace bajo CORTEX_PLUGINS_ROOT (default: plugins/ del monorepo si existe).
  3. Sideload con CORTEX_PLUGIN_DIRS (solo desarrollo; override por id).

Código: framework/cortex_framework/plugins/discovery.py.

Hosts dedicados: entry point cortex.panels (ver ADR 011).

Activación

Fase Qué ocurre
Instalación El paquete entra al catálogo (descubrible por entry point)
Activación Superadmin habilita en /control/plugins → persiste en PostgreSQL
Bootstrap Solo plugins activos ejecutan hooks y montan routers
Hot reload Cambios de activación pueden requerir reinicio si requiresRestart: true

Detalle: Activación de plugins.

Orden de bootstrap

flowchart TB
  C[Control embebido]
  P[Plugins activos cortex.plugins]
  H[Hooks register_*]
  E[ensure_panel namespaces generativos]
  M[merge_panel_infrastructure]
  V[validate_panels]

  C --> P --> H --> E --> M --> V
  1. Control — panel de plataforma siempre presente (bootstrap_control_panel).
  2. Plugins activos — instancia cada create_plugin().
  3. Hooks — UI, MCP, WS, listeners, observers, settings.
  4. Paneles generativosensure_panel("operations") (y similares) al primer aporte.
  5. Infraestructura — widgets, layouts, módulo configuration por panel.
  6. Validación — cada módulo CUS referencia un panel_id existente.

Código: framework/cortex_framework/plugins/loader.py, framework/cortex_framework/panels/registry.py.

Paneles generativos y namespaces

Un panel (panel_id) es un namespace de composición: ruta base, navegación y dashboards ensamblados desde contribuciones de plugins. El nombre del panel es decisión del plugin (contributes_panels en el descriptor, o entry point cortex.panels para hosts dedicados). El framework no mantiene un catálogo fijo de panels de negocio.

Mecanismo panel_id Origen
Plataforma control Framework (siempre activo)
Generativo operations, admin, samples Shell vacío; plugins habilitados inyectan módulos
Host dedicado Definido por el plugin Entry point cortex.panels + configure_panel

En el sandbox Reservas (caso de uso UnoSportClub), plugins como accounting o trainer pueden aportar hosts dedicados si están habilitados. No existe panel client — el plugin clients opera en operations.

Convención operations vs admin (ADR 019)

Namespace Rol Ejemplo en sandbox Reservas
operations Operación diaria booking, clients, resources
admin Parametrización, finanzas sales, billing, payments, pricing

La asignación módulo → namespace es convención del caso de uso ensamblado (ADR 025), no una regla del framework. Otro vertical podría usar otros panel_id.

Un mismo plugin puede registrar en varios namespaces (módulos, widgets o settings).

flowchart TB
  subgraph namespaces [Namespaces generativos]
    OP[operations]
    AD[admin]
  end

  subgraph opMods [Modulos operacion]
    BK[booking]
    CL[clients]
  end

  subgraph admMods [Modulos parametrizacion]
    SL[sales]
    BL[billing]
    PY[payments]
  end

  OP --> opMods
  AD --> admMods

Ver ADR 019 y Panel namespaces y composición.

Contribuir un módulo

from cortex_framework.ui import ResourceBuilder, register_resource

def register_resources(registry: ResourceRegistry) -> None:
    def configure(builder: ResourceBuilder) -> None:
        (
            builder.id("items")
            .title("Ítems")
            .api_base("/api/v1/mi-modulo")
            .list_path("/api/v1/mi-modulo/items")
            .module_path("items")
            .nav_group("catalog", nav_sort=20)
            .pages(list=True)
            .table(lambda t: t.columns(lambda c: c.text("name", "Nombre")))
        )

    register_resource(registry, "operations", "mi-modulo", configure)

Al registrar, el framework:

  1. Crea el namespace operations si no existe (ensure_panel).
  2. Añade el módulo mi-modulo al manifest del panel.
  3. Expone dashboards y forms vía /api/v1/panels/... y /api/v1/ui/....

Runtime HTTP

Tras el bootstrap, cada petición REST ejecuta solo el código en api_router() — los hooks ya corrieron una vez.

El shell React (web-shadcn) consume manifests y dashboards; los widgets llaman a tus rutas REST.

sequenceDiagram
  participant Shell as web_shadcn
  participant API as FastAPI
  participant Plugin as plugin.py

  Shell->>API: GET panels/operations/modules/.../manifest
  Shell->>API: GET ui/dashboards/{id}
  Shell->>API: GET /api/v1/mi-modulo/items
  API->>Plugin: handler list_items

Entry point opcional cortex.panels

Para namespaces con identidad propia (marca, tema, scopes), un plugin puede exportar configure_panel(PanelBuilder). El loader llama a load_panel_hosts() después de materializar namespaces generativos, solo para hosts que aún no existen.

No uses cortex.panels para operations ni admin — el framework ya aplica metadata de shell vía módulos integrados.

Plugin de demostración

plugins/helloworld es sandbox de plataforma (panel samples, To-Do demo). No está en el catálogo de dominio: ver API interna del framework.

Siguiente paso

Primer plugin — tutorial paso a paso desde la plantilla.