feat(sprint-1.5): rediseño visual PDF ROI + identidad InQ (Etapas 4-7)

- Header/footer compartidos con paleta InQ naranja en los 3 PDFs (Etapa 4)
- Layout híbrido portrait+landscape en PDFs Actual/Automatizado:
  página 2 landscape para diagrama BPMN heatmap (Etapa 5)
- Página 1 PDF ROI rediseñada: header denso, banner narrativo, KPI Hero
  con gradiente naranja→magenta, grid 2×2 de KPIs secundarios, Top 3
  actividades por ahorro (Etapa 6)
- Páginas 2-5 PDF ROI con identidad InQ: tabla con paleta naranja,
  análisis del ahorro, nota metodológica, trayectoria del ahorro
  acumulado con gráfico SVG nativo (Etapa 7)
- 500 tests verdes (+ 34 tests nuevos del Sprint 1.5)
- BACKLOG.md, TECH_DEBT.md, OBSERVATIONS.md: sistema de planificación
  reemplaza TODO.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-17 20:45:01 -03:00
parent 63c4fbac99
commit 2f4633a33c
20 changed files with 4163 additions and 117 deletions

View File

@@ -0,0 +1,452 @@
# Sprint 1.5 — Etapa 7: PDF ROI — Páginas 2-5 con identidad InQ
> **Objetivo:** completar el rediseño del PDF ROI aplicando identidad InQ a las páginas 2, 3 y 4. Implementar la trayectoria del ahorro acumulado en la página 5 (que en Etapa 6 quedó como placeholder).
>
> **Pre-requisitos:** Etapa 6 cerrada — Página 1 del PDF ROI con KPI Hero gradiente, banner narrativo, grid 2x2, Top 3. PDF ROI con 5 páginas (página 5 placeholder).
>
> **Etapa siguiente:** Etapa 8 — PDFs Actual y Automatizado con identidad InQ aplicada (rediseño consistente con el ROI).
---
## 1. Alcance estricto
### Sí entra
- ✅ Página 2 (Comparación por actividad) — aplicar paleta naranja a tabla, mantener estructura
- ✅ Página 3 (Análisis del ahorro + Transparencia metodológica) — rediseñar con paleta InQ
- ✅ Página 4 (Nota metodológica) — paleta InQ aplicada
- ✅ Página 5 (NUEVA — Trayectoria del ahorro acumulado) — gráfico SVG nativo en jsPDF (sin html2canvas)
- ✅ Mantener consistencia visual con la página 1 ya rediseñada
### NO entra
- ❌ Modificar la página 1 (cerrada en Etapa 6)
- ❌ Refinamientos visuales del KPI Hero, Top 3, banner narrativo (agendados para Etapa 11 — polish final)
- ❌ Resolver fórmulas truncadas en nota metodológica (Sprint 2 — font embedding)
- ❌ Resolver caracteres Unicode rotos en general (Sprint 2)
- ❌ Modificar PDFs Actual y Automatizado (Etapa 8)
---
## 2. Decisiones ya tomadas (no consultar de nuevo)
| Decisión | Justificación |
|---|---|
| Trayectoria del ahorro: SVG nativo en jsPDF (no html2canvas) | Brief sección 3.2 — html2canvas borrosea el chart |
| Trayectoria empieza en (Año 0, -inversión), no en (0, 0) | Decisión Etapa 3 — TODO.md |
| Tabla comparativa con header naranja `#FFF8ED` + border-bottom `#F59845` | Brief sección 2.5 |
| Sección Transparencia con fondo `#FFFBEB` + border `#F59E0B` | Brief sección 2.4 (warning) |
| PDF ROI mantiene 5 páginas | Decisión Etapa 6 |
| Nota metodológica con caracteres Unicode rotos se mantiene | Sprint 2 |
---
## 3. Especificación detallada por página
### 3.1 Página 2 — Comparación por actividad
**Estado actual (post-Etapa 6):**
- Header denso ✓
- Tabla con `Actividad / Act. (USD) / Auto. (USD) / Ahorro (USD) / Ahorro % / Prob.`
- Texto "(*) Actividades en negrita están marcadas como automatizables"
- Footer "Página 2 de 5"
**Cambios en Etapa 7:**
```
TABLA (autotable):
Header row:
- Fondo: #FFF8ED (inq-orange-lighter)
- Border-bottom: 1.5pt solid #F59845
- Padding: 8pt 6pt
- Texto: 10pt / peso 500 / color #92400E (inq-orange-dark)
- Letter-spacing: 0.5pt
- Uppercase
Body row (default / actividad automatizable):
- Fondo: white
- Border-bottom: 0.5pt solid #E2E8F0
- Padding: 7pt 6pt
- Texto: 10pt / peso 400 / color #0F172A
- Números: font mono, color #0F172A
Body row (actividad NO automatizable):
- Fondo: #F8FAFC (slate-50)
- Texto: color #94A3B8 (más tenue)
- Em dash "—" en columnas Ahorro y Ahorro %
Total row (si aplica):
- Fondo: #FFF8ED
- Border-top: 1.5pt solid #F59845
- Texto: 10pt / peso 500 / color #0F172A
```
**Mantener el texto "(*) Actividades en negrita..."** con el formato actual.
### 3.2 Página 3 — Análisis del ahorro + Transparencia
**Estado actual (post-Etapa 6):**
- Título "Análisis del ahorro"
- Sección "Composición del ahorro" con 3 bullets de actividades
- Sección "Trayectoria del ahorro acumulado" (texto narrativo)
- Sección "Transparencia metodológica" con caja ámbar (cuando aplica)
- Footer "Página 3 de 5"
**Cambios en Etapa 7:**
**Sección "Composición del ahorro":**
```
Título:
- Texto: "COMPOSICIÓN DEL AHORRO"
- Tamaño: 11pt
- Peso: 500
- Color: #92400E (inq-orange-dark)
- Letter-spacing: 1pt
- Uppercase
- Margin-bottom: 8mm
Texto descriptivo:
- Tamaño: 11pt
- Color: #0F172A
- Line-height: 1.5
- Margin-bottom: 6mm
Bullets:
- Bullet symbol: "•"
- Texto: 10pt / color #475569
- Línea: " • [actividad]: USD [N] ([NN]% del ahorro total)"
- Margin-bottom: 3mm cada uno
```
**Sección "Trayectoria del ahorro acumulado" (texto):**
```
Mantener el bloque narrativo actual. Aplicar paleta:
- Título: 11pt / peso 500 / color #92400E / uppercase
- Texto: 11pt / color #475569 / line-height 1.5
NOTA: el gráfico de la trayectoria va en página 5, no acá. En esta
página solo el texto narrativo descriptivo.
```
**Sección "Transparencia metodológica" (cuando aplica):**
```
Caja:
- Fondo: #FFFBEB (warning-bg)
- Border: 0.5pt solid #F59E0B (warning)
- Padding: 12pt 14pt
- Border-radius: 6pt
- Margin-top: 10mm
Título:
- Texto: "⚠ Transparencia metodológica"
- Tamaño: 11pt
- Peso: 500
- Color: #92400E
- NOTA: el ⚠ (U+26A0) puede no renderizar. Si no funciona, usar
texto plano "[!]" o "Transparencia metodológica" sin símbolo.
Texto:
- Tamaño: 10pt
- Peso: 400
- Color: #78350F (text on warning)
- Line-height: 1.6
Bullets de casos (cuando ROI > 1000%):
- Frecuencia anual del proceso sobreestimada
- Costo automatizado por ejecución subestimado
- Inversión en automatización subestimada
Formato:
- "• [caso]" con bullet symbol •
- Margin-bottom 3mm
```
### 3.3 Página 4 — Nota metodológica
**Estado actual (post-Etapa 6):**
- Sigue con caracteres `£` (Σ) y `"` () rotos. Decisión Sprint 2.
**Cambios en Etapa 7:**
```
Título:
- Texto: "NOTA METODOLÓGICA — ANÁLISIS DE ROI"
- Tamaño: 11pt
- Peso: 500
- Color: #92400E (inq-orange-dark)
- Letter-spacing: 1pt
- Uppercase
- Margin-bottom: 10mm
Caja contenedora (opcional, sutil):
- Fondo: #F8FAFC (slate-50)
- Padding: 14pt
- Border-radius: 4pt
- Border-left: 2pt solid #94A3B8 (text-tertiary)
Cada fórmula (5-6 bloques):
Sub-título:
- Tamaño: 10pt
- Peso: 600
- Color: #0F172A
- Margin-bottom: 2mm
Fórmula:
- Tamaño: 10pt
- Font-family: mono (para alineación)
- Color: #475569
- Line-height: 1.5
- Margin-bottom: 6mm
```
**Mantener el contenido textual actual:**
- Costo por ejecución actual
- Costo por ejecución automatizado
- Ahorro anual
- Payback (meses)
- Ahorro acumulado
- ROI anualizado
### 3.4 Página 5 — Trayectoria del ahorro acumulado (NUEVA)
Esta es la página técnicamente más compleja de Etapa 7. Reemplaza el placeholder de Etapa 6.
**Layout vertical de la página 5:**
```
┌─────────────────────────────────────────────────────────┐
│ HEADER ESTÁNDAR │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ TÍTULO: TRAYECTORIA DEL AHORRO ACUMULADO │
│ │
│ Subtítulo narrativo (1-2 líneas): │
│ "Evolución del ahorro neto acumulado a lo largo del │
│ horizonte de [N] años. El payback se alcanza en el │
│ mes [N]." │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ GRÁFICO SVG NATIVO (60-70% del alto disponible) │
│ │
│ Eje Y (USD acumulado): │
│ - 0 al medio │
│ - Rango: de -inversion a +max_acumulado │
│ │
│ Eje X (tiempo en meses o años): │
│ - 0 a horizon_months │
│ - Labels: "Año 0", "Año 1", "Año 2", "Año 3" │
│ │
│ Curva: │
│ - Inicio: (Año 0, -inversion) → punto rojo │
│ - Cruza el cero en payback_month → marker │
│ - Final: (Año N, ahorro_acumulado_final) │
│ │
│ Área NEGATIVA (antes del payback): │
│ - Fill: #FEE2E2 (light red) │
│ │
│ Área POSITIVA (después del payback): │
│ - Fill: #FED7AA (light orange) │
│ │
│ Línea principal: │
│ - Color: #F59845 (inq-orange) │
│ - Grosor: 1.5pt │
│ │
│ Marker vertical en payback: │
│ - Línea vertical punteada, color #B45309 │
│ - Label "Payback: [N.N] meses" (offset 4mm a la │
│ derecha del marker para no superponer eje Y) │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ ANOTACIONES (al pie del gráfico): │
│ - Inversión inicial: USD [N] │
│ - Ahorro acumulado al final: USD [N] │
│ - Multiplicador de retorno: [N.N]× la inversión │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ FOOTER: Página 5 de 5 │
└─────────────────────────────────────────────────────────┘
```
**Implementación técnica del gráfico SVG nativo:**
Usar primitivas de jsPDF directamente (`doc.line`, `doc.rect`, `doc.text`, `doc.setFillColor`, `doc.setDrawColor`). **NO usar html2canvas** — el chart se ve borroso con conversión a imagen.
Pseudocódigo:
```typescript
function drawTrajectoryChart(doc, config) {
const { x, y, width, height, data, paybackMonth, currency } = config;
// 1. Dibujar ejes
const yZero = y + (height * (data.maxNegative / (data.maxPositive - data.maxNegative)));
doc.setDrawColor(148, 163, 184); // text-tertiary
doc.line(x, yZero, x + width, yZero); // eje X (en y=0)
doc.line(x, y, x, y + height); // eje Y
// 2. Dibujar área negativa (antes del payback)
doc.setFillColor(254, 226, 226); // #FEE2E2
// ... path complejo
// 3. Dibujar área positiva (después del payback)
doc.setFillColor(254, 215, 170); // #FED7AA
// ... path complejo
// 4. Dibujar línea principal
doc.setDrawColor(245, 152, 69); // #F59845
doc.setLineWidth(1.5);
// doc.lines() para path de la línea
// 5. Dibujar marker de payback
doc.setDrawColor(180, 83, 9); // #B45309
doc.setLineDashPattern([2, 2], 0);
// línea vertical en x = payback
// 6. Labels de ejes
doc.setFontSize(8);
doc.setTextColor(100, 116, 139);
// labels "Año 0", "Año 1", etc.
// 7. Label del payback (offset a la derecha)
doc.text("Payback: " + formatPayback(paybackMonth),
x_payback + 4, y_payback);
}
```
**Datos para construir el gráfico:**
```typescript
// Cálculo de la trayectoria
const monthsArray = Array.from({length: horizonMonths + 1}, (_, i) => i);
const trajectoryData = monthsArray.map(month => ({
month,
acumulado: -inversion + (annualSavings / 12) * month
}));
// Encontrar el mes exacto del payback (cuando acumulado cruza 0)
const paybackMonth = inversion / (annualSavings / 12);
```
---
## 4. Validaciones automatizadas mandatorias
```
PDF ROI debe cumplir:
1. 5 páginas, todas portrait
2. Página 5 ahora tiene contenido real (NO placeholder):
- Título "TRAYECTORIA DEL AHORRO ACUMULADO" presente
- Gráfico SVG embebido (detectado por análisis de píxeles: presencia
de naranja #F59845 + áreas rojas/naranjas claras)
- Anotaciones al pie con cifras
3. Página 2 (Tabla):
- Header de tabla con fondo naranja claro (#FFF8ED visible en análisis)
- Border-bottom naranja en header
- Em dash "—" en filas no automatizables (Ahorro y Ahorro %)
4. Página 3 (Análisis + Transparencia):
- Título "COMPOSICIÓN DEL AHORRO" en naranja oscuro
- Caja de Transparencia presente cuando ROI > 1000% (fondo ámbar)
- Bullets de casos (cuando aplica)
5. Página 4 (Nota metodológica):
- Título "NOTA METODOLÓGICA — ANÁLISIS DE ROI" en naranja oscuro
- 5-6 sub-secciones con fórmulas
- Caracteres £ y " todavía rotos (Sprint 2) — esperado
6. Sin regresiones:
- Página 1 SIN CAMBIOS visualmente
- Footers correctos en todas las páginas (1, 2, 3, 4, 5 de 5)
- "InQ ROI", "Powered by InQuality" presentes
- "Process Cost Platform" ausente
7. PDFs Actual y Automatizado: idénticos a Etapa 6
8. Tests previos verdes: ≥ 483 + nuevos de Etapa 7
```
---
## 5. Entregables (Definition of Done)
```
[ ] Página 2 (Tabla) con paleta InQ aplicada
[ ] Página 3 (Análisis + Transparencia) con paleta InQ aplicada
[ ] Página 4 (Nota metodológica) con paleta InQ aplicada
[ ] Página 5 con gráfico SVG nativo de trayectoria del ahorro
[ ] Trayectoria empieza en (Año 0, -inversión), cruza 0 en payback,
termina en (Año N, ahorro_acumulado_final)
[ ] Áreas roja y naranja diferenciadas (antes/después del payback)
[ ] Marker vertical en payback con label "Payback: N.N meses"
[ ] Anotaciones al pie del gráfico (inversión, acumulado, multiplicador)
[ ] Página 1 NO MODIFICADA
[ ] PDFs Actual y Automatizado NO MODIFICADOS
[ ] 8 validaciones automatizadas confirmadas
[ ] Tests previos verdes + nuevos tests del gráfico SVG (al menos 4 casos)
[ ] npm run build limpio
[ ] PDF presentado para validación visual
[ ] Decisiones por iniciativa documentadas según política CLAUDE.md
```
---
## 6. Reporte final a entregar
1. Tabla de archivos modificados/creados
2. 8 validaciones automatizadas confirmadas (resultado de cada una)
3. Cantidad final de tests verdes
4. **PDF ROI con paths absolutos del filesystem para que el usuario abra en Finder**
- NO usar enlaces vscode-webview, que no funcionan fuera de VS Code
- Path tipo `/Users/marcos/.../tests/e2e/__output__/etapa-7-roi.pdf`
5. PDFs Actual y Automatizado regenerados (para confirmar no-regresión)
6. **Detalle del gráfico SVG de trayectoria:**
- Coordenadas del punto de inicio (debería ser y < 0)
- Coordenadas del payback (debería ser y = 0)
- Coordenadas del final (debería ser y > 0)
- Esto valida que la curva está bien construida matemáticamente
7. Hallazgos no esperados
8. Decisiones tomadas por iniciativa (con clasificación según niveles)
---
## 7. Reglas operativas
1. **NO TOCAR LA PÁGINA 1.** Cerrada en Etapa 6. Cualquier cambio visual ahí es Nivel 3 (consultar previa). Refinamientos están agendados para Etapa 11.
2. **NO TOCAR PDFs Actual y Automatizado.** Etapa 8 los rediseña.
3. **NO ARREGLAR FÓRMULAS TRUNCADAS O UNICODE.** Sprint 2 — font embedding. Si te tienta, pará.
4. **Para el gráfico SVG, usar SOLO primitivas de jsPDF.** Sin html2canvas, sin canvas, sin librerías externas. El chart se construye con `doc.line`, `doc.rect`, `doc.text`.
5. **Política de iniciativa proactiva refinada (de Etapa 5):**
- Cualquier cambio que afecte layout, paginación, o contenido visible más allá del scope: mínimo Nivel 2 (ejecutar y reportar)
- Cambio que choca con restricción explícita del prompt: Nivel 3 (consultar previo)
- Cambio en página 1 o en PDFs no-ROI: SIEMPRE Nivel 3 en esta etapa
6. **Si la implementación del gráfico SVG nativo se complica más de 2 horas, consultá.** Hay caminos intermedios (chart como imagen pre-renderizada del web app, etc.) que podemos evaluar.
7. **Si encontrás contradicción** entre prompt y código: PARÁ y consultá.
---
## 8. Por qué esta etapa importa
La página 5 es donde el reporte demuestra **rigor técnico**. El cliente que abra el PDF en una reunión va a ver:
- Página 1: el resumen ejecutivo con el número grande (KPI Hero)
- Página 5: la curva financiera que justifica ese número
Sin la página 5, el KPI Hero es "te creo o no". Con la página 5, es **evidencia visual** de cómo se construye el ahorro a lo largo del tiempo. Es la diferencia entre vendedor y consultor.
Si la curva queda mal, el reporte pierde credibilidad. Si queda bien, vale como diferenciador frente a competencia.
Apuntá alto.