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:
280
sprints/sprint-1-5/ETAPA_5_PROMPT.md
Normal file
280
sprints/sprint-1-5/ETAPA_5_PROMPT.md
Normal 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.
|
||||
480
sprints/sprint-1-5/ETAPA_6_PROMPT.md
Normal file
480
sprints/sprint-1-5/ETAPA_6_PROMPT.md
Normal 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.
|
||||
452
sprints/sprint-1-5/ETAPA_7_PROMPT.md
Normal file
452
sprints/sprint-1-5/ETAPA_7_PROMPT.md
Normal 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.
|
||||
Reference in New Issue
Block a user