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,280 @@
# Sprint 1.5 — Etapa 5: PDF — Layout híbrido portrait + landscape
> **Objetivo:** cambiar la orientación de la página que contiene el diagrama BPMN (heatmap) a landscape, mientras el resto del PDF se mantiene en portrait. Aplica a los 3 PDFs (Actual, Automatizado, ROI).
>
> **Pre-requisitos:** Etapa 4 cerrada — header y footer compartidos, paleta InQ aplicada en headers/footers.
>
> **Etapa siguiente:** Etapa 6 — Rediseño completo de página 1 del PDF ROI (KPI Hero gradiente, top 3, header denso).
---
## 1. Por qué este cambio
El diagrama BPMN con heatmap es el elemento visual más importante del PDF. En layout vertical A4 (210mm de ancho útil), procesos con más de 7-8 actividades no caben legiblemente — el diagrama se renderiza chiquito y los nombres de las actividades se truncan.
En landscape A4 (297mm de ancho útil), el diagrama tiene 41% más espacio horizontal. Los procesos típicos de InQuality (10-15 actividades con gateways) se ven legibles. **Es la diferencia entre un PDF que se entiende y uno que se descarga y nadie lee.**
---
## 2. Alcance estricto de Etapa 5
### Sí entra
- ✅ La página del diagrama BPMN (heatmap) cambia de portrait a landscape en los 3 PDFs (Actual, Automatizado, ROI)
- ✅ Las demás páginas (resumen ejecutivo, tabla comparativa, metodología) se mantienen en portrait
- ✅ El header y footer compartidos (creados en Etapa 4) se adaptan al ancho de la página landscape
- ✅ El diagrama BPMN renderizado ocupa MÁS espacio horizontal (no queda con padding excesivo)
- ✅ Tests E2E verifican que cada PDF tiene la mezcla correcta de orientaciones
### NO entra
- ❌ Rediseño del contenido del diagrama (Etapa 6 o posterior)
- ❌ Cambio de la leyenda del heatmap (bajo costo / alto costo) — solo se adapta al ancho landscape
- ❌ Cambio de los KPI cards de la página 1 (Etapa 6)
- ❌ Cambio de la tabla comparativa (Etapa 7)
- ❌ Embebido de fonts Unicode (Sprint 2, anotado en TODO)
- ❌ Tocar el resto de páginas del PDF
---
## 3. Decisiones técnicas obligatorias
### 3.1 Método correcto para cambiar orientación en jsPDF
**SOLO usar este método** — los otros tienen bugs conocidos:
```typescript
// ✅ CORRECTO — usar el parámetro de orientación en addPage
doc.addPage('a4', 'landscape');
// Para volver a portrait después:
doc.addPage('a4', 'portrait');
```
**Métodos prohibidos:**
```typescript
// ❌ NO USAR — método deprecated y comportamiento inconsistente
doc.addPage([842, 595]); // dimensiones manuales sin orientación
// ❌ NO USAR — rota el ordering de páginas y autotable
doc.internal.pageSize.width = 842;
doc.internal.pageSize.height = 595;
// ❌ NO USAR — transform/rotate de contenido sobre página portrait
// "Rotar el contenido 90° en una página portrait" se ve mal y rompe
// el cálculo de posiciones de texto
```
### 3.2 Detección del ancho disponible en cada página
El módulo `pdf-sections-shared.ts` ya recibe el `doc` y debería usar:
```typescript
const pageWidth = doc.internal.pageSize.getWidth();
const pageHeight = doc.internal.pageSize.getHeight();
```
Esto retorna dinámicamente el ancho de la página ACTUAL (portrait o landscape). **NO hardcodear `595` (A4 portrait) ni `842` (A4 landscape).** Si encontrás esos números mágicos en el código, reemplazalos.
### 3.3 Generación del diagrama BPMN en landscape
El diagrama BPMN se renderiza con html2canvas → imagen JPEG embebida en el PDF. La función actual probablemente está calculando dimensiones basadas en página portrait. **Hay que ajustarla para landscape:**
```typescript
// Antes (asumiendo portrait):
const maxImageWidth = pageWidth - 2 * marginX; // ~170mm
const imageHeight = maxImageWidth * (canvas.height / canvas.width);
// Después (funciona en ambas orientaciones):
const pageWidth = doc.internal.pageSize.getWidth(); // dinámico
const pageHeight = doc.internal.pageSize.getHeight(); // dinámico
const usableWidth = pageWidth - 2 * marginX;
const usableHeight = pageHeight - headerHeight - footerHeight - 2 * marginY;
// Calcular escala que cabe en ambas dimensiones
const scaleX = usableWidth / canvas.width;
const scaleY = usableHeight / canvas.height;
const scale = Math.min(scaleX, scaleY);
const imageWidth = canvas.width * scale;
const imageHeight = canvas.height * scale;
```
Esto garantiza que el diagrama:
- Aprovecha el espacio horizontal en landscape
- No se sale de los márgenes
- Mantiene aspect ratio del canvas original
### 3.4 Páginas con qué orientación — orden y dimensiones
**PDF Actual y Automatizado (3 páginas):**
| Página | Contenido | Orientación |
|---|---|---|
| 1 | Resumen ejecutivo (KPI cards) | Portrait |
| 2 | Diagrama BPMN con heatmap | **Landscape** |
| 3 | Tabla de costos + nota metodológica | Portrait |
**PDF ROI (4 páginas):**
| Página | Contenido | Orientación |
|---|---|---|
| 1 | Resumen ejecutivo ROI (KPI hero + cards) | Portrait |
| 2 | Comparación por actividad (tabla) | Portrait |
| 3 | Composición + trayectoria + transparencia | Portrait |
| 4 | Nota metodológica | Portrait |
**Decisión arquitectónica:** el PDF ROI **NO incluye página con diagrama BPMN** en este sprint. El BPMN está en los PDFs Actual y Automatizado. Si en el futuro se decide incluir BPMN en ROI, se replica el patrón landscape.
### 3.5 Header y footer en página landscape
El header y footer compartidos ya están en `pdf-sections-shared.ts` (Etapa 4). Deben:
- Adaptarse al nuevo ancho automáticamente (porque usan `getWidth()`, no constantes)
- Mantener la misma estructura visual (logo izquierda, metadata derecha, border-bottom naranja)
- **NO requieren código nuevo si la implementación de Etapa 4 fue correcta**
Si necesitás modificar `drawSharedHeader` o `drawSharedFooter` para soportar landscape, **PARÁ y consultá**. Probablemente significa que la implementación de Etapa 4 tiene un hardcode que se nos pasó.
---
## 4. Validaciones automatizadas mandatorias
Antes de `present_files`, ejecutá y confirmá:
```
Para cada PDF generado:
1. Cantidad de páginas correcta:
- actual: 3 páginas
- automatizado: 3 páginas
- roi: 4 páginas
2. Orientación de cada página (usando pdf-parse o pdfjs-dist para detectar):
- actual: portrait, LANDSCAPE, portrait
- automatizado: portrait, LANDSCAPE, portrait
- roi: portrait, portrait, portrait, portrait
3. Header y footer presentes en TODAS las páginas (incluyendo landscape):
- "InQ ROI" en header de cada página
- "Powered by InQuality" en footer de cada página
- Paginación correcta "Página X de Y"
4. Análisis de píxeles del diagrama BPMN en página 2 (actual/automatizado):
- El ancho del diagrama supera 200mm (40% más que en portrait)
- Heatmap presente con verde + ámbar + rojo
- Texto de las actividades legible (no truncado a "...")
5. Tests previos verdes: >= 469
6. NO hay regresiones en marcas:
- "InQ ROI" presente en todas las páginas
- "Process Cost Platform" ausente
- "v0.1.0" ausente
```
Si CUALQUIER validación falla, NO uses `present_files`. Reportá qué falló y esperá instrucciones.
---
## 5. Entregables (Definition of Done)
```
[ ] Página BPMN del PDF Actual ahora en landscape
[ ] Página BPMN del PDF Automatizado ahora en landscape
[ ] PDF ROI mantiene las 4 páginas en portrait (no tiene página BPMN)
[ ] Header y footer compartidos funcionan correctamente en ambas
orientaciones SIN modificar pdf-sections-shared.ts
(si requirió modificación, justificá la causa)
[ ] Diagrama BPMN aprovecha el ancho landscape (mínimo 200mm de ancho)
[ ] 6 validaciones automatizadas confirmadas
[ ] PDFs presentados con present_files
[ ] Tests previos siguen verdes (469+)
[ ] Tests nuevos para verificar orientación de páginas (3-5 casos mínimo)
[ ] npm run build limpio
[ ] Decisiones tomadas por iniciativa documentadas en reporte (Patrón C.6)
```
---
## 6. Tests obligatorios
### 6.1 Tests unitarios
Crear `tests/lib/export/pdf-orientation.test.ts`:
```typescript
describe('PDF orientation', () => {
it('el PDF actual tiene mezcla portrait-landscape-portrait', async () => {
const pdf = await generateActualPdf(mockData);
const orientations = getPageOrientations(pdf);
expect(orientations).toEqual(['portrait', 'landscape', 'portrait']);
});
it('el PDF automatizado tiene mezcla portrait-landscape-portrait', async () => {
const pdf = await generateAutomatedPdf(mockData);
const orientations = getPageOrientations(pdf);
expect(orientations).toEqual(['portrait', 'landscape', 'portrait']);
});
it('el PDF ROI mantiene las 4 páginas en portrait', async () => {
const pdf = await generateRoiPdf(mockData);
const orientations = getPageOrientations(pdf);
expect(orientations).toEqual(['portrait', 'portrait', 'portrait', 'portrait']);
});
it('el diagrama BPMN en landscape ocupa más de 200mm de ancho', async () => {
const pdf = await generateActualPdf(mockData);
const bpmnImageWidth = getImageWidthOnPage(pdf, 2);
expect(bpmnImageWidth).toBeGreaterThan(200);
});
it('header funciona en página landscape sin modificación', async () => {
// verificar que drawSharedHeader se llama desde página landscape
// y produce output coherente (logo izquierda, fecha derecha)
});
});
```
---
## 7. Reporte final a entregar
Cuando termines, devolveme:
1. **Tabla de archivos modificados/creados** con líneas
2. **Resultado de las 6 validaciones automatizadas**
3. **Cantidad final de tests verdes** (esperado 474+)
4. **3 PDFs presentados con `present_files`** para validación visual
5. **Comparación de ancho del diagrama**: ¿antes (portrait) vs ahora (landscape)?
6. **Hallazgos no esperados**
7. **Decisiones tomadas por iniciativa** según política CLAUDE.md
NO arranques Etapa 6 sin mi OK explícito.
---
## 8. Reglas operativas (recordatorios)
1. **Usar SOLO `doc.addPage('a4', 'landscape')`**. Los otros métodos están prohibidos por gotchas conocidos.
2. **No hardcodear dimensiones de página**. Usar `doc.internal.pageSize.getWidth()` y `getHeight()` siempre.
3. **No modificar pdf-sections-shared.ts** salvo causa documentada. Si la implementación de Etapa 4 fue correcta, el header/footer deben funcionar en landscape sin tocar.
4. **No tocar contenido de páginas que NO son la BPMN**. El resto del PDF se mantiene visualmente igual.
5. **No racionalizar problemas de renderizado**. Si el diagrama se ve mal en landscape, investigar causa raíz (probablemente cálculo de escala).
6. **Política de iniciativa proactiva (CLAUDE.md)**:
- Cambios Nivel 1 (refactor interno, mejor naming): ejecutar
- Cambios Nivel 2 (visible pero reversible): ejecutar y reportar
- Cambios Nivel 3 (marca, arquitectura, datos): CONSULTAR antes
7. **Si encontrás contradicción** entre este prompt y la realidad del código: **PARÁ y consultá**.
---
## 9. Riesgo conocido — orientation switching en jsPDF
Tres bugs históricos en jsPDF al cambiar orientación entre páginas:
1. **Bug del autotable que se reinicia mal**: si la página landscape contiene una tabla autotable y la siguiente página vuelve a portrait, autotable puede continuar en el ancho de la landscape. **Solución**: la página landscape de esta etapa contiene solo el diagrama BPMN como imagen, no tablas. Si en el futuro hay una tabla en landscape, requiere atención adicional.
2. **Bug de imagen recortada al cambiar orientación**: si después de `addPage('a4', 'landscape')` no se recalcula el ancho disponible, la imagen se inserta con el ancho anterior (portrait) y se ve chiquita o se corta. **Solución**: siempre llamar `getWidth()` después de `addPage`.
3. **Footer absoluto en posición incorrecta**: si el footer se posiciona con `doc.internal.pageSize.height - 20`, en landscape eso es ~575px, pero la altura landscape A4 es ~595px. **Solución**: usar `getHeight()` dinámico, no asumir altura.
Si durante la implementación encontrás algún comportamiento extraño en jsPDF que no esté en esta lista, **investigá causa raíz antes de aplicar workaround**. Documentá el hallazgo en el reporte final.

