El fix anterior (1aa1486) interceptaba onOpenChange de SheetPrimitive.Root, pero ese
callback solo se dispara cuando RADIX decide cerrar internamente (Escape, overlay,
botón X). Cuando el padre cierra el Sheet cambiando el prop `open` directamente —que
es lo que hace ProfileSheet.handleSave(): llama onOpenChange(false), que es
setProfileOpen(false) del padre AppHeader— Radix nunca invoca su propio onOpenChange.
El wrapper nunca se ejecutaba para este caso, exactamente el que reportó el usuario
en producción (body queda con pointer-events:none stuck tras guardar perfil).
Fix: useEffect que observa el prop `open` en sí, cubre ambos canales de cierre
(interno de Radix y externo del padre) sin depender de qué disparó el cambio.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Process Cost Platform
Transformá un archivo BPMN 2.0 en un reporte visual de costos operativos — y calculá el ROI de automatizar ese proceso — en minutos, sin backend, sin registro.
Hecho desde Paraguay 🇵🇾 · Herramienta interna de InQuality · Sprint 1 en desarrollo activo
¿Qué hace esto?
Un consultor de procesos recibe un diagrama BPMN del cliente. Con esta plataforma puede:
- Importar el diagrama (.bpmn) y ver el proceso renderizado al instante.
- Configurar costos actividad por actividad: costo fijo, tiempo, recursos humanos/sistemas.
- Simular para obtener el costo esperado de una ejecución completa, con propagación de probabilidades a través de gateways XOR, AND e inclusivos.
- Ver el reporte con mapa de calor sobre el diagrama, KPIs, gráficos, tabla de actividades.
- Exportar a PDF (presentación para el cliente) o CSV (datos para Excel).
En Sprint 1 (en curso):
- Marcar actividades como automatizables y configurar sus costos en el escenario automatizado.
- Calcular el ROI del proyecto de automatización: payback, ahorro anual, acumulado a N años.
- Mostrar un reporte comparativo Actual vs. Automatizado con transparencia metodológica.
Audiencia primaria: consultores de InQuality que usan esto en pre-venta de proyectos de automatización. No es un producto de consumo masivo. El diseño prioriza densidad de información y velocidad de uso.
Inicio rápido
git clone <repo>
cd simulador-web
npm install --legacy-peer-deps
npm run dev
Abre http://localhost:5173. Arrastrá un .bpmn o hacé clic en uno de los tres procesos de ejemplo.
Sin instalación de backend. Todo corre en el navegador. Los datos se guardan en IndexedDB del browser — si borrás el caché, perdés los procesos guardados. Exportá el PDF/CSV antes de limpiar.
Flujo de uso detallado
1. Importar un proceso
Arrastrá tu archivo .bpmn a la pantalla de inicio, o cargá uno de los procesos de ejemplo:
- Proceso lineal simple — para entender el flujo básico
- Aprobación de crédito — con gateways XOR y AND paralelo
- Control de calidad con revisión — con loop
La plataforma soporta BPMN 2.0 con múltiples pools (colaboraciones): todos los pools se importan y sus actividades aparecen configurables en el workspace.
2. Configurar el workspace
El panel derecho tiene tres tabs:
Tab "Actividad" (al hacer click en un nodo del diagrama):
- Costo directo fijo por ejecución
- Tiempo de ejecución en minutos
- Recursos asignados (rol/sistema/equipo con % de utilización)
- Sección "Automatización" (Sprint 1): toggle + costo y tiempo del escenario automatizado
Tab "Recursos": CRUD de recursos reutilizables con costo/hora.
Tab "Global":
- Nombre del proceso y cliente
- Moneda (USD, PYG, BRL, ARS, EUR, COP, MXN, CLP)
- Overhead (% de costos indirectos sobre directos)
- Frecuencia anual de ejecución (Sprint 1)
- Horizonte de análisis en años (Sprint 1)
- Inversión total en automatización (Sprint 1)
Las actividades marcadas como automatizables muestran un badge Bot ámbar (⚙️) en la esquina superior derecha del nodo en el canvas.
3. Simular
El botón "Simular" corre el motor determinístico. Si hay gateways XOR con probabilidades que no suman 100%, el botón queda deshabilitado y se muestran advertencias en la topbar.
Desde Sprint 1, el motor corre dos escenarios simultáneamente (actual + automatizado) y los guarda como un único snapshot. Cualquier cambio en los datos invalida ambos resultados — hay que re-simular.
4. Reportar y exportar
El reporte muestra mapa de calor, KPIs, gráficos y tabla de actividades. En Sprint 1 se agregan tabs de comparación y ROI.
Exportación:
- PDF: 3+ páginas presentables ante el cliente, con heatmap embebido como imagen JPEG.
- CSV: datos con BOM UTF-8 para compatibilidad con Excel regional.
Arquitectura técnica
src/
├── domain/ ← Lógica de negocio pura, sin React, 100% testeable
│ ├── types.ts ← Todas las interfaces del modelo de dominio
│ ├── simulation.ts ← Motor: propaga probabilidades por el grafo BPMN
│ ├── roi.ts ← Cálculos de ROI: payback, ahorro, acumulado (Sprint 1)
│ ├── bpmn-parser.ts← Parser XML BPMN 2.0 → grafo en memoria
│ └── schemas.ts ← Validación Zod de todas las entidades
│
├── store/ ← Estado global con Zustand
│ ├── process-store.ts ← Proceso actual, actividades, gateways, recursos
│ └── simulation-store.ts ← Resultados actual + automatizado, invalidación reactiva
│
├── persistence/ ← IndexedDB vía Dexie (schema versión 2)
│ ├── db.ts ← Schema y migraciones
│ └── repositories.ts ← CRUD de entidades (@internal: solo llamar desde stores)
│
├── features/
│ ├── import/ ← Landing, drag & drop, carga de ejemplos
│ ├── workspace/ ← Canvas BPMN + panel lateral de configuración
│ ├── simulation/ ← Hook useSimulate: dispara ambos escenarios
│ └── report/ ← Reporte visual, heatmap, gráficos, export
│
└── lib/
├── export/ ← pdf-export.ts, csv-export.ts (lazy-loaded al hacer clic)
├── colors.ts ← Gradiente heatmap: verde → ámbar → rojo
└── format.ts ← Formateo de moneda, tiempo, porcentajes
Reglas de dependencia
domain/ ← no importa nada del proyecto (puro TypeScript)
store/ ← importa solo de domain/ y persistence/
features/ ← importa de domain/, store/, persistence/, lib/, components/
La regla ESLint no-restricted-imports hace que cualquier import de
persistence/repositories desde fuera de store/ falle en npm run lint.
La única excepción intencional es simulation-store.ts, que importa
process-store.ts para suscribirse a cambios y mantener la invariante
de invalidación dual (documentado como excepción en el archivo).
Motor de simulación — decisiones clave
El motor acepta scenario: 'actual' | 'automated'. En 'automated', las
actividades con automatable=true usan sus campos alternativos de costo y tiempo.
La probabilidad de ejecución no cambia entre escenarios — solo los costos.
Overlays en el canvas: se usa overlays.add() de diagram-js con posición
{ top: -8, left: element.width - 12 } obtenida via elementRegistry.get().
No usar position.right directamente: la fórmula interna de diagram-js es
left = right * -1 + width, lo que con right: -8 produce left = width + 8
(badge enteramente fuera del nodo, sin overlap de esquina).
Stack tecnológico
| Capa | Tecnología | Nota |
|---|---|---|
| Framework | React 19 + Vite 8 (Rolldown) | |
| Routing | TanStack Router 1.x | Type-safe |
| Estado | Zustand 5 | Stores: process + simulation |
| Canvas BPMN | bpmn-js 18 / diagram-js | Viewer (read-only) |
| UI | shadcn/ui + Tailwind CSS | Components copy-pasted |
| Iconos | Lucide React | |
| Gráficos | Apache ECharts 5 | Lazy-loaded |
| Persistencia | Dexie 4 (IndexedDB) | Schema v2, migraciones automáticas |
| Validación | Zod 3 | |
| Export PDF | jsPDF + jspdf-autotable | Lazy-loaded |
| Export CSV | papaparse 5 | |
| Tests unitarios | Vitest 4 | 336+ tests |
| Tests E2E | Playwright | Con análisis de PDF y píxeles |
| Linting | ESLint 10 (flat config) | no-restricted-imports custom |
| Deploy | Cloudflare Pages | Estático, gratis |
Comandos
# Desarrollo
npm run dev # Servidor local en localhost:5173 con HMR
# Build y preview
npm run build # TypeScript check + Vite build → dist/
npm run preview # Preview del build en localhost:4173
# Testing
npm run test # Tests unitarios e integración (Vitest)
npx playwright test # Tests E2E contra localhost:4173 (requiere build previo)
npx playwright test --config=playwright.prod.config.ts # Smoke test vs producción
# Calidad
npm run lint # ESLint — 0 errores esperados
# Deploy
CLOUDFLARE_ACCOUNT_ID=<id> npx wrangler pages deploy dist \
--project-name=process-cost-platform
Producción
URL: https://process-cost-platform.pages.dev
Plataforma: Cloudflare Pages (estático, sin servidor)
Smoke test post-deploy: npx playwright test --config=playwright.prod.config.ts
Genera tests/e2e/__output__/prod-smoke.pdf como evidencia del flujo completo.
Documentación adicional
| Archivo | Contenido |
|---|---|
ARCHITECTURE.md |
Diseño del sistema, ADRs 1-15, roadmap completo |
CHANGELOG.md |
Historial detallado de cambios por versión |
TODO.md |
Backlog de features y deuda técnica |
METHODOLOGY_AUTOMATED_COST.md |
Guía para calcular el costo automatizado por ejecución |
Los procesos de negocio son activos estratégicos de las empresas y un diferencial competitivo.