Compare commits

..

2 Commits

6 changed files with 193 additions and 1 deletions
Binary file not shown.
+14 -1
View File
@@ -2,7 +2,20 @@
Acciones vivas del proyecto. Formato: `[ ]` abierta · `[x]` cerrada (no se borran, dejan rastro). Cada una con responsable y, si aplica, fecha. Ver contexto en [REGISTRO.md](REGISTRO.md).
_Última actualización: **2026-09-15** — corte de horas 10-ago→15-sep reconstruido y huecos de registro listados (seis sesiones sin bitácora). Anterior: **2026-08-21, mediodía** — ⭐ primera cotización real emitida (folio 1026; la 2.ª, corregida, pendiente de confirmar). Anterior: **2026-08-20, noche.** Cruce completo del buzón contra la bitácora (MCP ms365): se incorporaron 9 comunicaciones faltantes y se corrigieron 2 errores de registro. **Hay sesión mañana viernes 21-ago, 7:00 am** con Noé, Ara y Pedro sobre el formulario modificado y `FAC-106`. Ver [REGISTRO #65](REGISTRO.md)–[#68](REGISTRO.md)._
_Última actualización: **2026-09-29** — plan del webhook Jira FAC → vista previa de cotización ([#71](REGISTRO.md)). Anterior: **2026-09-15** — corte de horas 10-ago→15-sep reconstruido y huecos de registro listados (seis sesiones sin bitácora). Anterior: **2026-08-21, mediodía** — ⭐ primera cotización real emitida (folio 1026; la 2.ª, corregida, pendiente de confirmar). Anterior: **2026-08-20, noche.** Cruce completo del buzón contra la bitácora (MCP ms365): se incorporaron 9 comunicaciones faltantes y se corrigieron 2 errores de registro. **Hay sesión mañana viernes 21-ago, 7:00 am** con Noé, Ara y Pedro sobre el formulario modificado y `FAC-106`. Ver [REGISTRO #65](REGISTRO.md)–[#68](REGISTRO.md)._
## ⭐ 29-sep — webhook Jira FAC → vista previa de cotización ([REGISTRO #71](REGISTRO.md), [plan](../planeacion/Plan-Webhook-Jira-2026-09-29.md))
- [ ] 📄 **Archivar en `fuentes/` la autorización escrita de Pedro** para crear el webhook/regla en Jira; anotar su alcance (¿incluye crear un ticket de prueba en FAC?).
- [ ] 🔎 **Fase 1 (solo GET):** `myself` + `mypermissions` (ADMINISTER / ADMINISTER_PROJECTS en FAC) + inventario de webhooks → decide Vía A (webhook de sistema) o Vía B (regla de Automation).
- [ ] 🔴 **Decidir el evento:** creación del ticket, transición a *En proceso de facturación* (dura ~3 min), o ambos.
- [ ] 🔧 **Fase 2:** `POST /api/jira/webhook` con secreto, relectura del ticket, idempotencia y solo dry-run; pruebas con `FakeHandler`. Poller de respaldo.
- [ ] 🌐 **Fase 3:** ngrok con traffic policy de una sola ruta; API en ReadOnly mientras el túnel esté abierto.
- [ ] ✍️ **Fase 4:** alta del webhook/regla como operación numerada (id, URL, fecha, autorización).
- [ ] 🧪 **Fase 5:** ticket de prueba → "lista para revisar" → verificar que BIND no recibió escritura. Reversa documentada.
- [ ] ☁️ **Destino productivo del webhook:** ngrok con dominio fijo (de pago) vs Azure (sigue bloqueado por el cliente).
- [ ] ⚠️ **Una sola sesión de Claude Code dueña de la API** en sesiones de escritura (el 29-sep otra sesión la relanzó en ReadOnly).
- [ ] 📝 **Hueco de bitácora:** registrar el trabajo del 9/10-sep (puente a la UI de BIND, prefactura 2463, sonda #12 / remisión 1004) — hoy solo vive en `balam-plataforma/CLAUDE.md`.
## 🚨 Huecos de registro (detectados en el corte del 15-sep)
+26
View File
@@ -1610,6 +1610,32 @@ Se aplicó el protocolo del guion §6: parar, anunciar el diagnóstico, pivotear
---
## 71 · Sep 29, 2026 · Sesión de trabajo · App en modo escritura, token de Jira y plan del webhook FAC → vista previa de cotización ⭐
> Contexto: sesión de Johann con Claude Code. Nota: la bitácora no tiene entradas entre el #70 (26-ago) y este; el trabajo del 9/10-sep (puente a la UI de BIND para la prefactura) está documentado solo en `balam-plataforma/CLAUDE.md` y se sube al repo en esta misma fecha.
**1. Levantar la app en modo escritura.** Se arrancó Docker Desktop (estaba apagado) → Postgres `balam-postgres-dev` en 5438, frontend en 4200 y API en 5078 con `Bind__Mode=Write`, `Bind__Ui__Enabled=true` y `Bind__Ui__Mode=Write` como **variables de entorno de esa corrida** (los user-secrets siguen en `Bind:Mode=ReadOnly`, así que al apagar vuelve sola a solo lectura).
- ⚠️ **Choque entre dos sesiones de Claude Code:** otra sesión en la misma máquina levantó su propia API a las 13:24 (y de nuevo a las 15:28, `--no-build`) **sin** las variables de escritura. La API de esta sesión murió sin excepción en el log y el reinicio falló con `address already in use`. La API que quedó viva en 5078 era la de la otra sesión, en `Bind:Mode=ReadOnly`.
- Evidencia en pantalla: el paso 3 del wizard (*Vista previa y creación (ADR-001)*) generó la **operación #15 · `POST /api/Quotes`** como dry-run registrado en `WriteOperations`, con el botón *Crear cotización en BIND* deshabilitado: *"el servidor está en modo ReadOnly"*. **No se escribió nada en BIND.**
- Lección: una sola sesión debe ser dueña de la API durante una sesión de escritura; verificar el dueño del puerto (no solo que esté escuchando).
**2. Token de Jira.** Existe `Jira:ApiToken` en user-secrets de `Balam.Api` (junto con `Bind:ApiKey`, `Jwt:SigningKey`, etc.); configuración en `appsettings.Development.json`: `balam-jsm-temp.atlassian.net`, usuario `pedro.ayala@…` (token personal de **Pedro**), proyecto FAC, `Mode=ReadOnly`. No se verificó el valor (el clasificador de permisos bloqueó leerlo, correctamente). Prueba práctica de vigencia: que la bandeja de Solicitudes FAC cargue.
**3. ¿Se puede leer la creación de un ticket y automatizar la cotización?**
- **Leer: sí, hoy.** Polling con JQL delta (`SearchJqlAsync` + `SyncSchedulerService` + checkpoint con solape, ADR-002) o webhook. Recordatorio del 10-ago: el disparador acordado (*En proceso de facturación*) dura ~3 min, así que el poller debe leer el changelog, no el estatus actual.
- **Crear la cotización sin humano: técnicamente sí, pero rompe ADR-001** (dry-run + confirmación humana en cada escritura a BIND producción). Propuesta aceptada como camino: **el webhook/poller deja lista la vista previa y un humano confirma con un clic.** Automatización total solo con autorización escrita de Balam y enmienda a ADR-001.
**4. Webhook / Jira Automation — qué se necesita.** URL pública (ngrok ya instalado en la máquina de Johann; productivo = Azure o dominio fijo), endpoint nuestro `POST /api/jira/webhook` (no existe aún), y el disparador en Jira. Con el token actual: construir el endpoint sí (no requiere permisos de Jira); crear el webhook/regla en Jira solo si el usuario de Pedro es admin **y** con autorización expresa, porque es escribir en la configuración del Jira productivo a su nombre.
- **Johann confirma que existe autorización escrita de Pedro** para hacerlo. ⚠️ Aún no archivada en `fuentes/`.
**Resultado:** plan en [`../planeacion/Plan-Webhook-Jira-2026-09-29.md`](../planeacion/Plan-Webhook-Jira-2026-09-29.md): 5 fases (verificar permisos por GET → endpoint con secreto/idempotencia/relectura → ngrok con traffic policy de una sola ruta → una escritura auditada en Jira, preferentemente webhook de sistema → ticket de prueba y reversa).
**Repo de la plataforma:** se suben los cambios pendientes (puente de prefactura por la UI de BIND: `BindUiClient`, `PrefacturaUiEndpoints`, tarjeta del wizard y pruebas). Verificado antes del push: 107 pruebas en verde y frontend compilando; escaneo del diff sin secretos.
> **Lectura estratégica:** el webhook no cambia el protocolo de escritura: lo que acelera es la *captura*, no la *decisión*. Y el caso más valioso no es la creación del ticket sino el cruce de 3 minutos por *En proceso de facturación*, que el polling de 15 min pierde.
---
## Resumen ejecutivo del hilo (para contexto rápido)
### Datos duros confirmados por Balam
@@ -0,0 +1,42 @@
# Correo — Respuesta a Erika: token de Jira, límites de consumo y estado general
Borrador · 29-jul-2026 — **no enviado**
Responder a todos → Para: Erika Chávez · CC: Noé Rocha; Pedro Ayala
Asunto: (el del hilo, con `RE:`)
**Contexto:** Erika pregunta (29-jul, 1:25 pm) por comentarios sobre lo que entregó Pedro el 27-jul —token PAF por Drive + explicación de límites de consumo—, si se pudo ingresar y si se requiere algo adicional de su lado.
**Estrategia:** la pregunta de Erika abre la puerta para dar el panorama completo. El correo entrega dos cosas el mismo día (propuesta v1.3 y Excel de horas por etapa), reporta la prueba real del token con su resultado, y fecha los tres bloqueos que están del lado de Balam. Las fechas son el punto: el hueco en desarrollo del 28–29 existe porque la definición del flujo lleva en revisión interna desde el 24-jul y Azure desde la semana del 21-jul.
======================================================================
Buenas tardes Erika, Ing. Noé, Pedro:
Gracias Pedro por el token y por el detalle de los límites de consumo. Ya lo aterricé al diseño: como no hay tope mensual y lo que aplica son límites de velocidad, la integración se autorregula leyendo los headers `X-RateLimit-*` —baja el ritmo al acercarse al umbral y respeta el `Retry-After`—, así que no anticipo problema de consumo con el volumen del proceso. Que no exista dashboard no nos afecta, porque esa telemetría viaja en las respuestas.
Sobre el ingreso, ahí sí necesito tu apoyo: el token está siendo rechazado con 401. Ya descarté las causas de mi lado —la cadena está completa y bien formada (192 caracteres, con el prefijo que corresponde, sin espacios ni cortes), y probé con el correo que me confirmaste, tanto contra el sitio de Jira como por la ruta de `api.atlassian.com`. También lo validé contra el endpoint de cuenta de Atlassian, que no depende del sitio, y ahí también responde 401. Eso apunta a que la credencial ya no está activa.
¿Me ayudas a revisar en el administrador de tokens de tu cuenta si el token **PAF** sigue existiendo? Si se rotó o quedó reemplazado, con que lo regeneres y me lo compartas de nuevo lo pruebo de inmediato y les confirmo el mismo día.
Aprovecho una pregunta de diseño: convendría valorar si el token vive en una cuenta de servicio en lugar de en tu cuenta personal. Hoy todo lo que la plataforma escriba en Jira quedaría registrado a tu nombre, y una rotación tuya dejaría la integración sin acceso. Lo que ustedes decidan lo implemento igual, solo lo dejo sobre la mesa.
Aprovecho para dejarles el panorama completo. De mi lado va hoy:
- **La propuesta actualizada (v1.3)** con la integración Jira → BIND incorporada al alcance, que les envío en el hilo correspondiente.
- **El Excel de horas por etapa**, con las etapas 2 y 3 desglosadas como me lo pidió Erika para el conteo de facturación.
Y lo que está detenido esperando definición de su lado, con fecha para que sea fácil ubicar dónde está la fila:
1. **La definición del flujo de facturación**, en revisión interna desde la sesión del 24-jul. De ahí sale el estatus que dispara la creación de la cotización, y es la que tiene detenidas la capa de escritura y la automatización con Jira. Es la que más pesa.
2. **El acceso a Azure**, previsto para la semana del 21-jul. Sin él no puedo configurar el ambiente ni el CI/CD.
3. **El token de Jira**, lo que comento arriba.
En cuanto se liberen retomo de inmediato; el trabajo que no depende de ellas ya está hecho y verificado. Si les ayuda, puedo entrar a una sesión corta esta semana para cerrar la definición del flujo con Arturo y avanzar sin esperar la revisión completa.
Cuando toque la prueba en vivo de creación les aviso con anticipación para hacerla acompañados, como lo acordamos con el Ing. Noé.
Quedo a sus órdenes.
Saludos cordiales,
Johann Velázquez
@@ -0,0 +1,82 @@
# Plan — Webhook Jira (FAC) → vista previa automática de cotización BIND
_Creado: 2026-09-29 · Responsable: Johann · Contexto: [REGISTRO #71](../bitacora/REGISTRO.md) · Antecedente técnico: [Investigacion-API-Jira.md §Bloque 3–4](Investigacion-API-Jira.md)_
## 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)
+29
View File
@@ -0,0 +1,29 @@
# Correo — Propuesta v1.3 (ajuste de alcance: integración Jira → BIND)
Borrador · 29-jul-2026 — **no enviado**
Adjunto: `Propuesta-Balam.pdf` (v1.3, 2.8 MB)
Para: Ing. Noé Rocha
CC: Araceli Sánchez; Erika Chávez; Pedro Ayala
**Contexto:** cierra el compromiso del 22-jul (Erika preguntó dos veces si la propuesta se ajustaría por Jira) y la re-pregunta del 28-jul 9:12 am. Mismo reparto de destinatarios que la v1.2 (2-jul). Recomendado: responder dentro del hilo **"RE: Solicitud de cotización – PRD"** para conservar la trazabilidad comercial.
Asunto (si se envía en el hilo): `RE: Solicitud de cotización – PRD`
Asunto (si se envía como correo nuevo): `Balam · Propuesta v1.3 — ajuste de alcance: integración Jira → BIND`
======================================================================
Buenas tardes a todos:
Como quedamos en las sesiones de julio, les comparto la propuesta actualizada (v1.3, adjunta). Incorpora al alcance la integración Jira → BIND: los tickets de la bandeja de Facturación generan automáticamente su cotización en BIND, con trazabilidad ticket → cotización → factura.
- **Ajuste: 7 a 10 h** ($4,200 – $6,000 MXN + IVA), en línea con la estimación de ~10 h que comenté el 21 de julio.
- **Total primera etapa: 119 a 146 h** ($71,400 – $87,600 MXN + IVA), 6 a 8 semanas a media dedicación.
- El control fiscal no cambia: la integración crea cotizaciones, nunca facturas. Se conserva la cadena cotización → prefactura → aprobación humana → timbrado por el PAC de BIND. Tarifa, facturación semanal y garantía siguen igual.
La implementación arranca en cuanto quede cerrada la definición del flujo de facturación que tienen en revisión, de donde sale el estatus disparador. La conectividad ya está resuelta con el token que generó Pedro el 27 de julio.
Para ejecutarlo me basta su confirmación por este mismo correo. Cualquier comentario, con gusto lo revisamos antes.
Saludos cordiales,
Johann Velázquez