🧩 Desarrolladores

Perfil comercial/1.0

Versión 1.0 · 12 de octubre de 2026. La definición para máquinas es perfil-comercial-1.0.json; el SDK PHP (JesgIA\Conector\Perfil) la trae incorporada.

Este perfil es el contrato entre JesgIA y el sistema de gestión de una empresa cliente. JesgIA le pide datos al sistema con herramientas de solo lectura y redacta la respuesta para el personal de la empresa.

JesgIA nunca escribe SQL ni ve la base del cliente. Recibe solo los campos de este perfil, y el cliente decide qué puede ver cada rol.

1. Cómo se conectan las partes

Navegador del personal ──(widget, token de 15 min)──▶ JesgIA (servidor A)
                                                        │  petición firmada Ed25519
                                                        ▼
                                  Sistema del cliente: jesgia.php (SDK) ──▶ su MariaDB (solo lectura)

El cliente expone un solo archivo PHP con dos acciones:

AcciónMétodoURLPara qué
manifestGEThttps://SISTEMA/jesgia.php/manifest (o ?accion=manifest)Qué herramientas implementa
ejecutarPOSThttps://SISTEMA/jesgia.php/ejecutar (o ?accion=ejecutar)Ejecuta una herramienta

Reglas comunes a todas las peticiones:

  • Solo lectura. Ninguna herramienta modifica datos.
  • Se devuelven como máximo 10 filas.
  • JesgIA espera 3 segundos por respuesta; después la descarta.
  • Se usa HTTPS en producción.

2. Firma de las peticiones

JesgIA firma cada petición con su clave privada Ed25519. El sistema la verifica con la clave pública, que viene con el SDK y está publicada en el portal. Una petición sin firma válida no ejecuta nada y recibe 401 FIRMA_INVALIDA.

Cabeceras de la petición:

CabeceraContenido
X-Jesgia-TenantId del tenant del cliente
X-Jesgia-FechaMarca de tiempo Unix en segundos. Se aceptan ±300 s: sincroniza el reloj con NTP.
X-Jesgia-NonceIdentificador único de la petición, igual al request_id del cuerpo (UUID)
X-Jesgia-FirmaFirma Ed25519 en base64 estándar del mensaje de abajo

Mensaje firmado: siete líneas unidas por \n, sin salto final.

JESGIA-FIRMA-1
<MÉTODO>                 GET | POST
<acción>                 manifest | ejecutar
<tenant>
<fecha>
<nonce>
<sha256 hex del cuerpo>  (del cuerpo vacío en GET: e3b0c442…b855)

Se firma la acción y no la ruta, para que una reescritura de URL en el servidor del cliente no invalide la firma.

Anti-replay:

  • El sistema rechaza un nonce ya usado.
  • Solo lo registra después de verificar la firma, así nadie puede «gastar» nonces ajenos.

Rotación de la clave:

  • El archivo de claves públicas admite varias líneas id base64, y vale cualquiera de ellas.
  • La clave nueva se publica antes de empezar a usarla.

3. Manifest

GET manifest responde así:

{
  "ok": true,
  "perfil": "comercial/1.0",
  "sdk": "jesgia-conector-php/1.0.0",
  "empresa": "Mercaderías Demo S.A.C.",
  "moneda": "PEN",
  "zona_horaria": "America/Lima",
  "herramientas": ["buscar_producto", "detalle_producto", "buscar_cliente"]
}

El cliente implementa las herramientas que pueda. Las que no declara responden NO_IMPLEMENTADO.

4. Ejecutar

Petición

{
  "perfil": "comercial/1.0",
  "herramienta": "buscar_producto",
  "parametros": { "texto": "arroz" },
  "usuario": { "id": "u-123", "rol": "vendedor" },
  "request_id": "9b2f…-…",
  "contexto": { "pagina": "/clientes/ficha.php?id=2" }
}
  • usuario es la persona que pregunta, tal como la identificó el propio sistema al pedir su token. **El sistema decide los permisos con usuario.rol.** Por ejemplo, si un vendedor no debe ver costos, no se devuelven. Si un rol no puede usar una herramienta, responde NO_AUTORIZADO.
  • contexto es opcional e informativo.

Respuesta correcta

{
  "ok": true, "perfil": "comercial/1.0", "request_id": "9b2f…", "herramienta": "buscar_producto",
  "datos": [ { "sku": "AR-005", "nombre": "Arroz Doña Luz 5 kg", "unidad": "saco", "stock": 42, "precio": 18.5, "moneda": "PEN" } ],
  "total": 3,
  "truncado": false
}
  • **datos trae como máximo 10 filas, con exactamente** los campos de la herramienta. Los campos de más se descartan.
  • **total** es el número de filas encontradas. Si es mayor que las devueltas, truncado es true y total es un mínimo.

