Primeros pasos¶
Crea un plugin de negocio con API REST y pantalla de listado en el panel panel, sin escribir React.
Cuándo usar esta guía¶
- Es tu primer plugin en Cortex/HIVE.
- Necesitas un listado con columnas y rutas REST bajo
/api/v1. - Quieres UI declarativa con
ResourceBuilderen lugar de JSON manual.
Estructura mínima¶
plugins/mi-modulo/
pyproject.toml
cortex_plugin_mi_modulo/
__init__.py
plugin.py # API REST + create_plugin()
resources.py # register_resources()
fixtures/ # opcional en desarrollo
Paso 1 — Paquete y entry point¶
En pyproject.toml:
[project]
name = "cortex-plugin-mi-modulo"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"cortex-core",
"cortex-framework",
"fastapi>=0.115",
]
[tool.uv.sources]
cortex-core = { workspace = true }
cortex-framework = { workspace = true }
[project.entry-points."cortex.plugins"]
mi-modulo = "cortex_plugin_mi_modulo:create_plugin"
Añade "plugins/mi-modulo" al workspace en el pyproject.toml raíz y ejecuta uv sync --all-packages.
Paso 2 — Plugin REST¶
plugin.py expone el contrato obligatorio del SPI:
from cortex_core.plugin import PluginDescriptor
from cortex_framework.api.list_response import list_endpoint
from fastapi import APIRouter, Request
class MiModuloPlugin:
descriptor = PluginDescriptor("mi-modulo", "Mi módulo", "0.1.0")
def api_router(self) -> APIRouter:
router = APIRouter(prefix="/mi-modulo", tags=["mi-modulo"])
@router.get("/items")
async def list_items(request: Request) -> dict:
items = [...] # tu lógica
return list_endpoint(items, request)
return router
def resource_paths(self) -> list[str]:
return ["mi-modulo"]
def create_plugin() -> MiModuloPlugin:
return MiModuloPlugin()
Referencia completa: plugins/clients/cortex_plugin_clients/plugin.py.
Paso 3 — UI con ResourceBuilder¶
resources.py registra manifest, dashboards y formularios:
from cortex_framework.ui import ResourceBuilder, register_resource
from cortex_framework.ui.registry import ResourceRegistry
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, create=False, edit=False, view=False)
.table(
lambda t: t.columns(
lambda c: c.text("name", "Nombre", sortable=True)
)
)
)
register_resource(registry, "panel", "mi-modulo", configure)
Reexporta el hook en __init__.py:
from cortex_plugin_mi_modulo.plugin import create_plugin
from cortex_plugin_mi_modulo.resources import register_resources
__all__ = ["create_plugin", "register_resources"]
Ejemplo real: plugins/clients/cortex_plugin_clients/resources.py.
Paso 4 — Activar el plugin¶
En otra terminal:
Paso 5 — Verificar¶
| Comprobación | Cómo |
|---|---|
| API | GET http://localhost:8000/api/v1/mi-modulo/items + header X-Tenant-Id: default |
| OpenAPI | http://localhost:8000/api/docs |
| UI | Panel panel → módulo mi-modulo en la navegación |
| Manifest | GET /api/v1/panels/panel/modules/mi-modulo/manifest |
Flujo bootstrap → pantalla¶
sequenceDiagram
participant P as Plugin Python
participant API as FastAPI bootstrap
participant Shell as web-shadcn
participant W as Widgets
P->>API: register_resources
Shell->>API: GET panels/panel/modules/.../manifest
Shell->>API: GET ui/dashboards/{id}
Shell->>W: render data-table
W->>API: GET /api/v1/mi-modulo/items Errores frecuentes¶
| Síntoma | Causa habitual |
|---|---|
| Plugin no aparece en OpenAPI | Falta en CORTEX_ENABLED_PLUGINS o error en uv sync |
| Módulo no en navegación | panel_id incorrecto o hook no reexportado en __init__.py |
| Tabla vacía o 404 | list_path no coincide con la ruta del APIRouter |
register_dashboards ignorado | Si existe register_resources, el loader no ejecuta register_dashboards |
Siguiente paso¶
Profundiza en el ciclo de vida del plugin y en Recursos para páginas create/edit/view.