View File

@@ -0,0 +1,480 @@
# Sprint 1.5 — Etapa 6: PDF ROI — Rediseño de página 1 con identidad InQ
> **Objetivo:** transformar la página 1 del PDF ROI en la "página de discusión" del reporte. Implementa KPI Hero con gradiente naranja → magenta, banner narrativo, KPIs secundarios con paleta InQ, y Top 3 actividades por ahorro. La trayectoria del ahorro se posterga a Etapa 7.
>
> **Pre-requisitos:** Etapas 1-5 cerradas. Módulo `pdf-sections-shared.ts` con header/footer compartidos. Layout híbrido funcionando en PDFs Actual/Automatizado.
>
> **Etapa siguiente:** Etapa 7 — PDF ROI páginas 2-5 (tabla con paleta, trayectoria del ahorro, transparencia rediseñada, nota metodológica).
---
## 1. Decisión arquitectónica de esta etapa
**El PDF ROI pasa de 4 páginas a 5 páginas.**
| Página | Contenido actual (Etapa 5) | Contenido nuevo (Etapa 6) |
|---|---|---|
| 1 | KPIs (header simple) | **Rediseño completo: header denso + banner + KPI Hero + 4 KPIs + Top 3** |
| 2 | Comparación por actividad | Comparación por actividad (sin cambios — Etapa 7) |
| 3 | Análisis del ahorro | Análisis del ahorro (sin cambios — Etapa 7) |
| 4 | Nota metodológica | Nota metodológica (sin cambios — Etapa 7) |
| 5 | — | NUEVA: trayectoria del ahorro acumulado (Etapa 7) |
**En Etapa 6 solo tocamos la página 1.** Las páginas 2-4 quedan iguales que en Etapa 5. La página 5 se agrega en Etapa 7.
---
## 2. Alcance estricto
### Sí entra
- ✅ Rediseño completo de la página 1 del PDF ROI con la estructura del brief sección 3.2
- ✅ Header denso de página 1 con metadata integrada (proceso, cliente, fecha)
- ✅ Banner narrativo con resumen ejecutivo en `#FFF8ED` y border-left naranja
- ✅ KPI Hero con gradiente naranja → magenta (cifra de Ahorro proyectado a N años)
- ✅ Grid 2x2 de KPIs secundarios con paleta `#FEF3E2` (Ahorro/ejecución, Ahorro anual, Payback, ROI anual)
- ✅ Top 3 actividades por ahorro con barras horizontales naranjas
- ✅ Footer estándar (sin cambios, ya creado en Etapa 4)
### NO entra
- ❌ Trayectoria del ahorro acumulado (gráfico SVG nativo) — Etapa 7
- ❌ Cambios en página 2 (Comparación por actividad) — Etapa 7
- ❌ Cambios en página 3 (Análisis del ahorro) — Etapa 7
- ❌ Cambios en página 4 (Nota metodológica) — Etapa 7
- ❌ Rediseño de PDFs Actual y Automatizado — Etapa 8
- ❌ Resolver fórmulas truncadas o Unicode roto — Sprint 2
---
## 3. Decisiones ya tomadas (no consultar de nuevo)
| Decisión | Justificación |
|---|---|
| Gradiente KPI Hero: `linear-gradient(135deg, #F59845 0%, #ED3E8F 100%)` | Brief sección 2.2 |
| KPI Hero muestra el ahorro acumulado a N años (no por ejecución) | El número que importa al ejecutivo |
| KPIs secundarios: Ahorro/ejecución, Ahorro anual, Payback, ROI anual | Brief sección 3.2 |
| Top 3 con barras horizontales naranjas, sin grid pesado | Visual ligero, foco en magnitud relativa |
| Banner narrativo con `#FFF8ED` + border-left 3px `#F59845` | Brief sección 2.3 |
| Trayectoria del ahorro POSTERGADA a página 5 (Etapa 7) | Decisión Camino B de planificación previa |
| PDF ROI pasa a 5 páginas (con `Página X de 5` en footers) | Consecuencia del Camino B — se aplica desde Etapa 6 con placeholder en página 5 |
| Sin carátula | Brief sección 3.1 — info integrada en header denso |
---
## 4. Estructura visual de la página 1 (nueva)
Layout vertical de la página 1 (de arriba hacia abajo):
```
┌─────────────────────────────────────────────────────────┐
│ HEADER DENSO (15% del alto) │
│ │
│ InQ ROI UN PRODUCTO DE │
│ InQ │
│ ANÁLISIS DE RETORNO DE INVERSIÓN InQuality │
│ │
│ ───────────────────────────────────────────────── 3px │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ STRIP DE METADATA (5% del alto, fondo #FAFBFC) │
│ Proceso: medium-with-gateways | Cliente: — | Fecha │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ BANNER NARRATIVO (10% del alto, fondo #FFF8ED + border) │
│ ▌ Resumen ejecutivo: automatización de 3 actividades │
│ ▌ sobre proceso de 11 etapas. Frecuencia 5.000/año, │
│ ▌ horizonte 3 años, inversión USD 80.000. │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ KPI HERO (25% del alto, gradiente naranja → magenta) │
│ │
│ AHORRO PROYECTADO A 3 AÑOS │
│ USD 8.020.000 │
│ neto de inversión · 101× retorno │
│ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ GRID 2x2 KPIs SECUNDARIOS (20% del alto, fondo #FEF3E2)│
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ AHORRO POR EJEC.│ │ AHORRO ANUAL │ │
│ │ USD 540 │ │ USD 2.700.000 │ │
│ │ ↓ 90% vs actual │ │ × 3 años │ │
│ └─────────────────┘ └─────────────────┘ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ PAYBACK │ │ ROI ANUAL │ │
│ │ < 1 mes │ │ 3.375% │ │
│ │ Dentro horizonte│ │ retorno anual │ │
│ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ TOP 3 AHORROS (20% del alto) │
│ │
│ TOP 3 ACTIVIDADES POR AHORRO │
│ │
│ Analizar riesgo crediticio ████████████ USD 216 (40%) │
│ Recepcionar solicitud ████████████ USD 216 (40%) │
│ Calcular score crediticio ██████ USD 108 (20%) │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ FOOTER (5% del alto) │
│ InQ ROI · Powered by InQuality · — · 17 may 2026 │
│ Página 1 de 5 │
└─────────────────────────────────────────────────────────┘
```
**Proporciones aproximadas:** header 15%, metadata 5%, banner 10%, hero 25%, grid 20%, top 3 20%, footer 5%.
Si en la práctica algún bloque no entra con esas proporciones, **PARÁ y consultá**. NO comprimas elementos arbitrariamente.
---
## 5. Especificación detallada por bloque
### 5.1 Header denso de página 1
```
Layout: flex justify-between, border-bottom 3px solid #F59845
Padding-bottom: 12mm
Margin-bottom: 14mm
Izquierda (60% ancho):
Línea 1: "InQ ROI"
- Tamaño: 22pt
- Peso: 700 (bold)
- Color: #F59845 (inq-orange)
- Tracking: -0.5pt
Línea 2: "ANÁLISIS DE RETORNO DE INVERSIÓN"
- Tamaño: 9pt
- Peso: 500
- Color: #94A3B8 (text-tertiary)
- Letter-spacing: 1.5pt
- Margin-top: 4mm
Derecha (40% ancho):
Línea 1: "UN PRODUCTO DE"
- Tamaño: 9pt
- Color: #94A3B8
- Letter-spacing: 1pt
- Align: right
Línea 2: "InQ"
- Tamaño: 16pt
- Peso: 700
- Color: #475569 (text-secondary)
- Align: right
Línea 3: "InQuality"
- Tamaño: 9pt
- Color: #64748B
- Align: right
```
**Importante:** "InQ" siempre I-n-Q (regla no negociable de marca).
### 5.2 Strip de metadata
```
Fondo: #FAFBFC
Padding: 8mm horizontal, 5mm vertical
Border-radius: 4mm
Layout: grid 3 columnas (proceso 2fr, cliente 1fr, fecha 1fr)
Margin-bottom: 8mm
Cada celda:
Label (top): 8pt, color #94A3B8, uppercase, letter-spacing 1pt
Valor (bottom): 11pt, peso 500, color #0F172A
```
**Datos a mostrar:**
- Proceso: nombre del proceso BPMN (ej. "medium-with-gateways")
- Cliente: "—" si no hay cliente configurado (se completa cuando agregemos campo cliente en Sprint 2)
- Fecha: fecha de simulación formato "17 mayo 2026"
### 5.3 Banner narrativo
```
Fondo: #FFF8ED (inq-orange-lighter)
Border-left: 3px solid #F59845
Padding: 10mm 12mm
Border-radius: 0 4mm 4mm 0
Margin-bottom: 10mm
Texto:
- Tamaño: 11pt
- Line-height: 1.55
- Color: #475569 (text-secondary)
- Peso: 400 (regular)
Contenido (plantilla):
"Análisis de retorno de inversión para automatización del proceso
[nombreProceso], con frecuencia anual de [N.NNN] ejecuciones,
horizonte de [N] años e inversión estimada de USD [N.NNN].
Resultado: ahorro de USD [N.NNN] por ejecución ([NN]% de reducción).
La inversión se recupera en [formatPayback], dentro del horizonte
de análisis."
```
Usar la función `formatPayback` ya implementada en Etapa 2.
### 5.4 KPI Hero (gradiente naranja → magenta)
```
Fondo: linear-gradient(135deg, #F59845 0%, #ED3E8F 100%)
Padding: 16mm 18mm
Border-radius: 6mm
Margin-bottom: 10mm
Altura aproximada: 50mm
Label superior:
- Texto: "AHORRO PROYECTADO A [N] AÑOS"
- Tamaño: 10pt
- Peso: 500
- Color: white con opacity 0.9
- Letter-spacing: 1.2pt
- Margin-bottom: 6mm
Cifra principal:
- Texto: "USD 8.020.000" (formateado con formatCurrency)
- Tamaño: 30pt
- Peso: 700
- Color: white
- Tracking: -1pt
- Margin-bottom: 4mm
Subtítulo:
- Texto: "neto de inversión · [N.N]× retorno"
- Tamaño: 11pt
- Color: white con opacity 0.85
- Peso: 400
```
**Implementación técnica del gradiente en jsPDF:**
jsPDF NO soporta gradientes nativos. Hay dos opciones:
**Opción A — Renderizar como imagen embedida (recomendado):**
1. Crear un canvas en JS con el gradiente usando `CanvasRenderingContext2D.createLinearGradient()`
2. Dibujar texto sobre el canvas
3. Convertir canvas a base64 PNG
4. Embed en jsPDF con `doc.addImage()`
**Opción B — Simulación con múltiples rectángulos:**
- Dibujar ~50 rectángulos verticales de 4mm cada uno, cada uno con color interpolado
- Visualmente aceptable pero menos suave
- Más rápido de implementar pero menos calidad
**Elegí Opción A.** Justificación: el KPI Hero es el elemento visual más importante del PDF. Vale la pena el costo técnico de hacerlo bien. La Opción B se ve "computada", no "diseñada".
Si Opción A tiene complicación técnica que requiere más de 1 hora, **PARÁ y consultá**.
### 5.5 Grid 2x2 de KPIs secundarios
```
Layout: grid 2 columnas × 2 filas
Gap: 4mm horizontal, 4mm vertical
Margin-bottom: 10mm
Cada card:
Fondo: #FEF3E2 (inq-orange-light)
Padding: 8mm 10mm
Border-radius: 4mm
Label superior:
- Tamaño: 8pt
- Peso: 500
- Color: #92400E (inq-orange-dark)
- Letter-spacing: 1pt
- Uppercase
- Margin-bottom: 4mm
Cifra:
- Tamaño: 16pt
- Peso: 700 (bold para WCAG)
- Color: #0F172A (text-primary)
- Font-family: mono (para alineación de números)
Delta/contexto:
- Tamaño: 9pt
- Peso: 500
- Color: #B45309 (inq-orange-dark)
- Margin-top: 3mm
```
**Contenido de cada card:**
| Card | Label | Cifra | Delta/contexto |
|---|---|---|---|
| 1 | AHORRO POR EJECUCIÓN | `formatCurrency(savingsPerExec)` | `↓ {savingsPercent}% vs. actual` |
| 2 | AHORRO ANUAL | `formatCurrency(annualSavings)` | `× {horizonYears} años` |
| 3 | PAYBACK | `formatPayback(paybackMonths)` | `Dentro del horizonte` o `Fuera` |
| 4 | ROI ANUAL | `formatPercent(roi.annualizedRoi, 0)` | `retorno anual` |
### 5.6 Top 3 actividades por ahorro
```
Margin-bottom: 8mm
Título:
- Texto: "TOP 3 ACTIVIDADES POR AHORRO"
- Tamaño: 9pt
- Peso: 500
- Color: #94A3B8
- Letter-spacing: 1.2pt
- Uppercase
- Margin-bottom: 6mm
Cada fila (3 filas):
Layout: grid 3 columnas
Col 1 (40%): nombre actividad
Col 2 (40%): barra horizontal
Col 3 (20%): cifra + porcentaje
Margin-bottom: 4mm
Nombre actividad:
- Tamaño: 10pt
- Color: #0F172A
- Truncar a 32 caracteres con "..."
Barra horizontal:
- Altura: 6mm
- Fondo de la barra: #FED7AA (inq-orange-100)
- Fill: #F59845 (inq-orange)
- Ancho de fill: proporcional al ahorro (la actividad #1 tiene ancho completo, las demás proporcionales)
- Border-radius: 1mm
Cifra + porcentaje:
- Texto: "USD 216 (40%)"
- Tamaño: 10pt
- Peso: 500
- Color: #B45309
- Font-family: mono
- Align: right
```
**Cálculo del ancho de la barra:**
- Buscar el ahorro máximo entre las 3 actividades
- Ancho de cada barra = (ahorro / ahorro_max) × ancho_max_disponible
- Esto hace que la actividad #1 siempre tenga la barra completa, lo cual es intuitivo
---
## 6. Validaciones automatizadas mandatorias
Antes de `present_files`, ejecutá y confirmá:
```
PDF ROI debe cumplir:
1. Cantidad de páginas: 5 (era 4 en Etapa 5, ahora 5 con placeholder página 5)
NOTA: la página 5 va vacía o con texto "Trayectoria del ahorro
(rediseño en Etapa 7)". NO dejar página 4 sin nota metodológica.
2. Orientaciones: 5 páginas en portrait
3. Footers correctos:
- Página 1: "Página 1 de 5"
- Página 2: "Página 2 de 5"
- Página 3: "Página 3 de 5"
- Página 4: "Página 4 de 5"
- Página 5: "Página 5 de 5"
4. Página 1 contiene los siguientes elementos detectables:
- Texto "ANÁLISIS DE RETORNO DE INVERSIÓN" en header
- Texto "AHORRO PROYECTADO A 3 AÑOS" en KPI Hero
- Texto "TOP 3 ACTIVIDADES POR AHORRO"
- Al menos 3 nombres de actividades
- Análisis de píxeles confirma:
- Gradiente naranja → magenta (al menos 100 píxeles naranja Y al menos 50 píxeles magenta)
- Paleta naranja InQ en cards (al menos 500 píxeles #FEF3E2 o similar)
- Color blanco prominente en KPI Hero (texto sobre gradiente)
5. Tamaño de página 1: significativamente mayor que Etapa 5
(esperado 35-60 KB vs ~10 KB anterior, por imagen del gradiente embedida)
6. Validaciones globales sin regresión:
- "InQ ROI" presente
- "Powered by InQuality" presente
- "Process Cost Platform" ausente
- "v0.1.0" ausente
- "INQ", "Inq", "inq" (mayúsculas/minúsculas erróneas) ausentes
7. PDFs Actual y Automatizado: SIN CAMBIOS respecto a Etapa 5
- Sigue siendo 4 páginas cada uno
- Orientaciones: ['portrait', 'landscape', 'portrait', 'portrait']
- Tamaños similares a Etapa 5
8. Tests previos verdes: >= 476
```
Si CUALQUIER validación falla, NO uses `present_files`. Reportá qué falló.
---
## 7. Entregables (Definition of Done)
```
[ ] Página 1 del PDF ROI rediseñada según especificación de §4 y §5
[ ] PDF ROI tiene 5 páginas (página 5 con placeholder de trayectoria)
[ ] Footer de TODAS las páginas dice "Página X de 5"
[ ] KPI Hero con gradiente naranja → magenta visible y legible
[ ] Grid 2x2 con paleta naranja InQ aplicada
[ ] Top 3 con barras horizontales proporcionales al ahorro
[ ] Banner narrativo con border-left naranja
[ ] Header denso con metadata integrada
[ ] PDFs Actual y Automatizado NO modificados
[ ] 8 validaciones automatizadas confirmadas
[ ] PDFs presentados con present_files
[ ] Tests previos verdes (476+) sin regresiones
[ ] Tests nuevos para los componentes de página 1 ROI (al menos 4 casos)
[ ] npm run build limpio
[ ] Decisiones tomadas por iniciativa documentadas (Patrón C.6 —
con criterios explícitos: si cambia layout, paginación, o contenido
visible más allá del scope, es mínimo Nivel 2)
```
---
## 8. Reporte final a entregar
1. **Tabla de archivos modificados/creados**
2. **8 validaciones automatizadas confirmadas**
3. **Cantidad final de tests verdes**
4. **PDF ROI presentado con `present_files`** + PDFs Actual y Automatizado para confirmar no-regresión
5. **Captura específica de página 1 del ROI**: detalle visual del KPI Hero y Top 3 si es posible
6. **Hallazgos no esperados**
7. **Decisiones tomadas por iniciativa** según política CLAUDE.md, con clasificación explícita por nivel
---
## 9. Reglas operativas
1. **Solo tocar página 1 del PDF ROI.** Las otras 3 páginas existentes quedan iguales. La página 5 es placeholder.
2. **NO tocar PDFs Actual y Automatizado.** El alcance de Etapa 6 es solo el PDF ROI.
3. **NO resolver fórmulas truncadas ni Unicode.** Esos hallazgos están en TODO para Sprint 2. Si te tienta arreglarlos, pará — no es Etapa 6.
4. **Si el gradiente requiere más de 1 hora de implementación técnica, consultá.** No quemes 3 horas peleándote con canvas → PNG → addImage. Si bloqueás, presentá alternativas.
5. **Política de iniciativa proactiva (CLAUDE.md), con criterios explícitos refinados después de Etapa 5:**
- Si el cambio modifica cantidad de páginas, layout, o contenido visible más allá del scope: mínimo Nivel 2
- Si choca con una restricción explícita del prompt (ej. "NO entra"): Nivel 3 — consultar antes
- Si afecta marca, datos, dependencias o arquitectura: Nivel 3 — consultar antes
- Si nada de lo anterior: Nivel 1 — ejecutar y mencionar al final si fueron varios cambios acumulados
6. **Si encontrás contradicción** entre prompt y código: PARÁ y consultá.
---
## 10. Esta es la etapa visualmente más importante del Sprint
La página 1 del PDF ROI es **el primer artefacto que un cliente de InQuality va a ver del producto en una reunión**. Es la "página de discusión" del reporte. Tiene que verse profesional, identitaria, y comunicar el valor en 5 segundos.
Si algo de la especificación visual no te queda claro, **es mejor consultar que improvisar**. El brief y los mockups previos son ground truth — no inventes interpretaciones nuevas.
Cuando termines, validá vos mismo abriendo el PDF en Preview antes de declarar la etapa terminada. Si vos no pondrías eso al frente de un cliente bancario, retrabaja antes de present_files.

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.