Files
balam/planeacion/Plan-Webhook-Jira-2026-09-29.md

7.0 KiB
Raw Permalink Blame History

Plan — Webhook Jira (FAC) → vista previa automática de cotización BIND

Creado: 2026-09-29 · Responsable: Johann · Contexto: REGISTRO #84 (nació como #71; renumerado al fusionar el 30-sep) · Antecedente técnico: Investigacion-API-Jira.md §Bloque 3–4

Objetivo

Que la plataforma se entere en el momento en que se crea (o avanza) un ticket de FAC y deje preparada la vista previa (dry-run) de la cotización en BIND, para que un humano solo revise y confirme con un clic.

Fuera de alcance: crear la cotización en BIND sin confirmación humana. ADR-001 sigue vigente: toda escritura en BIND producción = dry-run + confirmación humana + Bind:Mode=Write encendido solo durante la operación. La automatización total requeriría autorización escrita de Balam y enmienda de ADR-001, con reglas (solo clientes conocidos, IVA dentro del catálogo, tope de monto, interruptor de apagado).

Decisiones previas (antes de escribir en Jira)

  1. ¿Qué evento dispara? Hay dos candidatos y no son equivalentes:
    • jira:issue_created: el ticket nace. Es lo que se pidió el 29-sep.
    • Transición a En proceso de facturación: es el disparador acordado en julio/agosto. Dura ~3 minutos (FAC-100: 2m44s), así que un poller de 15 min se lo pierde; el webhook lo resuelve de raíz.
    • Propuesta: escuchar created y updated (filtrado a cambio de estatus) en un solo webhook; la plataforma decide qué hacer con cada uno leyendo el changelog.
  2. Tickets de Automation for Jira (10 de 69 al 10-ago, sin request type ni campos estructurados): el endpoint los recibe, pero los marca "sin datos para cotizar" en lugar de armar una vista previa.
  3. Autorización escrita de Pedro: Johann confirma que existe (29-sep). Falta archivarla en fuentes/ con fecha, y confirmar su alcance: ¿cubre solo crear el webhook/regla, o también crear un ticket de prueba en FAC?

Fases

Fase 1 — Verificación de permisos (solo lectura, riesgo cero)

  • GET /rest/api/3/myself: el token es de Pedro y está vivo.
  • GET /rest/api/3/mypermissions?projectKey=FAC&permissions=ADMINISTER,ADMINISTER_PROJECTS
    • ADMINISTER = admin del sitio → Vía A (webhook de sistema).
    • Solo ADMINISTER_PROJECTS → Vía B (regla de Automation del proyecto).
    • Ninguno → Pedro lo crea en pantalla; nosotros solo damos los datos.
  • GET /rest/webhooks/1.0/webhook (si Vía A): inventario de webhooks existentes, para no duplicar y para saber qué hay antes de tocar.

Fase 2 — Endpoint en la plataforma (código nuestro, no toca Jira)

POST /api/jira/webhook en Balam.Api/Jira/:

  • Autenticación: secreto compartido (Vía A: firma HMAC X-Hub-Signature si el sitio la ofrece; Vía B: header propio). Sin secreto válido → 401, sin leer el cuerpo. Secreto en user-secrets (Jira:WebhookSecret), nunca en el repo.
  • No confía en el payload: solo extrae issueKey, valida que sea FAC-\d+, y relee el ticket con JiraClient (ReadOnly).
  • Idempotencia: tabla/registro por (issueKey, evento, timestamp); un reintento de Jira no genera una segunda vista previa.
  • Acción: arma el body de POST /api/Quotes con el mismo mapeo del wizard (cliente del combo 11598, servicio, cantidad, IVA como tasa, moneda, días de crédito), lo registra en WriteOperations como DryRun y marca el ticket como "Cotización lista para revisar" en la bandeja. Nunca llama a BIND en escritura.
  • Responde rápido (202) y procesa en segundo plano: Jira reintenta si el webhook tarda.
  • Pruebas xUnit con FakeHandler: secreto inválido → 401; payload con clave ajena → 400; reintento → una sola vista previa; ticket de Automation sin campos → "sin datos"; jamás se invoca un método mutante de BindClient.
  • El poller (JQL delta con solape, ADR-002) queda como respaldo: si la laptop está apagada y el webhook falla, el ticket se recupera en la siguiente pasada.

Fase 3 — Exposición temporal con ngrok

  • ngrok http 5078 con traffic policy que solo deja pasar POST /api/jira/webhook; cualquier otra ruta → 403 en el borde. Login, cartera y emisión no quedan expuestos.
  • Mientras el túnel esté abierto: API en Bind:Mode=ReadOnly.
  • ⚠️ Con ngrok gratuito la URL cambia en cada reinicio y depende de la máquina de Johann encendida. Es piloto, no productivo. Productivo = dominio fijo de ngrok (de pago) o Azure (bloqueado por el cliente).

Fase 4 — Alta del disparador en Jira (UNA escritura, auditada)

Operación puntual, numerada en la bitácora; no se cambia Jira:Mode de la app.

  • Vía A (preferida): POST /rest/webhooks/1.0/webhook con events: ["jira:issue_created", "jira:issue_updated"], filters: { "issue-related-events-section": "project = FAC" }, URL de ngrok y secreto. Reproducible, sin consumir cuota de Automation, reversible con DELETE /rest/webhooks/1.0/webhook/{id}.
  • Vía B: regla de Automation del proyecto FAC: Work item created (y/o Work item transitioned → En proceso de facturación) → Send web request (POST, header del secreto, body {"issueKey":"{{issue.key}}","evento":"{{webhookEvent}}"}). Se crea en la UI de Automation (la API de reglas es menos estable). Consume cuota mensual de ejecuciones: verificar el plan con Pedro.
  • Anotar en la bitácora: id del webhook/regla, URL, fecha, quién autorizó.

Fase 5 — Prueba y reversa

  • Prueba: un ticket de prueba en FAC (lo crea alguien de Balam, o Johann si la autorización lo cubre). Criterio de éxito: llega el aviso → aparece "lista para revisar" → WriteOperations tiene un DryRun → BIND no recibió ninguna escritura (verificar por lectura).
  • Reversa: borrar webhook/regla (id anotado) + cerrar ngrok. El endpoint queda inerte sin secreto configurado.

Riesgos

Riesgo Mitigación
API local expuesta a internet Traffic policy de ngrok (una sola ruta), secreto, Bind:Mode=ReadOnly con túnel abierto
Escritura en el Jira productivo del cliente Una sola operación, autorizada por escrito, numerada y reversible
Payload falsificado Secreto/HMAC + relectura del ticket por API
Pérdida de eventos (laptop apagada, URL de ngrok cambió) Poller de respaldo con checkpoint y solape
Cuota de Automation (Vía B) Verificar plan; preferir Vía A
Dos sesiones de Claude Code levantando la API a la vez (29-sep) Una sola sesión dueña de la API durante la prueba

Checklist

  • Archivar la autorización escrita de Pedro en fuentes/ y anotar su alcance
  • Fase 1 — verificar identidad y permisos del token (solo GET)
  • Decidir evento(s): creación, transición a En proceso de facturación, o ambos
  • Fase 2 — endpoint + idempotencia + pruebas
  • Fase 3 — ngrok con traffic policy de una sola ruta
  • Fase 4 — alta del webhook/regla (operación numerada)
  • Fase 5 — ticket de prueba, verificación y registro en bitácora
  • Definir el destino productivo (ngrok de pago vs Azure)