Migración a Python/Flask y adaptación para proyecto Infra

- Reemplaza Netlify Functions con servidor Python/Flask (server.py)
- Adapta dashboard para contar tickets en lugar de Story Points
- Conecta al proyecto IO (Infra) de Jira
- Elimina secciones de QA y Code Review
- Agrega métricas de solicitudes semanales y reporters
- Excluye devs inactivos y unifica nombres duplicados

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
juan.beldomenico
2026-04-27 15:09:04 -03:00
parent 76edc176f9
commit 695401f237
7 changed files with 711 additions and 427 deletions
+15 -218
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard LABS — Story Points</title>
<title>Dashboard Infra — Tickets</title>
<link rel="stylesheet" href="./css/styles.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.min.js"></script>
<script type="module" src="./js/app.js" defer></script>
@@ -23,9 +23,9 @@
<!-- Header Principal -->
<header>
<div>
<h1>📊 Dashboard LABS — Story Points</h1>
<h1>📊 Dashboard Infra</h1>
<div style="font-size:13px;opacity:.7;margin-top:4px;">
Proyecto: <strong>LABS</strong> · invera.atlassian.net
Proyecto: <strong>Infra</strong> · invera.atlassian.net
</div>
</div>
<div class="header-meta">
@@ -59,14 +59,14 @@
<div class="main">
<div class="section-block">
<div class="kpi-row">
<div class="kpi progress" title="Suma de Story Points (SP) de todos los tickets actualmente en la columna En Progreso"><div class="kpi-value" id="kpi-ip">—</div><div class="kpi-label">SP En Progreso</div><div class="kpi-sub">Trabajo en curso</div></div>
<div class="kpi todo" title="Suma de Story Points de tickets pendientes que aún no comenzaron"><div class="kpi-value" id="kpi-todo">—</div><div class="kpi-label">SP Por Hacer</div><div class="kpi-sub">Backlog del periodo</div></div>
<div class="kpi members" title="Cantidad de personas con carga de trabajo (tickets) asignados en este momento"><div class="kpi-value" id="kpi-members">—</div><div class="kpi-label">Devs con Carga</div><div class="kpi-sub">Con tickets pendientes</div></div>
<div class="kpi progress" title="Tickets actualmente en la columna En Progreso"><div class="kpi-value" id="kpi-ip">—</div><div class="kpi-label">Tickets En Progreso</div><div class="kpi-sub">Trabajo en curso</div></div>
<div class="kpi todo" title="Tickets pendientes que aún no comenzaron"><div class="kpi-value" id="kpi-todo">—</div><div class="kpi-label">Tickets Por Hacer</div><div class="kpi-sub">Backlog del periodo</div></div>
<div class="kpi members" title="Cantidad de personas con tickets asignados en este momento"><div class="kpi-value" id="kpi-members">—</div><div class="kpi-label">DevOps</div><div class="kpi-sub">Con tickets pendientes</div></div>
</div>
<div class="charts-grid">
<div class="chart-card">
<h3>🔵 Pendientes por Desarrollador</h3>
<h3>🔵 Tkt pendientes</h3>
<div class="sub">Story Points con trabajo pendiente</div>
<div style="position:relative;height:260px"><canvas id="chartCurrentState"></canvas></div>
</div>
@@ -96,7 +96,7 @@
<div class="table-card">
<h3>Detalle de Carga de Trabajo</h3>
<table>
<thead><tr><th>Desarrollador</th><th>🔵 En Progreso</th><th>⏳ Por Hacer</th><th>Total Pendiente</th><th>Carga Visual</th></tr></thead>
<thead><tr><th>Desarrollador</th><th>🔵 En Progreso</th><th>⏳ Por Hacer</th><th>Total Pendiente</th><th>Distribución</th></tr></thead>
<tbody id="tableCurrentState"></tbody>
</table>
</div>
@@ -114,25 +114,20 @@
<div class="main">
<div class="section-block">
<div class="kpi-row-3">
<div class="kpi done" title="Suma total de Story Points entregados y completados en el período de tiempo seleccionado"><div class="kpi-value" id="kpi-done-period">—</div><div class="kpi-label">SP Completados</div><div class="kpi-sub">en el período</div></div>
<div class="kpi members" title="Cantidad de desarrolladores que han cerrado al menos 1 Story Point en este período"><div class="kpi-value" id="kpi-devs-period">—</div><div class="kpi-label">Desarrolladores</div><div class="kpi-sub">que completaron SP</div></div>
<div class="kpi progress" title="Promedio simple: Total de SP completados dividido por la cantidad de desarrolladores"><div class="kpi-value" id="kpi-avg-period">—</div><div class="kpi-label">SP promedio / dev</div><div class="kpi-sub">en el período</div></div>
</div>
<div class="kpi-row-3" style="margin-top:-8px;">
<div class="kpi" style="border-color:#36b37e;" title="Lead Time: Tiempo total promedio que vive un ticket desde su creación hasta que es cerrado"><div class="kpi-value" id="kpi-lead-time">—</div><div class="kpi-label">Promedio Lead Time</div><div class="kpi-sub">Días (Creación a Fin)</div></div>
<div class="kpi" style="border-color:#00b8d9;" title="Cycle Time: Velocidad de desarrollo neto. Promedio en días desde que un developer mueve el ticket 'En Curso' hasta cerrarse"><div class="kpi-value" id="kpi-cycle-time">—</div><div class="kpi-label">Promedio Cycle Time</div><div class="kpi-sub">Días (En Curso a Fin)</div></div>
<div class="kpi warning" title="Variación entre el Story Point estimado al sprint vs el final real; un número en (+) indica Scope Creep (inflación de puntos)"><div class="kpi-value" id="kpi-sp-deviation">—</div><div class="kpi-label">Desviación SP</div><div class="kpi-sub" id="kpi-sp-deviation-sub">Original vs Final</div></div>
<div class="kpi done" title="Total de tickets completados en el período de tiempo seleccionado"><div class="kpi-value" id="kpi-done-period">—</div><div class="kpi-label">Tickets Completados</div><div class="kpi-sub">en el período</div></div>
<div class="kpi progress" title="Promedio de tickets resueltos por semana en el período seleccionado"><div class="kpi-value" id="kpi-avg-period">—</div><div class="kpi-label">Promedio tkts / semana</div><div class="kpi-sub" id="kpi-avg-period-sub">tickets por semana</div></div>
<div class="kpi" style="border-color:#6554c0;" title="Promedio de tickets nuevos solicitados por semana en el período seleccionado"><div class="kpi-value" id="kpi-created-week">—</div><div class="kpi-label">Tkts solicitados / semana</div><div class="kpi-sub" id="kpi-created-week-sub">tickets por semana</div></div>
</div>
<div class="charts-grid">
<div class="chart-card">
<h3>✅ SP Completados — por Desarrollador</h3>
<h3>✅ Tickets Completados</h3>
<div class="sub">Período seleccionado</div>
<div style="position:relative;height:260px"><canvas id="chartDoneDev"></canvas></div>
</div>
<div class="chart-card">
<h3>📈 Velocidad Histórica</h3>
<div class="sub">SP completados mes a mes</div>
<h3>📥 Solicitudes de Tickets</h3>
<div class="sub">Tickets creados por persona en el período</div>
<div style="position:relative;height:260px"><canvas id="chartVelocity"></canvas></div>
</div>
</div>
@@ -143,7 +138,7 @@
<span id="teamAvgLabel" style="font-size:12px; font-weight:normal; background:#e6fcff; color:#0065ff; padding:4px 8px; border-radius:4px; display:none;"></span>
</h3>
<table>
<thead><tr><th>Desarrollador</th><th>✅ SP Total</th><th>🎟️ Tickets</th><th>📉 Media SP/Ticket</th><th>% del impacto total vs Equipo</th></tr></thead>
<thead><tr><th>Desarrollador</th><th>✅ Tickets Total</th><th>📉 % del equipo</th></tr></thead>
<tbody id="tableHistory"></tbody>
</table>
</div>
@@ -153,207 +148,9 @@
<!-- ── SECCIÓN: Revisión de Código (Code Review) ── -->
<div class="section-header" style="border-color:#00b8d9;">
<div class="dot" style="background:#00b8d9;"></div>
<h2>Revisión de Código (Code Review)</h2>
<span style="font-size:12px;color:#5e6c84;margin-left:8px;">Métricas de revisión entre pares antes de QA</span>
</div>
<div class="main">
<div class="section-block">
<!-- Colas Actuales -->
<div class="kpi-row" style="margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #dfe1e6;">
<div class="kpi warning" style="border-color:#ff8b00;" title="Tickets que se encuentran en este preciso instante en la columna Code Review esperando o siendo revisados">
<div class="kpi-value" id="kpi-cr-queue-now">—</div>
<div class="kpi-label">En Cola Actual CR</div>
<div class="kpi-sub" id="kpi-cr-queue-sp">— SP en espera</div>
</div>
<div class="kpi warning" title="Tickets que se encuentran actualmente y desde hace más de 2 días atascados solos en la columna de revisión">
<div class="kpi-value" id="kpi-cr-stalled">—</div>
<div class="kpi-label">Tickets Atascados CR</div>
<div class="kpi-sub">Demorados actualmente (más de 2 días)</div>
</div>
</div>
<!-- Historial del período -->
<h3 style="font-size:14px; margin-bottom:12px; color:#172b4d;">Métricas del período seleccionado</h3>
<div class="kpi-row">
<div class="kpi" style="border-color:#00b8d9;" title="Cantidad de tickets que registraron actividad en la fase de Code Review">
<div class="kpi-value" id="kpi-cr-tickets">—</div>
<div class="kpi-label">Tickets en CR</div>
<div class="kpi-sub">Procesados en el período</div>
</div>
<div class="kpi" style="border-color:#00b8d9;">
<div class="kpi-value" id="kpi-cr-p50">—</div>
<div class="kpi-label">
<div class="pop-trigger" style="border-bottom: 1px dotted #5e6c84;">Tiempo P50 CR
<div class="pop-content" style="text-transform:none; font-weight:normal; letter-spacing:normal; text-align:left;">
<div class="pop-item" style="font-size:12px;"><strong>Percentil 50 (Mediana)</strong><br>El 50% de las revisiones de código se completan en esta cantidad de horas o menos.<br><br>A diferencia del promedio tradicional, el P50 muestra un valor "habitual" sin ser distorsionado por tickets que queden atascados durante meses.</div>
</div>
</div>
</div>
<div class="kpi-sub">Horas (Mediana)</div>
</div>
<div class="kpi" style="border-color:#ff8b00;">
<div class="kpi-value" id="kpi-cr-p90">—</div>
<div class="kpi-label">
<div class="pop-trigger" style="border-bottom: 1px dotted #5e6c84;">Tiempos P90 y P99
<div class="pop-content" style="text-transform:none; font-weight:normal; letter-spacing:normal; text-align:left;">
<div class="pop-item" style="font-size:12px;"><strong>Métricas de Cuello de Botella</strong><br>Muestran los "peores escenarios" posibles.<br><br><strong>P90:</strong> El 90% de los tickets logra pasar en este tiempo. El 10% restante demoró aún más.<br><strong>P99:</strong> El 99% pasa en este tiempo. Ideal para medir los bloqueos máximos.</div>
</div>
</div>
</div>
<div class="kpi-sub" id="kpi-cr-p99-sub">P99: — hs</div>
</div>
</div>
<div class="charts-grid">
<div class="chart-card full">
<h3>📈 Tiempo Promedio en Code Review — Mes a Mes</h3>
<div class="sub">Evolución de la velocidad de revisión de pares (horas)</div>
<div style="position:relative;height:240px"><canvas id="chartCrMonthly"></canvas></div>
</div>
</div>
</div>
</div>
<!-- ── SECCIÓN 3: Control de Calidad (QA) ── -->
<div class="section-header qa">
<div class="dot qa"></div>
<h2>Control de Calidad (QA)</h2>
<span style="font-size:12px;color:#5e6c84;margin-left:8px;">Métricas del proceso de QA · Tiempos, colas y devoluciones</span>
</div>
<div class="main">
<div class="section-block">
<!-- Colas Actuales -->
<div class="kpi-row" style="margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #dfe1e6;">
<div class="kpi qa-queue" style="border-color:#ff8b00;" title="Tickets que se encuentran en este preciso instante en la columna Ready to QA">
<div class="kpi-value" id="kpi-qa-queue-now">—</div>
<div class="kpi-label">En Cola Actual RTQA</div>
<div class="kpi-sub" id="kpi-qa-queue-now-sp">— SP esperando</div>
</div>
<div class="kpi qa" style="border-color:#0065ff;" title="Tickets que se encuentran en este preciso instante siendo probados en la columna QA">
<div class="kpi-value" id="kpi-qa-active-now">—</div>
<div class="kpi-label">En Cola Actual QA</div>
<div class="kpi-sub" id="kpi-qa-active-now-sp">— SP en prueba</div>
</div>
</div>
<!-- KPIs del período -->
<h3 style="font-size:14px; margin-bottom:12px; color:#172b4d;">Métricas del período seleccionado</h3>
<div class="kpi-row-3" style="margin-bottom:16px;">
<div class="kpi qa" title="Total de tickets que han pasado por QA">
<div class="kpi-value" id="kpi-qa-tickets">—</div>
<div class="kpi-label">Tickets QA</div>
<div class="kpi-sub">Procesados en el período</div>
</div>
<div class="kpi qa-time">
<div class="kpi-value" id="kpi-qa-p50">—</div>
<div class="kpi-label">
<div class="pop-trigger" style="border-bottom: 1px dotted #5e6c84;">Tiempo P50 QA
<div class="pop-content" style="text-transform:none; font-weight:normal; letter-spacing:normal; text-align:left;">
<div class="pop-item" style="font-size:12px;"><strong>Percentil 50 (Mediana)</strong><br>El 50% de las pruebas se completan en esta cantidad de horas netas o menos.</div>
</div>
</div>
</div>
<div class="kpi-sub">Horas en prueba</div>
</div>
<div class="kpi qa-time" style="border-color:#ff8b00;">
<div class="kpi-value" id="kpi-qa-p90">—</div>
<div class="kpi-label">
<div class="pop-trigger" style="border-bottom: 1px dotted #5e6c84;">Tiempos P90 y P99 QA
<div class="pop-content" style="text-transform:none; font-weight:normal; letter-spacing:normal; text-align:left;">
<div class="pop-item" style="font-size:12px;"><strong>Cuellos de Botella QA</strong><br><strong>P90:</strong> El 90% logran probarse en este tiempo.<br><strong>P99:</strong> El 99% logra terminar en este tiempo.</div>
</div>
</div>
</div>
<div class="kpi-sub" id="kpi-qa-p99-sub">P99: — hs</div>
</div>
</div>
<div class="kpi-row-3">
<div class="kpi returned" title="Tickets que sufrieron rechazos en revisiones (Code Review, Ready to QA o QA) y volvieron a desarrollo.">
<div class="kpi-value" id="kpi-qa-returned">—</div>
<div class="kpi-label">Tickets con Retrabajo</div>
<div class="kpi-sub" id="kpi-qa-returned-pct">Sufrieron rechazos</div>
</div>
<div class="kpi qa-queue">
<div class="kpi-value" id="kpi-qa-rtqa-p50">—</div>
<div class="kpi-label">
<div class="pop-trigger" style="border-bottom: 1px dotted #5e6c84;">Tiempo P50 RTQA
<div class="pop-content" style="text-transform:none; font-weight:normal; letter-spacing:normal; text-align:left;">
<div class="pop-item" style="font-size:12px;"><strong>Percentil 50 (Mediana)</strong><br>El 50% de los tickets espera esta cantidad de horas (o menos) en la cola antes de ser tomado por QA.</div>
</div>
</div>
</div>
<div class="kpi-sub">Horas en cola</div>
</div>
<div class="kpi qa-queue" style="border-color:#ff8b00;">
<div class="kpi-value" id="kpi-qa-rtqa-p90">—</div>
<div class="kpi-label">
<div class="pop-trigger" style="border-bottom: 1px dotted #5e6c84;">Tiempos P90 y P99 Cola
<div class="pop-content" style="text-transform:none; font-weight:normal; letter-spacing:normal; text-align:left;">
<div class="pop-item" style="font-size:12px;"><strong>Cuellos de Botella RTQA</strong><br>Casos atascados sin tester asignado.<br><br><strong>P90:</strong> El 90% de los tickets sale de la cola en este tiempo.<br><strong>P99:</strong> Bloqueos máximos en la cola.</div>
</div>
</div>
</div>
<div class="kpi-sub" id="kpi-qa-rtqa-p99-sub">P99: — hs</div>
</div>
</div>
<!-- Gráficos fila 1 -->
<div class="charts-grid">
<div class="chart-card">
<h3>📊 Distribución de Tiempos en QA</h3>
<div class="sub">Rangos: &lt;30min · 30min–2hs · 2–8hs · &gt;8hs</div>
<div style="position:relative;height:240px"><canvas id="chartQaDist"></canvas></div>
</div>
<div class="chart-card">
<h3>🔄 Flujo Directo vs Retrabajo</h3>
<div class="sub">Tickets con 0 rechazos vs con devoluciones (CR/QA)</div>
<div style="position:relative;height:240px"><canvas id="chartQaReturned"></canvas></div>
</div>
</div>
<!-- Gráficos fila 2 -->
<div class="charts-grid">
<div class="chart-card">
<h3>📈 Tiempo Promedio en QA — Mes a Mes</h3>
<div class="sub">Evolución de la velocidad de revisión (horas)</div>
<div style="position:relative;height:240px"><canvas id="chartQaMonthly"></canvas></div>
</div>
<div class="chart-card">
<h3>⏳ Tiempo en Cola RTQA — Mes a Mes</h3>
<div class="sub">Horas promedio esperando ser tomado por QA</div>
<div style="position:relative;height:240px"><canvas id="chartRtqaMonthly"></canvas></div>
</div>
</div>
<!-- Tabla de tickets QA -->
<div class="table-card">
<h3>🔍 Detalle de Tickets — QA</h3>
<table>
<thead>
<tr>
<th>Ticket</th>
<th>Resumen</th>
<th>⏱️ Dev (hs)</th>
<th>⏱️ CR (hs)</th>
<th>⏱️ QA (hs)</th>
<th>🔄 Veces devuelto</th>
<th>Estado</th>
</tr>
</thead>
<tbody id="tableQA"></tbody>
</table>
</div>
</div>
</div>
<footer>
Dashboard en tiempo real · Arquitectura Modular Serverless · Realizado para Vercel & Jira
</footer>