Respuesta con error

{ "ok": false, "perfil": "comercial/1.0", "request_id": "9b2f…",
  "error": { "codigo": "AMBIGUO", "mensaje": "Hay varias coincidencias; hace falta precisar." },
  "candidatos": [ … ] }
CódigoHTTPCuándo
NO_ENCONTRADO200La búsqueda no encontró nada. El SDK lo responde solo si la herramienta devuelve 0 filas.
AMBIGUO200Una herramienta de registro único encontró varios. Trae candidatos (≤ 10).
NO_AUTORIZADO200El rol del usuario no puede ver eso
NO_IMPLEMENTADO200La herramienta no está en el manifest
PARAMETRO_INVALIDO400Falta un parámetro obligatorio o no cumple su tipo o largo
FIRMA_INVALIDA401Sin firma, firma no válida, fecha fuera de la ventana, nonce repetido u otro tenant
ERROR_INTERNO500Falló el sistema. El mensaje es genérico: nunca se exponen SQL ni rutas.

Cómo actúa JesgIA con cada caso:

  • **NO_ENCONTRADO:** dice que no encontró, sin inventar.
  • **AMBIGUO o varias filas:** pregunta cuál de ellas.
  • **NO_AUTORIZADO:** se lo dice al usuario.

5. Herramientas

Tipos de los campos

TipoValor
textoCadena, recortada a 300 caracteres
numeroEntero o decimal. El texto numérico que devuelve PDO se convierte.
enteroNúmero entero
fechaAAAA-MM-DD. Un AAAA-MM-DD HH:MM:SS se recorta a la fecha.
monedaCódigo ISO 4217 de 3 letras
enum:a\|bUno de los valores indicados
lista:XLista (≤ 10) de objetos del grupo X

Un tipo terminado en ? admite null.

buscar_producto

Parámetrotexto (2–100 caracteres): parte del nombre o el código exacto
Devuelve (lista)sku, nombre, unidad, stock (numero), precio (numero?), moneda

detalle_producto

Parámetrosku (1–60 caracteres)
Devuelve (un registro)los campos de buscar_producto + almacen (texto?), categoria (texto?), ultimo_ingreso (fecha?)

buscar_cliente

Parámetrotexto (2–100 caracteres): parte del nombre, o RUC o DNI exactos
Devuelve (lista)id (texto), nombre, documento (texto?), telefono (texto?)

estado_cuenta

Parámetroid_cliente (el id de buscar_cliente)
Devuelve (un registro)deuda_total, vencido (numero), moneda, documentos: lista de {numero, fecha_emision (fecha), fecha_vencimiento (fecha?), saldo (numero)}

Si el cliente existe pero no debe nada, la respuesta es deuda_total 0 y documentos vacío. No es NO_ENCONTRADO.

pedidos_cliente

Parámetrosid_cliente; estado (opcional, texto libre del sistema)
Devuelve (lista, del más reciente al más antiguo)numero, fecha (fecha), total (numero), moneda, estado

movimientos_producto

Parámetrossku; dias (opcional, entero 1–365, 30 por defecto)
Devuelve (lista, del más reciente al más antiguo)fecha (fecha), tipo (entrada \salida), cantidad (numero), documento (texto?)

6. Token de usuario del widget

El servidor del cliente pide el token para su usuario ya logueado:

POST https://JESGIA/conector/token
Authorization: Bearer jgk_live_…            ← API key del tenant; nunca en el navegador
{"usuario": {"id": "u-123", "rol": "vendedor", "nombre": "Ana"}}

200 {"token": "…", "expira_en": 1760000000}

El token dura 15 minutos y está firmado por JesgIA con el tenant, el usuario y su rol. El navegador solo recibe el token. En el SDK: TokenUsuario::pedir().

7. Prueba de conformidad y activación

php bin/conformidad.php arranque.php casos.php [--url=https://SISTEMA/jesgia.php] repite las peticiones firmadas de JesgIA con una clave de prueba y comprueba:

  • la firma, el anti-replay y el tenant;
  • el manifest;
  • cada herramienta: con datos, sin datos y sin parámetros;
  • los campos exactos y el tiempo de respuesta;
  • opcionalmente, que el usuario de la base sea de solo lectura y que el endpoint publicado use HTTPS y rechace las peticiones sin firma.

Un tenant pasa de pendiente a activo solo si su sistema es conforme. Con --json, la prueba produce el informe que se adjunta al pedido de activación.

8. Compatibilidad

  • Los perfiles nuevos (por ejemplo, logistica/1.0 o comercial/2.0) no cambian este. Un sistema conforme con comercial/1.0 lo sigue siendo.
  • Agregar una herramienta opcional a este perfil sería comercial/1.1. Cambiar o quitar campos sería comercial/2.0.