7.0 KiB
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)
- ¿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
createdyupdated(filtrado a cambio de estatus) en un solo webhook; la plataforma decide qué hacer con cada uno leyendo el changelog.
- 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. - 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_PROJECTSADMINISTER= 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-Signaturesi 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 seaFAC-\d+, y relee el ticket conJiraClient(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/Quotescon el mismo mapeo del wizard (cliente del combo 11598, servicio, cantidad, IVA como tasa, moneda, días de crédito), lo registra enWriteOperationscomoDryRuny 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 deBindClient. - 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 5078con traffic policy que solo deja pasarPOST /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/webhookconevents: ["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 conDELETE /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" →
WriteOperationstiene unDryRun→ 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)