feat(sprint-3): biblioteca, recursos TO-BE, ROI mejorado e identidad de marca

Sprint 3 completo — 7 etapas:

- Etapa 1-2: biblioteca de procesos con agrupación por cliente (Dexie v4,
  LibraryPage, library-store, groupId/tags en Process)
- Etapa 3: modal de configuración global por proceso (horizonte, frecuencia,
  inversión, moneda) con validación y persistencia
- Etapa 4: panel de recursos rediseñado con soporte de unidades y minutos
  de utilización (utilizationMinutes + units)
- Etapa 5: recursos en escenario automatizado — motor de simulación,
  UI de edición en ActivityPanel, comparación AS-IS/TO-BE en reporte
- Etapa 6: PDF recursos automatizados, automatedAssignedResources requerido,
  561 tests pasando
- Etapa 7: identidad de marca — AppHeader gradiente naranja/magenta con logo
  InQuality en 5 páginas, favicon con logo real, logo/marca navegan a home

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-27 11:49:43 -03:00
parent d2746f07d1
commit 67e259e6ed
57 changed files with 4372 additions and 82 deletions

View File

@@ -16,7 +16,7 @@ import type { Activity, Process } from '@/domain/types'
// ─── Fixtures de registros "viejos" (sin campos Sprint 1) ─────────────────────
function makeLegacyActivity(id: string, processId: string): Omit<Activity, 'automatable' | 'automatedCostFixed' | 'automatedTimeMinutes'> {
function makeLegacyActivity(id: string, processId: string): Omit<Activity, 'automatable' | 'automatedCostFixed' | 'automatedTimeMinutes' | 'automatedAssignedResources'> {
return {
id, processId,
bpmnElementId: `task_${id}`,
@@ -28,7 +28,7 @@ function makeLegacyActivity(id: string, processId: string): Omit<Activity, 'auto
}
}
function makeLegacyProcess(id: string): Omit<Process, 'annualFrequency' | 'analysisHorizonYears' | 'automationInvestment'> {
function makeLegacyProcess(id: string): Omit<Process, 'annualFrequency' | 'analysisHorizonYears' | 'automationInvestment' | 'groupId' | 'tags'> {
return {
id, name: 'Proceso Legacy', clientName: 'Cliente Viejo',
bpmnXml: '<definitions/>', currency: 'USD', overheadPercentage: 0.15,
@@ -59,6 +59,7 @@ describe('Migración Dexie v2 — Activity: defaults de campos Sprint 1', () =>
automatable: false,
automatedCostFixed: 0,
automatedTimeMinutes: 0,
automatedAssignedResources: [],
}
await activityRepo.save(act)
const retrieved = await activityRepo.getByProcess('p1')
@@ -73,6 +74,7 @@ describe('Migración Dexie v2 — Activity: defaults de campos Sprint 1', () =>
automatable: true,
automatedCostFixed: 12.5,
automatedTimeMinutes: 3,
automatedAssignedResources: [],
}
await activityRepo.save(act)
const [retrieved] = await activityRepo.getByProcess('p1')
@@ -87,6 +89,7 @@ describe('Migración Dexie v2 — Activity: defaults de campos Sprint 1', () =>
automatable: true,
automatedCostFixed: 5,
automatedTimeMinutes: 10,
automatedAssignedResources: [],
}
await activityRepo.save(act)
// Actualizar solo directCostFixed — los campos de automatización no deben cambiar
@@ -105,6 +108,7 @@ describe('Migración Dexie v2 — Process: defaults de campos Sprint 1', () => {
annualFrequency: 1000,
analysisHorizonYears: 3,
automationInvestment: 0,
groupId: null, tags: [],
}
await processRepo.save(proc)
const retrieved = await processRepo.getById('proc-1')
@@ -119,6 +123,7 @@ describe('Migración Dexie v2 — Process: defaults de campos Sprint 1', () => {
annualFrequency: 5000,
analysisHorizonYears: 5,
automationInvestment: 75_000,
groupId: null, tags: [],
}
await processRepo.save(proc)
const retrieved = await processRepo.getById('proc-2')
@@ -133,6 +138,7 @@ describe('Migración Dexie v2 — Process: defaults de campos Sprint 1', () => {
annualFrequency: 2000,
analysisHorizonYears: 4,
automationInvestment: 30_000,
groupId: null, tags: [],
}
await processRepo.save(proc)
// Actualizar solo el nombre — los campos de volumetría no deben cambiar