Antes de meterle a sprint 1 etapa 4 y 5
This commit is contained in:
54
CLAUDE.md
54
CLAUDE.md
@@ -5,6 +5,49 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## ⚠️ Reglas de Marca — NO NEGOCIABLES (Sprint 1.5+)
|
||||||
|
|
||||||
|
Estas reglas aplican a TODO string que aparezca en código, PDFs, CSVs, tests y documentación.
|
||||||
|
|
||||||
|
### 1. Ortografía de "InQ" — SIEMPRE I-n-Q
|
||||||
|
|
||||||
|
```
|
||||||
|
✅ InQ ← correcto
|
||||||
|
✅ InQuality ← correcto (nombre completo)
|
||||||
|
✅ InQ ROI ← nombre del producto
|
||||||
|
|
||||||
|
❌ INQ ← bug
|
||||||
|
❌ Inq ← bug
|
||||||
|
❌ inq ← bug
|
||||||
|
❌ inQ ← bug
|
||||||
|
```
|
||||||
|
|
||||||
|
Cualquier desviación es un bug que debe corregirse antes de hacer commit.
|
||||||
|
|
||||||
|
### 2. Nombre del producto
|
||||||
|
|
||||||
|
`InQ ROI` — nombre de trabajo para Sprint 1.5. Se reemplazará en Sprint 3-4. No debatir el nombre ahora.
|
||||||
|
|
||||||
|
### 3. Color protagonista
|
||||||
|
|
||||||
|
```
|
||||||
|
Primario: #F59845 (naranja InQ)
|
||||||
|
Gradiente: #F59845 → #ED3E8F (naranja → magenta InQ)
|
||||||
|
```
|
||||||
|
|
||||||
|
El gradiente se usa SOLO en KPI Hero y banners principales.
|
||||||
|
**NO usar morado de CONCILIA** (`#572FA2`, `#CB1889`) en este producto.
|
||||||
|
|
||||||
|
### 4. Footer de PDFs
|
||||||
|
|
||||||
|
Tagline obligatorio: `"Powered by InQuality"` — en todos los footers de PDF, siempre.
|
||||||
|
|
||||||
|
### 5. Rol del consultor
|
||||||
|
|
||||||
|
Si aparece un nombre de consultor en algún campo, es como "consultor responsable", no como "creador" ni "founder" del producto.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Identidad del Proyecto
|
## Identidad del Proyecto
|
||||||
|
|
||||||
**Nombre de trabajo**: Process Cost Platform (nombre comercial por definir)
|
**Nombre de trabajo**: Process Cost Platform (nombre comercial por definir)
|
||||||
@@ -232,3 +275,14 @@ npx playwright test # tests E2E (Playwright headless)
|
|||||||
- Análisis de costos operativos en consultoría de procesos
|
- Análisis de costos operativos en consultoría de procesos
|
||||||
- **Pre-venta de proyectos de automatización con cálculo de ROI** (caso estrella del Sprint 1)
|
- **Pre-venta de proyectos de automatización con cálculo de ROI** (caso estrella del Sprint 1)
|
||||||
- Valora: claridad, robustez, pulido visual, mantenibilidad, validación rigurosa
|
- Valora: claridad, robustez, pulido visual, mantenibilidad, validación rigurosa
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Reglas de marca NO NEGOCIABLES
|
||||||
|
|
||||||
|
- "InQ" siempre se escribe I-n-Q (mayúscula-minúscula-mayúscula)
|
||||||
|
- Color protagonista: naranja #F59845
|
||||||
|
- Gradiente identidad: #F59845 → #ED3E8F
|
||||||
|
- NO usar morado CONCILIA (#572FA2, #CB1889)
|
||||||
|
- Footer obligatorio: "Powered by InQuality"
|
||||||
|
- No promover a Marcos como creador
|
||||||
330
DESIGN_SYSTEM.md
Normal file
330
DESIGN_SYSTEM.md
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
# InQ ROI — Sistema de Diseño
|
||||||
|
|
||||||
|
> Documento de referencia visual para Sprint 2+.
|
||||||
|
> Fuente de verdad para la paleta, tipografía y componentes.
|
||||||
|
> Actualizar en cada sprint que modifique la identidad visual.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Identidad de Marca
|
||||||
|
|
||||||
|
### Nombre del producto
|
||||||
|
**InQ ROI** — herramienta interna de InQuality para cuantificación de ROI de automatización.
|
||||||
|
|
||||||
|
### Regla de ortografía (NO NEGOCIABLE)
|
||||||
|
```
|
||||||
|
✅ InQ ← I mayúscula, n minúscula, Q mayúscula
|
||||||
|
✅ InQuality ← nombre completo
|
||||||
|
❌ INQ / Inq / inq / inQ ← cualquiera es bug
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tagline en footers PDF
|
||||||
|
`"Powered by InQuality"` — obligatorio en todos los footers de PDF.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Paleta Cromática
|
||||||
|
|
||||||
|
### 2.1 InQ Orange — Color protagonista
|
||||||
|
|
||||||
|
| Token Tailwind | CSS Var | Hex | HSL | Uso |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| `bg-inq-orange` | `--inq-orange` | `#F59845` | 28° 90% 62% | Principal: logo, KPIs hero, CTAs primarios |
|
||||||
|
| `bg-inq-orange-dark` | `--inq-orange-dark` | `#B45309` | 34° 93% 37% | Texto sobre fondos claros, hover de CTAs |
|
||||||
|
| `bg-inq-orange-light` | `--inq-orange-light` | `#FEF3E2` | 36° 95% 88% | Fondos de KPI cards |
|
||||||
|
| `bg-inq-orange-lighter` | `--inq-orange-lighter` | `#FFF8ED` | 36° 100% 94% | Fondos de banner narrativo, hover sutiles |
|
||||||
|
|
||||||
|
### 2.2 InQ Magenta — Gradiente identidad
|
||||||
|
|
||||||
|
| Token Tailwind | CSS Var | Hex | Uso |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `bg-inq-magenta` | `--inq-magenta` | `#ED3E8F` | Segundo color del gradiente identidad |
|
||||||
|
|
||||||
|
#### Gradiente identidad
|
||||||
|
```css
|
||||||
|
background: linear-gradient(135deg, #F59845 0%, #ED3E8F 100%);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Uso exclusivo:** KPI Hero "Ahorro proyectado" en PDF y web. NUNCA en bordes, separadores ni fondos secundarios.
|
||||||
|
|
||||||
|
### 2.3 Semánticos
|
||||||
|
|
||||||
|
| Token Tailwind | CSS Var | Hex | Uso |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `bg-success` | `--color-success` | `#16A34A` | Ahorros positivos, payback alcanzado |
|
||||||
|
| `bg-success-light` | `--color-success-light` | `#F0FDF4` | Fondos de mensajes positivos |
|
||||||
|
| `bg-warning` | `--color-warning` | `#F59E0B` | Advertencias, sección transparencia |
|
||||||
|
| `bg-warning-bg` | `--color-warning-bg` | `#FFFBEB` | Fondo de sección transparencia |
|
||||||
|
| `bg-destructive` / `--color-danger` | — | `#EF4444` | Costos altos, valores negativos |
|
||||||
|
| `--color-danger-light` | — | `#FEE2E2` | Fondos de heatmap alto costo |
|
||||||
|
|
||||||
|
### 2.4 Heatmap — Paleta saturada (FIJA hasta Sprint 3-4)
|
||||||
|
|
||||||
|
| Token Tailwind | Hex | RGB | Uso |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `bg-heatmap-low` | `#10B981` | (16, 185, 129) | Actividades de bajo costo |
|
||||||
|
| `bg-heatmap-mid` | `#F59E0B` | (245, 158, 11) | Actividades de costo medio |
|
||||||
|
| `bg-heatmap-high` | `#EF4444` | (239, 68, 68) | Actividades de alto costo |
|
||||||
|
|
||||||
|
#### Decisión sobre paleta de heatmap
|
||||||
|
|
||||||
|
**Se mantiene saturada** (verde-ámbar-rojo) en lugar de la variante pastel del brief por dos razones:
|
||||||
|
|
||||||
|
1. **Tests E2E calibrados**: los análisis de píxeles del heatmap (`export-pdf.spec.ts`, `validate-dod-etapa4.spec.ts`) tienen umbrales calibrados para estos colores. Cambiar la paleta requiere recalibrar todos esos umbrales.
|
||||||
|
|
||||||
|
2. **Visibilidad en pantallas grandes**: el producto se usa en talleres y charlas InQuality proyectadas en pantalla. Los colores saturados mantienen contraste a distancia. Los pasteles se "lavan" a 3+ metros.
|
||||||
|
|
||||||
|
**Revisión programada**: Sprint 3-4 con feedback real de uso en talleres.
|
||||||
|
|
||||||
|
**Invariante crítica**: los valores de `tailwind.config.js` `heatmap.*` DEBEN coincidir con las constantes `HEATMAP_LOW/MID/HIGH` en `src/lib/colors.ts`. Si se modifica uno, debe actualizarse el otro.
|
||||||
|
|
||||||
|
### 2.5 Neutrales
|
||||||
|
|
||||||
|
| Hex | Tailwind equivalente | Uso |
|
||||||
|
|---|---|---|
|
||||||
|
| `#0F172A` | `slate-900` | Títulos, números importantes |
|
||||||
|
| `#475569` | `slate-600` | Texto del cuerpo |
|
||||||
|
| `#64748B` | `slate-500` | Labels, metadatos |
|
||||||
|
| `#94A3B8` | `slate-400` | Placeholders, texto muy secundario |
|
||||||
|
| `#E2E8F0` | `slate-200` | Bordes generales |
|
||||||
|
| `#F1F5F9` | `slate-100` | Separadores sutiles |
|
||||||
|
| `#F8FAFC` | `slate-50` | Fondo de la app, canvas BPMN |
|
||||||
|
|
||||||
|
### 2.6 Colores que NO usar
|
||||||
|
|
||||||
|
```
|
||||||
|
❌ #572FA2 Morado primario de CONCILIA — marca hermana, no mezclar
|
||||||
|
❌ #CB1889 Magenta de CONCILIA
|
||||||
|
❌ azul shadcn por defecto (221.2 83.2% 53.3%) — reemplazado por InQ orange
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Tipografía
|
||||||
|
|
||||||
|
### 3.1 Familias
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* Primaria — web app y body de PDFs */
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
|
||||||
|
|
||||||
|
/* Mono — números en tablas, datos financieros */
|
||||||
|
font-family: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
|
||||||
|
```
|
||||||
|
|
||||||
|
Tailwind: `font-sans` / `font-mono`
|
||||||
|
|
||||||
|
### 3.2 Escala PDF
|
||||||
|
|
||||||
|
| Elemento | Tamaño | Peso | Tracking |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Logo "InQ ROI" en header | 22px | 700 | −0.8px |
|
||||||
|
| Título de sección | 16px | 500 | normal |
|
||||||
|
| KPI Hero (cifra) | 30px | 700 | −1px |
|
||||||
|
| KPI secundario (cifra) | 16px | 700 | normal |
|
||||||
|
| Body text | 11px | 400 | normal |
|
||||||
|
| Labels en cards | 8px | 500 | 1px uppercase |
|
||||||
|
| Tabla header | 10px | 500 | normal |
|
||||||
|
| Tabla body | 10px | 400 | normal |
|
||||||
|
| Footer | 9px | 400 | normal |
|
||||||
|
|
||||||
|
### 3.3 Escala Web App
|
||||||
|
|
||||||
|
| Elemento | Tamaño |
|
||||||
|
|---|---|
|
||||||
|
| Logo header | 18px / 700 |
|
||||||
|
| Page title | 16px / 500 |
|
||||||
|
| KPI Hero | 28px / 700 |
|
||||||
|
| KPI secundario | 16px / 700 |
|
||||||
|
| Nav / Tabs | 12px / 400-500 |
|
||||||
|
| Body | 12-13px / 400 |
|
||||||
|
| Labels en panels | 10-11px / 400-500 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Componentes
|
||||||
|
|
||||||
|
### 4.1 KPI Hero (gradiente naranja → magenta)
|
||||||
|
|
||||||
|
```
|
||||||
|
Fondo: linear-gradient(135deg, #F59845 0%, #ED3E8F 100%)
|
||||||
|
Padding: 16-18px
|
||||||
|
Border-radius: 6-8px
|
||||||
|
Label: 9-10px / uppercase / letter-spacing 1.2px / white opacity 0.9
|
||||||
|
Cifra: 28-30px / 700 / letter-spacing −1px / white
|
||||||
|
Subtítulo: 10-11px / white opacity 0.85
|
||||||
|
```
|
||||||
|
|
||||||
|
Uso: el KPI "Ahorro proyectado a N años" — el más importante del reporte ROI.
|
||||||
|
|
||||||
|
### 4.2 KPI Card (secundario, fondo naranja claro)
|
||||||
|
|
||||||
|
```
|
||||||
|
Fondo: #FEF3E2 (inq-orange-light)
|
||||||
|
Padding: 10px 12px
|
||||||
|
Border-radius: 6px
|
||||||
|
Label: 8px / 500 / letter-spacing 1px / color #92400E / uppercase
|
||||||
|
Cifra: 16px / 700 / color #0F172A
|
||||||
|
Delta: 10px / 500 / color #B45309
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 Banner narrativo (resumen ejecutivo)
|
||||||
|
|
||||||
|
```
|
||||||
|
Fondo: #FFF8ED (inq-orange-lighter)
|
||||||
|
Border-left: 3px solid #F59845
|
||||||
|
Padding: 10-12px 14px
|
||||||
|
Border-radius: 0 4px 4px 0
|
||||||
|
Texto: 11px / 400 / line-height 1.55 / color #475569
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.4 Sección Transparencia Metodológica
|
||||||
|
|
||||||
|
```
|
||||||
|
Fondo: #FFFBEB (warning-bg)
|
||||||
|
Border: 0.5px solid #F59E0B
|
||||||
|
Padding: 12px 14px
|
||||||
|
Border-radius: 6px
|
||||||
|
Título: 11px / 500 / color #92400E / con ícono ⚠
|
||||||
|
Texto: 10px / 400 / line-height 1.6 / color #78350F
|
||||||
|
```
|
||||||
|
|
||||||
|
4 condiciones que activan la sección:
|
||||||
|
1. Actividades `automatable=true` con `automatedCostFixed=0` y `automatedTimeMinutes=0`
|
||||||
|
2. `automationInvestment=0`
|
||||||
|
3. `roiAnnualPercent > 1000` (finito)
|
||||||
|
4. (reservado para futuras reglas)
|
||||||
|
|
||||||
|
### 4.5 Tabla comparativa PDF
|
||||||
|
|
||||||
|
```
|
||||||
|
Header row:
|
||||||
|
Fondo: #FFF8ED
|
||||||
|
Border-bottom: 1px solid #F59845
|
||||||
|
Texto: 10px / 500 / #92400E
|
||||||
|
|
||||||
|
Body row — automatizable:
|
||||||
|
Fondo: white
|
||||||
|
|
||||||
|
Body row — no automatizable:
|
||||||
|
Fondo: #F8FAFC
|
||||||
|
Texto: color #64748B (más tenue)
|
||||||
|
|
||||||
|
Total row:
|
||||||
|
Fondo: #FFF8ED
|
||||||
|
Border-top: 1.5px solid #F59845
|
||||||
|
Texto: 10px / 500 / #0F172A
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.6 Header PDF
|
||||||
|
|
||||||
|
```
|
||||||
|
Layout: flex justify-between
|
||||||
|
Border-bottom: 3px solid #F59845 (pág. 1) / 2px (otras)
|
||||||
|
Padding-bottom: 10-12px
|
||||||
|
Margin-bottom: 14-16px
|
||||||
|
|
||||||
|
Izquierda:
|
||||||
|
"InQ ROI" 18-22px / 700 / #F59845
|
||||||
|
Tagline: 9px / letter-spacing 1.5px / #94A3B8 (solo pág. 1)
|
||||||
|
|
||||||
|
Derecha:
|
||||||
|
"UN PRODUCTO DE" 9px / letter-spacing 1px / #94A3B8
|
||||||
|
"InQ" 16px / 700 / #475569
|
||||||
|
"InQuality" 9px / #64748B
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.7 Footer PDF
|
||||||
|
|
||||||
|
```
|
||||||
|
Position: absolute bottom 14-16mm
|
||||||
|
Padding-top: 6-8px
|
||||||
|
Border-top: 0.5px solid #E2E8F0
|
||||||
|
Layout: flex justify-between
|
||||||
|
Font: 9px / 400 / #94A3B8
|
||||||
|
|
||||||
|
Izquierda: "InQ ROI" bold #F59845 " · Powered by InQuality · " cliente · fecha
|
||||||
|
Derecha: "Página X de Y"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.8 Badge ⚡ (Automatizable)
|
||||||
|
|
||||||
|
#### En canvas BPMN overlay
|
||||||
|
```
|
||||||
|
Diámetro: 14px
|
||||||
|
Fondo: #F59845 (naranja sólido)
|
||||||
|
Border: 1.5px solid white
|
||||||
|
Posición: { top: -8, left: nodeWidth - 12 }
|
||||||
|
Símbolo: ⚡ blanco 8px
|
||||||
|
```
|
||||||
|
|
||||||
|
Nota: en Sprint 1 el badge usa fondo `#fffbeb` (ámbar-50) con ícono ámbar. La migración a naranja sólido se hace en **Etapa 9** de Sprint 1.5.
|
||||||
|
|
||||||
|
#### En tablas y leyendas
|
||||||
|
```
|
||||||
|
Diámetro: 14px inline
|
||||||
|
Fondo: #F59845
|
||||||
|
Color: white
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.9 Layout híbrido de PDFs (portrait + landscape)
|
||||||
|
|
||||||
|
Los PDFs combinan orientaciones por página:
|
||||||
|
|
||||||
|
- **Páginas SIN diagrama**: A4 vertical (210×297mm) — texto, tablas, KPIs
|
||||||
|
- **Página DEL diagrama BPMN**: A4 horizontal (297×210mm) — para que el diagrama ocupe espacio real
|
||||||
|
|
||||||
|
Implementación jsPDF: `doc.addPage([297, 210], 'landscape')`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Tokens en código
|
||||||
|
|
||||||
|
### Web (Tailwind)
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// Colores de marca
|
||||||
|
<div className="bg-inq-orange"> // #F59845
|
||||||
|
<div className="bg-inq-orange-dark"> // #B45309
|
||||||
|
<div className="bg-inq-orange-light"> // #FEF3E2
|
||||||
|
<div className="text-inq-orange"> // texto naranja
|
||||||
|
<div className="border-inq-orange"> // borde naranja
|
||||||
|
|
||||||
|
// Gradiente identidad (como style prop — Tailwind no soporta gradientes dinámicos)
|
||||||
|
<div style={{ background: 'linear-gradient(135deg, #F59845 0%, #ED3E8F 100%)' }}>
|
||||||
|
|
||||||
|
// Semánticos
|
||||||
|
<div className="bg-success text-white"> // #16A34A
|
||||||
|
<div className="bg-warning-bg"> // #FFFBEB
|
||||||
|
```
|
||||||
|
|
||||||
|
### PDF (jsPDF)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Constante en pdf-sections.ts (a migrar en Etapas 4-8)
|
||||||
|
const PDF_ORANGE: [number, number, number] = [245, 152, 69] // #F59845
|
||||||
|
const PDF_ORANGE_LIGHT: [number, number, number] = [254, 243, 226] // #FEF3E2
|
||||||
|
const PDF_MAGENTA: [number, number, number] = [237, 62, 143] // #ED3E8F
|
||||||
|
|
||||||
|
// Gradiente en jsPDF se simula con pasos (ver pdf-sections-roi.ts)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Reglas de uso — DO / DON'T
|
||||||
|
|
||||||
|
### DO ✅
|
||||||
|
- Usar `bg-primary` / `text-primary` para todos los CTAs — hereda el naranja de `--primary`
|
||||||
|
- Usar gradiente identidad en exactamente 1 KPI Hero por página/vista
|
||||||
|
- Usar `font-mono` para todos los números financieros
|
||||||
|
- Escribir siempre **InQ** con I-n-Q
|
||||||
|
|
||||||
|
### DON'T ❌
|
||||||
|
- Usar `bg-blue-*` donde debería ir naranja InQ
|
||||||
|
- Aplicar el gradiente en más de un elemento por vista
|
||||||
|
- Usar colores de CONCILIA (`#572FA2`, `#CB1889`)
|
||||||
|
- Cambiar los colores del heatmap sin recalibrar los tests E2E
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Actualizado: Sprint 1.5 Etapa 1 — 2026-05-16*
|
||||||
2
TODO.md
2
TODO.md
@@ -31,6 +31,8 @@
|
|||||||
|
|
||||||
- [ ] **Indicador visual en el reporte de actividades automatable** (borde punteado o ícono diferenciador): en Sprint 1 se usa solo leyenda de texto. Evaluar si el cliente necesita más claridad visual al comparar Actual vs Automatizado.
|
- [ ] **Indicador visual en el reporte de actividades automatable** (borde punteado o ícono diferenciador): en Sprint 1 se usa solo leyenda de texto. Evaluar si el cliente necesita más claridad visual al comparar Actual vs Automatizado.
|
||||||
|
|
||||||
|
- [ ] **Sprint 3-4: revisar paleta del heatmap** (verde/ámbar/rojo saturados vs. pasteles). Los colores saturados actuales (`#10B981`, `#F59E0B`, `#EF4444`) funcionan bien en pantallas grandes de talleres. El brief de Sprint 1.5 propone pasteles más "consultivos" (`#BBF7D0`, `#FED7AA`, `#FECACA`), pero el cambio requiere recalibrar los tests E2E de análisis de píxeles (umbrales de verde/ámbar/rojo). Hacer con feedback real de uso en talleres InQuality.
|
||||||
|
|
||||||
- [ ] **Columna "Eficiencia de automatización" en ComparisonTable**: métrica = `(ahorro$ × probabilidad) / inversión-prorrateada`. Permite rankear actividades por "qué tan valiosa es automatizar cada una" en lugar de solo "cuánto cuestan". Útil en conversaciones de pre-venta donde el cliente quiere priorizar qué automatizar primero.
|
- [ ] **Columna "Eficiencia de automatización" en ComparisonTable**: métrica = `(ahorro$ × probabilidad) / inversión-prorrateada`. Permite rankear actividades por "qué tan valiosa es automatizar cada una" en lugar de solo "cuánto cuestan". Útil en conversaciones de pre-venta donde el cliente quiere priorizar qué automatizar primero.
|
||||||
|
|
||||||
## Baja prioridad / Fase 2
|
## Baja prioridad / Fase 2
|
||||||
|
|||||||
90
etapa-1-audit.md
Normal file
90
etapa-1-audit.md
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
# Auditoría de colores — Etapa 1 Sprint 1.5
|
||||||
|
|
||||||
|
> Hallazgos del audit de azules, hardcodes y `primary` en el código fuente.
|
||||||
|
> **No se resuelven en Etapa 1.** Las acciones se ejecutan en Etapas 3 (Web App) y 4-8 (PDFs).
|
||||||
|
>
|
||||||
|
> Fecha: 2026-05-16 · Ejecutado por: Claude Code
|
||||||
|
> Comandos: `grep -rn "blue|sky|indigo|3B82F6|2563EB" src/` + `grep -rn "#[0-9a-fA-F]{6}" src/`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Categorías
|
||||||
|
|
||||||
|
- **Migrar a InQ orange**: color azul que debería ser naranja de marca
|
||||||
|
- **Mantener azul funcional**: azul donde es convención semántica (info, links, paralelo AND)
|
||||||
|
- **Migrar a neutral**: azul accidental que debería ser slate/gray
|
||||||
|
- **Migrar a token**: hex hardcodeado que tiene un token equivalente en tailwind.config.js
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Hallazgos — Azules en clases Tailwind
|
||||||
|
|
||||||
|
| Archivo:línea | Clase actual | Categoría | Acción sugerida |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `GatewayPanel.tsx:122` | `bg-blue-50 border-blue-200` | **Mantener azul funcional** | El azul en gateways AND paralelos es convención visual (flujo paralelo = azul). Evaluar en Sprint 2 si cambiar a slate-50 sin perder semántica. |
|
||||||
|
| `GatewayPanel.tsx:124` | `text-blue-500` | **Mantener azul funcional** | Ídem — ícono Info en bloque paralelo |
|
||||||
|
| `GatewayPanel.tsx:126-127` | `text-blue-800`, `text-blue-700` | **Mantener azul funcional** | Texto del bloque informativo de gateway AND |
|
||||||
|
| `GatewayPanel.tsx:144` | `text-blue-600` | **Mantener azul funcional** | "100%" en gateway paralelo — valor fijo, semántica coherente |
|
||||||
|
| `ResourcesPanel.tsx:22` | `bg-blue-100 text-blue-700` (rol "role") | **Migrar a neutral** | Badge de tipo "role" no tiene razón de ser azul. Migrar a slate o usar color propio del sistema de recursos. Etapa 3. |
|
||||||
|
|
||||||
|
## Hallazgos — `PDF.blue` en exportación
|
||||||
|
|
||||||
|
| Archivo:línea | Color actual | Categoría | Acción sugerida |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `pdf-sections.ts:9` | `blue: [30, 64, 175]` (`#1E40AF`) | **Migrar a InQ orange** | Header de tabla PDF usa azul corporativo. Reemplazar por naranja InQ `[245, 152, 69]` (`#F59845`) en Etapa 4 (PDF: header y footer). |
|
||||||
|
| `pdf-sections.ts:112` | `PDF.blue` en KPI card accent | **Migrar a InQ orange** | El KPI "Costo total" usa azul como accent. Cambiar a naranja InQ en Etapa 6 (PDF: rediseño página 1). |
|
||||||
|
| `pdf-export.ts:120` | `fillColor: PDF.blue` en autotable | **Migrar a InQ orange** | Header de tabla de costos en azul. Migrar en Etapa 7 (PDF: páginas 3-4). |
|
||||||
|
| `pdf-sections-roi.ts:203` | `fillColor: PDF.blue` en autotable | **Migrar a InQ orange** | Header de tabla comparativa ROI. Migrar en Etapa 7. |
|
||||||
|
|
||||||
|
## Hallazgos — Hex hardcodes en componentes React
|
||||||
|
|
||||||
|
| Archivo:línea | Hex | Descripción | Categoría | Acción sugerida |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| `BpmnCanvas.tsx:24` | `#f59e0b` | Stroke del ícono Bot en SVG inline | **Migrar a InQ orange** | En Etapa 9 el badge ⚡ cambia a fondo naranja sólido `#F59845`. El stroke del SVG se rediseña en esa etapa. |
|
||||||
|
| `BpmnCanvas.tsx:40` | `#fffbeb` | Fondo del badge Bot (amber-50) | **Migrar a InQ orange** | Reemplazar por `var(--inq-orange-lighter)` `#FFF8ED` en Etapa 9. |
|
||||||
|
| `BpmnCanvas.tsx:41` | `#e2e8f0` | Borde del badge Bot | **Mantener neutral** | Borde sutil, está bien como slate-200. |
|
||||||
|
| `CumulativeSavingsChart.tsx:32,34` | `#10b981` | Color del marker de payback | **Migrar a token** | Verde éxito = `var(--color-success)` `#16A34A`. Migrar en Etapa 3. |
|
||||||
|
| `CumulativeSavingsChart.tsx:55` | `#10b981`, `#ef4444` | Colores del tooltip (positivo/negativo) | **Migrar a token** | Usar `--color-success` y `--color-danger`. Etapa 3. |
|
||||||
|
| `CumulativeSavingsChart.tsx:91,102` | `#3b82f6` | Línea y punto del chart acumulado | **Migrar a InQ orange** | La línea del gráfico de trayectoria debería ser naranja InQ `#F59845` para coherencia de marca. Etapa 3. |
|
||||||
|
| `HeatmapCanvas.tsx:118` | `#f8fafc` | Background del canvas | **Mantener neutral** | slate-50 es correcto para fondo del diagrama BPMN. |
|
||||||
|
| `TopSavingsChart.tsx:73,79` | `#10b981` | Barras y labels del chart | **Migrar a token** | Verde éxito correcto. Usar `--color-success` vía `style={{ color: 'var(--color-success)' }}`. Etapa 3. |
|
||||||
|
| `HeatmapLegend.tsx:24` | `#10b981`, `#f59e0b`, `#ef4444` | Gradiente de la leyenda del heatmap | **Migrar a token** | Usar constantes exportadas de `colors.ts` o tokens `heatmap.*`. Etapa 3. |
|
||||||
|
| `chart-options.ts:12` | `#3b82f6` (role) | Color del tipo de recurso "role" | **Migrar a neutral** | El azul para "roles" no es marca InQ. Evaluar paleta diferenciadora de tipos en Sprint 2. |
|
||||||
|
| `chart-options.ts:12` | `#8b5cf6` (system) | Color del tipo "system" | **Mantener azul funcional** | Violeta para sistemas es una convención razonable. Evaluar en Sprint 2. |
|
||||||
|
| `chart-options.ts:123` | `#3b82f6` | Costo directo en donut chart | **Migrar a InQ orange** | El donut de composición directo/overhead debería usar naranja InQ. Etapa 3. |
|
||||||
|
| `chart-options.ts:57,69,211,224` | `#f1f5f9`, `#e2e8f0` | Grid lines y ejes de charts | **Mantener neutral** | slate-100/200 son correctos para UI de soporte. |
|
||||||
|
| `chart-options.ts:63,107,209` | `#475569` | Labels de ejes | **Mantener neutral** | slate-600, correcto. |
|
||||||
|
| `chart-options.ts:78,217,237` | `#64748b`, `#94a3b8` | Labels secundarios | **Mantener neutral** | slate-500/400, correctos. |
|
||||||
|
| `chart-options.ts:136` | `#1e293b` | Fill del label de total en donut | **Mantener neutral** | slate-800, correcto para texto. |
|
||||||
|
|
||||||
|
## Hallazgos — `primary` en JSX
|
||||||
|
|
||||||
|
| Archivo | Usos | Evaluación |
|
||||||
|
|---|---|---|
|
||||||
|
| `router.tsx`, `WorkspacePage.tsx` | `text-primary` spinner | ✅ Correcto — spinner naranja InQ ahora |
|
||||||
|
| `ResourcesPanel.tsx:101` | `border-primary/20 bg-primary/5` | ✅ Correcto — borde/fondo naranja sutil |
|
||||||
|
| `RoiKpiBar.tsx:88-89` | `text-primary`, `bg-primary/10` | ✅ Correcto — ícono Calendar naranja |
|
||||||
|
| `KpiBar.tsx:46-47` | `text-primary`, `bg-primary/10` | ✅ Correcto — ícono DollarSign naranja |
|
||||||
|
| `ActivitiesTable.tsx:22-23` | `text-primary` arrows | ✅ Correcto — flechas de ordenamiento naranjas |
|
||||||
|
| `ActivitiesTable.tsx:96` | `bg-primary/5 ring-primary/20` | ✅ Correcto — highlight de fila naranja |
|
||||||
|
| `ImportPage.tsx:173,198-199,205,210-211,252,255-258` | `text-primary`, `bg-primary/*`, `border-primary` | ✅ Correcto — AccentS de la landing page naranjas |
|
||||||
|
| `SampleProcessLoader.tsx:77,83-84,92` | `hover:border-primary/30`, `bg-primary/10`, `text-primary` | ✅ Correcto |
|
||||||
|
| `WorkspacePage.tsx:178,243` | `text-primary border-primary/30`, `bg-primary` | ✅ Correcto |
|
||||||
|
| `slider.tsx` | `bg-primary/20`, `bg-primary`, `border-primary/50` | ✅ Correcto — slider naranja |
|
||||||
|
| `tooltip.tsx` | `bg-primary text-primary-foreground` | ✅ Correcto — tooltip naranja |
|
||||||
|
| `switch.tsx` | `bg-primary` when checked | ✅ Correcto — switch naranja |
|
||||||
|
| `button.tsx` | `bg-primary text-primary-foreground` default | ✅ Correcto — botón naranja |
|
||||||
|
| `badge.tsx` | `bg-primary text-primary-foreground` | ✅ Correcto — badge naranja |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Resumen de acciones pendientes
|
||||||
|
|
||||||
|
| Etapa | Archivos afectados | Acción |
|
||||||
|
|---|---|---|
|
||||||
|
| Etapa 3 (Web App) | `CumulativeSavingsChart.tsx`, `TopSavingsChart.tsx`, `HeatmapLegend.tsx`, `chart-options.ts` | Migrar hex a tokens CSS/constantes |
|
||||||
|
| Etapa 4-8 (PDFs) | `pdf-sections.ts`, `pdf-export.ts`, `pdf-sections-roi.ts` | Reemplazar `PDF.blue` por array naranja InQ |
|
||||||
|
| Etapa 9 (Badge ⚡) | `BpmnCanvas.tsx` | Rediseño completo del badge a naranja sólido |
|
||||||
|
| Sprint 2 | `ResourcesPanel.tsx`, `GatewayPanel.tsx`, `chart-options.ts` | Evaluar paleta de tipos de recurso y gateways |
|
||||||
|
|
||||||
|
**No se toca nada de lo anterior en Etapa 1.**
|
||||||
0
sprints/sprint-1-5/ETAPA_2_PROMPT.md
Normal file
0
sprints/sprint-1-5/ETAPA_2_PROMPT.md
Normal file
@@ -26,7 +26,7 @@ const TabsTrigger = React.forwardRef<
|
|||||||
<TabsPrimitive.Trigger
|
<TabsPrimitive.Trigger
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow',
|
'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-inq-orange data-[state=active]:shadow data-[state=active]:font-semibold',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -9,14 +9,19 @@
|
|||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
:root {
|
:root {
|
||||||
|
/* ── Shadcn/ui tokens — primary cambiado a InQ Orange ─────────────────
|
||||||
|
Antes: azul (221.2 83.2% 53.3%).
|
||||||
|
Ahora: naranja InQ #F59845 ≈ HSL(28, 90%, 62%).
|
||||||
|
Esto actualiza automáticamente Button default, Switch checked,
|
||||||
|
Tabs ring, Slider y cualquier componente que use bg-primary/text-primary. */
|
||||||
--background: 0 0% 100%;
|
--background: 0 0% 100%;
|
||||||
--foreground: 222.2 84% 4.9%;
|
--foreground: 222.2 84% 4.9%;
|
||||||
--card: 0 0% 100%;
|
--card: 0 0% 100%;
|
||||||
--card-foreground: 222.2 84% 4.9%;
|
--card-foreground: 222.2 84% 4.9%;
|
||||||
--popover: 0 0% 100%;
|
--popover: 0 0% 100%;
|
||||||
--popover-foreground: 222.2 84% 4.9%;
|
--popover-foreground: 222.2 84% 4.9%;
|
||||||
--primary: 221.2 83.2% 53.3%;
|
--primary: 28 90% 62%;
|
||||||
--primary-foreground: 210 40% 98%;
|
--primary-foreground: 0 0% 100%;
|
||||||
--secondary: 210 40% 96.1%;
|
--secondary: 210 40% 96.1%;
|
||||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||||
--muted: 210 40% 96.1%;
|
--muted: 210 40% 96.1%;
|
||||||
@@ -27,8 +32,25 @@
|
|||||||
--destructive-foreground: 210 40% 98%;
|
--destructive-foreground: 210 40% 98%;
|
||||||
--border: 214.3 31.8% 91.4%;
|
--border: 214.3 31.8% 91.4%;
|
||||||
--input: 214.3 31.8% 91.4%;
|
--input: 214.3 31.8% 91.4%;
|
||||||
--ring: 221.2 83.2% 53.3%;
|
--ring: 28 90% 62%;
|
||||||
--radius: 0.5rem;
|
--radius: 0.5rem;
|
||||||
|
|
||||||
|
/* ── InQ ROI brand variables ─────────────────────────────────────────
|
||||||
|
Para uso en CSS inline, SVG y contextos donde Tailwind no aplica.
|
||||||
|
En componentes React, preferir las clases Tailwind (bg-inq-orange, etc.) */
|
||||||
|
--inq-orange: #F59845;
|
||||||
|
--inq-orange-dark: #B45309;
|
||||||
|
--inq-orange-light: #FEF3E2;
|
||||||
|
--inq-orange-lighter: #FFF8ED;
|
||||||
|
--inq-magenta: #ED3E8F;
|
||||||
|
|
||||||
|
/* ── Semánticos ──────────────────────────────────────────────────────*/
|
||||||
|
--color-success: #16A34A;
|
||||||
|
--color-success-light: #F0FDF4;
|
||||||
|
--color-warning: #F59E0B;
|
||||||
|
--color-warning-bg: #FFFBEB;
|
||||||
|
--color-danger: #EF4444;
|
||||||
|
--color-danger-light: #FEE2E2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,10 +45,35 @@ export default {
|
|||||||
DEFAULT: 'hsl(var(--card))',
|
DEFAULT: 'hsl(var(--card))',
|
||||||
foreground: 'hsl(var(--card-foreground))',
|
foreground: 'hsl(var(--card-foreground))',
|
||||||
},
|
},
|
||||||
|
// ── InQ ROI brand tokens ──────────────────────────────────────────
|
||||||
|
// Uso: bg-inq-orange, bg-inq-orange-dark, bg-inq-magenta, etc.
|
||||||
|
// El gradiente identidad (#F59845 → #ED3E8F) se usa SOLO en KPI Hero
|
||||||
|
// y banners principales. NUNCA en bordes ni fondos secundarios.
|
||||||
|
inq: {
|
||||||
|
orange: {
|
||||||
|
DEFAULT: '#F59845',
|
||||||
|
dark: '#B45309',
|
||||||
|
light: '#FEF3E2',
|
||||||
|
lighter: '#FFF8ED',
|
||||||
|
},
|
||||||
|
magenta: '#ED3E8F',
|
||||||
|
},
|
||||||
|
// ── Heatmap (saturado, calibrado para análisis de píxeles E2E) ──
|
||||||
|
// DEBE coincidir con HEATMAP_LOW/MID/HIGH en src/lib/colors.ts.
|
||||||
|
// Cambiar solo en conjunto con recalibración de tests E2E.
|
||||||
heatmap: {
|
heatmap: {
|
||||||
low: '#10b981',
|
low: '#10B981',
|
||||||
mid: '#f59e0b',
|
mid: '#F59E0B',
|
||||||
high: '#ef4444',
|
high: '#EF4444',
|
||||||
|
},
|
||||||
|
// ── Semánticos ───────────────────────────────────────────────────
|
||||||
|
success: {
|
||||||
|
DEFAULT: '#16A34A',
|
||||||
|
light: '#F0FDF4',
|
||||||
|
},
|
||||||
|
warning: {
|
||||||
|
DEFAULT: '#F59E0B',
|
||||||
|
bg: '#FFFBEB',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
borderRadius: {
|
borderRadius: {
|
||||||
|
|||||||
49
tests/design-system/tokens.test.ts
Normal file
49
tests/design-system/tokens.test.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* Tests del sistema de diseño InQ ROI — Sprint 1.5.
|
||||||
|
*
|
||||||
|
* Verifican que los tokens de marca estén correctamente definidos en
|
||||||
|
* tailwind.config.js y que no haya contaminación de la marca hermana CONCILIA.
|
||||||
|
*
|
||||||
|
* Estos tests son la fuente de verdad del contrato de marca: si cambiás
|
||||||
|
* un token, el test falla y te fuerza a ser explícito con el cambio.
|
||||||
|
*/
|
||||||
|
import { describe, it, expect } from 'vitest'
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||||
|
const tailwindConfig = require('../../tailwind.config.js').default ?? require('../../tailwind.config.js')
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const colors = (tailwindConfig.theme.extend.colors) as Record<string, any>
|
||||||
|
|
||||||
|
describe('Design tokens — paleta InQ ROI', () => {
|
||||||
|
it('expone tokens de marca InQ con estructura anidada correcta', () => {
|
||||||
|
const inq = colors.inq
|
||||||
|
|
||||||
|
expect(inq.orange.DEFAULT).toBe('#F59845')
|
||||||
|
expect(inq.orange.dark).toBe('#B45309')
|
||||||
|
expect(inq.orange.light).toBe('#FEF3E2')
|
||||||
|
expect(inq.orange.lighter).toBe('#FFF8ED')
|
||||||
|
expect(inq.magenta).toBe('#ED3E8F')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('NO incluye los colores de CONCILIA (marca hermana, no mezclar)', () => {
|
||||||
|
const configStr = JSON.stringify(tailwindConfig)
|
||||||
|
|
||||||
|
// Morado primario de CONCILIA
|
||||||
|
expect(configStr).not.toContain('#572FA2')
|
||||||
|
expect(configStr).not.toContain('#572fa2')
|
||||||
|
|
||||||
|
// Magenta de CONCILIA
|
||||||
|
expect(configStr).not.toContain('#CB1889')
|
||||||
|
expect(configStr).not.toContain('#cb1889')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('expone tokens del heatmap saturado (calibrado para tests E2E)', () => {
|
||||||
|
const heatmap = colors.heatmap
|
||||||
|
|
||||||
|
// Valores en mayúscula: #10B981, #F59E0B, #EF4444
|
||||||
|
// Deben coincidir con HEATMAP_LOW/MID/HIGH en src/lib/colors.ts
|
||||||
|
expect(heatmap.low).toBe('#10B981')
|
||||||
|
expect(heatmap.mid).toBe('#F59E0B')
|
||||||
|
expect(heatmap.high).toBe('#EF4444')
|
||||||
|
})
|
||||||
|
})
|
||||||
65
tests/e2e/screenshots-etapa-1.spec.ts
Normal file
65
tests/e2e/screenshots-etapa-1.spec.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* Screenshots de validación visual — Etapa 1 Sprint 1.5.
|
||||||
|
*
|
||||||
|
* Captura 3 vistas que muestran la identidad InQ aplicada:
|
||||||
|
* 1. workspace.png — CTAs naranjas, Simular button, tabs
|
||||||
|
* 2. report-tabs.png — tab activo naranja en el reporte
|
||||||
|
* 3. switch-on.png — switch de automatización en estado ON naranja
|
||||||
|
*
|
||||||
|
* Estos screenshots son evidencia de que el cambio de --primary a naranja
|
||||||
|
* se ve correctamente en la aplicación real.
|
||||||
|
*/
|
||||||
|
import { test } from '@playwright/test'
|
||||||
|
import { resolve } from 'path'
|
||||||
|
import { mkdirSync } from 'fs'
|
||||||
|
import { fileURLToPath } from 'url'
|
||||||
|
|
||||||
|
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
||||||
|
const BPMN_DIR = resolve(__dirname, '../../public/sample-processes')
|
||||||
|
const OUT_DIR = resolve(__dirname, '../screenshots/etapa-1')
|
||||||
|
|
||||||
|
test.beforeAll(() => { mkdirSync(OUT_DIR, { recursive: true }) })
|
||||||
|
|
||||||
|
test('screenshot workspace — CTAs naranjas visibles', async ({ page }) => {
|
||||||
|
await page.goto('/')
|
||||||
|
await page.locator('#bpmn-file-input').setInputFiles(resolve(BPMN_DIR, 'simple-linear.bpmn'))
|
||||||
|
await page.waitForURL(/\/workspace\//, { timeout: 15_000 })
|
||||||
|
await page.waitForSelector('button:has-text("Simular")', { timeout: 10_000 })
|
||||||
|
await page.waitForTimeout(1_000)
|
||||||
|
|
||||||
|
await page.screenshot({ path: resolve(OUT_DIR, 'workspace.png'), fullPage: false })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('screenshot switch ON — switch de automatización naranja', async ({ page }) => {
|
||||||
|
await page.goto('/')
|
||||||
|
await page.locator('#bpmn-file-input').setInputFiles(resolve(BPMN_DIR, 'simple-linear.bpmn'))
|
||||||
|
await page.waitForURL(/\/workspace\//, { timeout: 15_000 })
|
||||||
|
await page.waitForSelector('button:has-text("Simular")', { timeout: 10_000 })
|
||||||
|
await page.waitForTimeout(1_500)
|
||||||
|
|
||||||
|
// Hacer click en el primer task del BPMN para abrir el ActivityPanel
|
||||||
|
await page.locator('[data-element-id="task1"]').first().click()
|
||||||
|
await page.waitForTimeout(500)
|
||||||
|
|
||||||
|
// Encender el switch de automatización
|
||||||
|
const toggle = page.getByRole('switch', { name: /automatizable/i })
|
||||||
|
await toggle.click()
|
||||||
|
await page.waitForTimeout(300)
|
||||||
|
|
||||||
|
await page.screenshot({ path: resolve(OUT_DIR, 'switch-on.png'), fullPage: false })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('screenshot report-tabs — tab activo naranja', async ({ page }) => {
|
||||||
|
await page.goto('/')
|
||||||
|
await page.locator('#bpmn-file-input').setInputFiles(resolve(BPMN_DIR, 'medium-with-gateways.bpmn'))
|
||||||
|
await page.waitForURL(/\/workspace\//, { timeout: 15_000 })
|
||||||
|
await page.waitForSelector('button:has-text("Simular")', { timeout: 10_000 })
|
||||||
|
await page.waitForTimeout(1_500)
|
||||||
|
|
||||||
|
const simBtn = page.getByRole('button', { name: 'Simular' })
|
||||||
|
await simBtn.click()
|
||||||
|
await page.waitForURL(/\/report\//, { timeout: 20_000 })
|
||||||
|
await page.waitForSelector('button:has-text("Exportar PDF")', { timeout: 20_000 })
|
||||||
|
|
||||||
|
await page.screenshot({ path: resolve(OUT_DIR, 'report-tabs.png'), fullPage: false })
|
||||||
|
})
|
||||||
21
tests/lib/format-payback.test.ts
Normal file
21
tests/lib/format-payback.test.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* Tests de formatPayback — Sprint 1.5 Etapa 2.
|
||||||
|
*
|
||||||
|
* Stubs preparados. La implementación se agrega en Etapa 2.
|
||||||
|
* Los 7 casos están definidos en SPRINT_1_5_BRIEF_REDISENIO_VISUAL.md § 3.4.
|
||||||
|
*
|
||||||
|
* Regla: un payback de "0.0 meses" (como mostraba el sistema con costos
|
||||||
|
* artificialmente bajos) es confuso. formatPayback resuelve esto con
|
||||||
|
* una escala legible para el consultor y el cliente.
|
||||||
|
*/
|
||||||
|
import { describe, it } from 'vitest'
|
||||||
|
|
||||||
|
describe('formatPayback', () => {
|
||||||
|
it.todo('0 → "Inmediato" (inversión cero con ahorro positivo)')
|
||||||
|
it.todo('0.05 → "< 1 día" (payback de horas, prácticamente instantáneo)')
|
||||||
|
it.todo('0.5 → "< 1 mes (0.50 meses)"')
|
||||||
|
it.todo('6 → "6.0 meses"')
|
||||||
|
it.todo('15 → "15.0 meses (~1.3 años)"')
|
||||||
|
it.todo('30 → "2.5 años"')
|
||||||
|
it.todo('Infinity → "No recupera en horizonte"')
|
||||||
|
})
|
||||||
BIN
tests/screenshots/etapa-1/report-tabs.png
Normal file
BIN
tests/screenshots/etapa-1/report-tabs.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 95 KiB |
BIN
tests/screenshots/etapa-1/switch-on.png
Normal file
BIN
tests/screenshots/etapa-1/switch-on.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
BIN
tests/screenshots/etapa-1/workspace.png
Normal file
BIN
tests/screenshots/etapa-1/workspace.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
Reference in New Issue
Block a user