Registra la recuperación técnica del 1-ago (#61), refresca pendientes, borrador de status para Erika y script de pruebas Jira de lectura
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,15 +2,18 @@
|
||||
|
||||
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-08-01 (propuesta v1.3 con Jira→BIND enviada 29-jul y APROBADA por Noé 30-jul [#60]; Excel de etapas `Avance-Balam-2026-07-28.xlsx` entregado 29-jul; acceso API Jira resuelto 30-jul con token regenerado de Pedro; Azure escalado a Noé — requisitos ya comunicados: grupo de recursos + Contributor, sin Global Admin)._
|
||||
_Última actualización: 2026-08-01, noche ([#61]: E1 técnica cerrada — B5 scheduler, B6 RLS verificado, B8 suite de integración, B9 seeder demo; frontend de lectura de E2 completo (login→cartera→facturas→detalle+PDF→clientes+CSV); cliente Jira de lectura con pruebas; 16 commits pusheados al repo del cliente. Siguen bloqueados por Balam: Azure, sesión del flujo (B7) y decisiones Jira)._
|
||||
|
||||
## 🔴 Johann (proveedor) — inmediato
|
||||
|
||||
- [x] ~~⚠️🔥 **Enviar la propuesta/adenda ajustada por la integración Jira→BIND**~~ → **Hecho (29-jul):** v1.3 enviada por WhatsApp (8:18 am) y por correo (3:56 pm) a Noé, CC Ara/Erika/Pedro. **APROBADA por Noé el 30-jul:** "De acuerdo con la propuesta actualizada". Alcance: 7–10 h ($4,200–$6,000 MXN + IVA); total primera etapa 119–146 h. Ver [REGISTRO #59](REGISTRO.md), [#60](REGISTRO.md).
|
||||
- [x] ~~📊 **Enviar el Excel de horas de las etapas siguientes (2, 3)**~~ → **Hecho (29-jul, 8:18 am):** `Avance-Balam-2026-07-28.xlsx` por WhatsApp; 👍 de Erika. Ver [REGISTRO #59](REGISTRO.md).
|
||||
- [x] ~~🔑 **Destrabar el acceso a la API de Jira (401 del 29-jul)**~~ → **Resuelto (30-jul):** Pedro confirmó el correo del apikey (`pedro.ayala@...`), regeneró el token y `GET /myself` respondió 200. Ver `../planeacion/Investigacion-API-Jira.md` (Bloque 0).
|
||||
- [ ] 🌱 **Seeder de datos de prueba (B9):** sigue pendiente aunque a Erika se le reportó como hecho el 27-jul dentro de "Modelo + migraciones + datos de prueba". Cerrarlo antes de que se pida una demo sobre datos limpios.
|
||||
- [ ] 🧾 **Integración Jira→BIND — preparar las pruebas aprobables:** con el alcance aprobado (30-jul), avanzar los bloques de `../planeacion/Investigacion-API-Jira.md`; las pruebas de escritura requieren aprobación explícita previa.
|
||||
- [x] ~~🌱 **Seeder de datos de prueba (B9)**~~ → **Hecho (1-ago):** `DevDataSeeder` opt-in con datos ficticios (5 estados × MXN/USD × PUE/PPD). El desfase con lo reportado a Erika el 27-jul quedó saldado. Ver [REGISTRO #61](REGISTRO.md).
|
||||
- [ ] 🔑 **Copiar `propuesta/token-jira.txt` a esta máquina** (quedó en la otra computadora) y correr `../planeacion/pruebas-jira-lectura.sh` — completa los bloques 2/3/4/5 (solo lectura) de `../planeacion/Investigacion-API-Jira.md`.
|
||||
- [ ] 🧪 **Crear el sandbox Jira Cloud Free propio** (decidido 1-ago) para desarrollar escritura (transiciones/comentarios/creación) sin tocar FAC; la prueba en la instancia real sigue reservada a la sesión acompañada que autorizó Noé.
|
||||
- [ ] ⏱️ **Capturar horas 28-jul→1-ago en el CSV** (propuesta preparada, validar montos) y **regenerar `Avance-Balam` desde script** — la copia en disco del 28-jul está desincronizada (re-guardado manual).
|
||||
- [ ] 📅 **Demo del viernes 7-ago:** material listo — frontend (login→cartera→facturas→detalle+PDF→clientes), seeder demo como respaldo si BIND falla, scheduler en vivo.
|
||||
|
||||
- [x] ~~**Asistir al kickoff con Noé (mié 1-jul, 7:00 am)**~~ → **Hecho (1-jul).** Ver [REGISTRO #22](REGISTRO.md).
|
||||
- [x] ~~📅 **Asistir a la sesión "Proceso actual de facturación y cobranza" (lun 6-jul, 7:00 am)**~~ → **Hecha (6-jul).** Proceso mapeado end-to-end; lista blanca eliminada; cotización BIND obligatoria. Ver [REGISTRO #27](REGISTRO.md).
|
||||
|
||||
@@ -1149,6 +1149,30 @@ Johann envió el **avance por actividad en texto** (8:12 am), con 👍 de Erika
|
||||
|
||||
---
|
||||
|
||||
## 61 · Ago 1, 2026 · Desarrollo · Recuperación del plan: E1 técnica cerrada (B5/B6/B8/B9), frontend de lectura de E2 completo y cliente Jira ⭐
|
||||
|
||||
> Sesión de trabajo del sábado 1-ago para poner el proyecto donde el plan del 28-jul dice que debería estar, y adelantar todo lo que no depende de Balam. 9 commits nuevos en `pedro-balam-itsm/BALAM` (pusheados junto con los 7 que faltaban de B0–B6 — **el repo del cliente ya refleja todo el trabajo**).
|
||||
|
||||
**Entorno (bloqueos propios resueltos):** el backend no compilaba en esta máquina (faltaba apuntar al SDK .NET 10 de `~/.dotnet`); Docker apagado. Resuelto y documentado en el CLAUDE.md del repo. `bind_token_api.txt` borrado del disco (el token vive solo en user-secrets).
|
||||
|
||||
**Etapa 1 — deuda técnica cerrada (lo no bloqueado):**
|
||||
- **B9 · `DevDataSeeder`** ✅ — datos demo 100% ficticios opt-in (`Seed:DevData=true`): 5 clientes (con caso de dedup), 11 facturas cubriendo los 5 estados × MXN/USD × PUE/PPD, 3 cotizaciones y 2 vínculos con ticket ficticio. Idempotente, fechas relativas a "hoy" MX. **Cierra el entregable 8 y el pendiente "se reportó como hecho el 27-jul".** Runbook en CLAUDE.md.
|
||||
- **B6 · verificación RLS real** ✅ — rol `balam_app` (NOSUPERUSER/NOBYPASSRLS) creado y con ownership de las tablas; la connection string de desarrollo ya lo usa. Verificado fail-closed por psql: sin GUC 0 filas, INSERT rechazado. Script de init para volúmenes nuevos en `backend/db/init/`.
|
||||
- **B5 · scheduler** ✅ — `BackgroundService` + `PeriodicTimer` cada 15 min (configurable; ≤0 lo apaga) con guardas de solape y de cuota (<10% restante salta el ciclo). **Primer ciclo real contra BIND detectó el movimiento desde el 27-jul: 3 facturas nuevas, 46 pagos, 2 cotizaciones nuevas.**
|
||||
- **B8 · `Balam.Api.Tests`** ✅ — 25 pruebas de integración con el API completo contra Postgres real (`balam_test`, recreada por corrida): matriz rol→policy (401/403/200), login sin filtración de correos, cartera multimoneda contra la fixture demo, paginación/filtros, PDF demo sin tocar BIND. **Total de la solución: 61/61 pruebas verdes.**
|
||||
|
||||
**Etapa 2 — recuperadas las filas vencidas (29-31 jul) y adelantadas las de la semana próxima (solo lectura, nada bloqueado):** andamiaje Angular (sesión JWT en señales, interceptor, guards por rol espejo de las policies, login) · shell con identidad de marca y estado del sync · cartera por moneda **sin total combinado** · listado de facturas con búsqueda/filtros/paginación/orden del lado del servidor (el API se extendió para ello) · detalle con desglose y **descarga de PDF vía proxy** (el token de BIND nunca llega al navegador) · catálogo de clientes con dedup visible y **export CSV** (facturas y clientes). Verificado end-to-end con login real por el proxy de desarrollo. **Fuera de alcance por bloqueo:** creación de cotizaciones y conversión (flujo sin validar por Balam), XML (shape sin confirmar con Pedro), tipo de cambio DOF (diferido: la captura al facturar depende de B7).
|
||||
|
||||
**Integración Jira — todo lo posible sin Balam:** proyecto `Balam.Integrations.Jira` espejo del cliente BIND (Basic auth email:token, `search/jql` con `nextPageToken` — el clásico da 410—, changelog, transiciones con `expand=transitions.fields`, servicedeskapi, rate limit leído de headers `X-RateLimit-*`), con los tres modos ReadOnly/DryRun/Write y **read-only por default** (FAC es producción); 10 pruebas con `FakeHandler`. Los modelos persisten el **id numérico inmutable** (la llave FAC-nnn cambia con un move — Bloque 5). Registro condicional en el API (+`/api/jira/status`). ⚠️ **Las pruebas de lectura contra FAC real quedaron bloqueadas EN ESTA MÁQUINA: `propuesta/token-jira.txt` no existe aquí (quedó en la otra computadora, gitignoreado).** Script listo para correrlas en un comando: `planeacion/pruebas-jira-lectura.sh`.
|
||||
|
||||
**Pendientes que deja la sesión:**
|
||||
- [ ] Johann — **copiar `propuesta/token-jira.txt` a esta máquina** y correr `planeacion/pruebas-jira-lectura.sh` (bloques 2/3/4/5 de la investigación, solo lectura).
|
||||
- [ ] Johann — **crear el sandbox Jira Cloud Free propio** (decidido 1-ago) para desarrollar transiciones/comentarios/creación sin tocar FAC.
|
||||
- [ ] Johann — **capturar las horas del 28-jul→1-ago** en el CSV (propuesta preparada, pendiente de validación) y regenerar el Excel de avance desde el script (la copia en disco está desincronizada — re-guardado manual del 28-jul).
|
||||
- [ ] Johann — demo del viernes 7-ago: ya hay material (frontend + seeder demo + scheduler).
|
||||
|
||||
---
|
||||
|
||||
## Resumen ejecutivo del hilo (para contexto rápido)
|
||||
|
||||
### Datos duros confirmados por Balam
|
||||
|
||||
@@ -32,3 +32,19 @@ Johann Velázquez
|
||||
## 3. Confirmación al recibir el repositorio
|
||||
|
||||
> Listo, ya recibí la invitación y confirmé que tengo acceso de escritura al repositorio. Muchas gracias. Voy a publicar la estructura inicial del backend y les aviso cuando quede disponible.
|
||||
|
||||
## 4. WhatsApp a Erika — status lunes 3-ago + lo que falta de Balam (preparado 1-ago)
|
||||
|
||||
> Hola Erika, buen día. Te comparto avance del fin de semana:
|
||||
>
|
||||
> ✅ Cierre técnico de la Etapa 1 (lo que no estaba bloqueado): sincronización automática cada 15 min, datos de demostración, y suite de pruebas del API (61 pruebas en verde).
|
||||
> ✅ Adelanté el frontend de la Etapa 2 (parte de consulta): inicio de sesión por roles, cartera por moneda, listado de facturas con filtros y búsqueda, detalle con descarga del PDF del CFDI y catálogo de clientes con exportación a Excel/CSV. Todo el código ya está en el repositorio de Balam.
|
||||
> ✅ La base técnica de la integración con Jira (lectura) quedó lista y probada.
|
||||
>
|
||||
> Para seguir avanzando solo me falta de su lado:
|
||||
> 1. ☁️ El acceso a Azure que quedó con el inge Noé (grupo de recursos con Contributor) — es lo que libera el ambiente de pruebas y el despliegue.
|
||||
> 2. 📅 La fecha de la sesión del flujo de facturación — desbloquea la capa de escritura (cotización→factura) y las pantallas de emisión.
|
||||
> 3. 🧾 Tres definiciones de la integración Jira→BIND (pueden salir en una sola sesión con Pedro y Arturo): ¿qué tipo de solicitud se automatiza (Facturación o Facturación adicional)?, ¿qué estatus dispara la cotización?, y ¿de dónde tomamos monto y conceptos del ticket?
|
||||
>
|
||||
> Si te parece, el viernes les muestro todo funcionando en la demo semanal.
|
||||
|
||||
|
||||
Executable
+99
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env bash
|
||||
# Pruebas de SOLO LECTURA contra la instancia real de Jira (FAC) — Bloques 2,
|
||||
# 3 (inventario), 4 y 5 de Investigacion-API-Jira.md. Ninguna llamada muta nada.
|
||||
#
|
||||
# Requisitos: el token en propuesta/token-jira.txt (gitignoreado) o en $JIRA_TOKEN.
|
||||
# Uso: ./pruebas-jira-lectura.sh [directorio_salida]
|
||||
# La salida VA FUERA DEL REPO por default (los tickets traen datos reales de
|
||||
# clientes): /tmp/jira-probes-<fecha>. Al repo solo se llevan los hallazgos
|
||||
# agregados, transcritos a mano a Investigacion-API-Jira.md.
|
||||
set -euo pipefail
|
||||
|
||||
SITE="https://balam-jsm-temp.atlassian.net"
|
||||
EMAIL="pedro.ayala@balamtalentoestrategico.com"
|
||||
REPO_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
TOKEN="${JIRA_TOKEN:-$(cat "$REPO_DIR/propuesta/token-jira.txt" 2>/dev/null || true)}"
|
||||
if [ -z "$TOKEN" ]; then
|
||||
echo "ERROR: token no encontrado (propuesta/token-jira.txt o \$JIRA_TOKEN)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OUT="${1:-/tmp/jira-probes-$(date +%Y%m%d-%H%M%S)}"
|
||||
mkdir -p "$OUT"
|
||||
AUTH="$EMAIL:$TOKEN"
|
||||
|
||||
req() { # req <nombre> <ruta> — guarda body y headers, imprime status + rate limit
|
||||
local name="$1" path="$2"
|
||||
local hdr="$OUT/$name.headers" body="$OUT/$name.json"
|
||||
local status
|
||||
status=$(curl -sS -u "$AUTH" -H "Accept: application/json" \
|
||||
-D "$hdr" -o "$body" -w "%{http_code}" "$SITE$path")
|
||||
local rate
|
||||
rate=$(grep -i "x-ratelimit" "$hdr" | tr -d '\r' | paste -sd' ' - || true)
|
||||
echo "[$status] $name ${rate:-(sin headers de rate limit)}"
|
||||
}
|
||||
|
||||
echo "== Bloque 0 · auth =="
|
||||
req myself "/rest/api/3/myself"
|
||||
|
||||
echo "== Bloque 4 · búsqueda vigente, fields acotados y tope de maxResults =="
|
||||
req search-recientes "/rest/api/3/search/jql?jql=$(python3 -c 'import urllib.parse;print(urllib.parse.quote("project = FAC ORDER BY updated DESC"))')&maxResults=10&fields=summary,status,updated,created,issuetype,reporter"
|
||||
req search-tope "/rest/api/3/search/jql?jql=$(python3 -c 'import urllib.parse;print(urllib.parse.quote("project = FAC"))')&maxResults=5000&fields=id"
|
||||
req search-delta "/rest/api/3/search/jql?jql=$(python3 -c 'import urllib.parse;print(urllib.parse.quote("project = FAC AND updated >= \"-20m\" ORDER BY updated ASC"))')&fields=updated"
|
||||
|
||||
echo "== Bloque 5 · origen de los tickets (changelog de los 8 más recientes) =="
|
||||
python3 - "$OUT" <<'PY'
|
||||
import json, sys, subprocess, os
|
||||
out = sys.argv[1]
|
||||
data = json.load(open(f"{out}/search-recientes.json"))
|
||||
keys = [(i["id"], i["key"]) for i in data.get("issues", [])][:8]
|
||||
open(f"{out}/ids-muestra.txt", "w").write("\n".join(f"{i} {k}" for i, k in keys))
|
||||
print("muestra:", ", ".join(k for _, k in keys))
|
||||
PY
|
||||
while read -r id key; do
|
||||
req "issue-$key" "/rest/api/3/issue/$id?expand=changelog&fields=summary,status,issuetype,created,reporter,attachment,description,resolution"
|
||||
done < "$OUT/ids-muestra.txt"
|
||||
|
||||
echo "== Bloque 3 · transiciones con campos obligatorios (2 tickets de la muestra) =="
|
||||
head -2 "$OUT/ids-muestra.txt" | while read -r id key; do
|
||||
req "transitions-$key" "/rest/api/3/issue/$id/transitions?expand=transitions.fields"
|
||||
done
|
||||
|
||||
echo "== Bloque 2 · request types faltantes (12 Facturación, 389 Automatización) =="
|
||||
req requesttype-12 "/rest/servicedeskapi/servicedesk/35/requesttype/12/field"
|
||||
req requesttype-389 "/rest/servicedeskapi/servicedesk/35/requesttype/389/field"
|
||||
|
||||
echo "== Resumen para transcribir a Investigacion-API-Jira.md =="
|
||||
python3 - "$OUT" <<'PY'
|
||||
import json, sys, glob, os
|
||||
out = sys.argv[1]
|
||||
|
||||
def load(n):
|
||||
try: return json.load(open(f"{out}/{n}.json"))
|
||||
except Exception: return None
|
||||
|
||||
tope = load("search-tope")
|
||||
if tope: print(f"- maxResults efectivo con 5000 pedidos: {len(tope.get('issues', []))} issues devueltos; isLast={tope.get('isLast')}")
|
||||
delta = load("search-delta")
|
||||
if delta is not None: print(f"- delta 20m: {len(delta.get('issues', []))} tickets actualizados en la ventana")
|
||||
|
||||
moves = 0
|
||||
for f in sorted(glob.glob(f"{out}/issue-*.json")):
|
||||
d = load(os.path.basename(f)[:-5])
|
||||
if not d: continue
|
||||
key = d.get("key", "?")
|
||||
fields = d.get("fields", {})
|
||||
hist = (d.get("changelog") or {}).get("histories", []) or (d.get("changelog") or {}).get("values", [])
|
||||
key_changes = [i for h in hist for i in h.get("items", []) if i.get("field") in ("Key", "project")]
|
||||
if key_changes: moves += 1
|
||||
att = fields.get("attachment") or []
|
||||
desc = fields.get("description")
|
||||
desc_len = len(json.dumps(desc)) if desc else 0
|
||||
total_hist = (d.get("changelog") or {}).get("total", len(hist))
|
||||
print(f"- {key}: type={ (fields.get('issuetype') or {}).get('name') } · status={(fields.get('status') or {}).get('name')} · "
|
||||
f"resolution={(fields.get('resolution') or {}).get('name') if fields.get('resolution') else None} · "
|
||||
f"adjuntos={len(att)} · descripcion_adf={desc_len}B · changelog(total={total_hist}, en_expand={len(hist)})"
|
||||
f"{' · ⚠️ MOVE/KEY-CHANGE detectado' if key_changes else ''}")
|
||||
print(f"- tickets con move/cambio de llave en la muestra: {moves}")
|
||||
print(f"\nBodies completos en: {out} (NO copiar al repo: contienen datos reales)")
|
||||
PY
|
||||
Reference in New Issue
Block a user