feat: MVP Fase 0 — Process Cost Platform v0.1.0

Plataforma completa de análisis de costos operativos basada en BPMN 2.0.

Funcionalidades incluidas:
- Import de archivos BPMN 2.0 por drag & drop + 3 procesos de ejemplo
- Visualización read-only del diagrama (bpmn-js)
- Configuración de actividades (costo, tiempo, recursos asignados)
- CRUD de recursos (rol, persona, sistema, equipo, insumo)
- Configuración global (moneda, overhead %, nombre, cliente)
- Motor de simulación determinístico agregado con propagación de gateways XOR/AND
- Reporte visual con mapa de calor en dos modos (relativo/absoluto)
- Gráficos: KPIs, top actividades, composición, costo por recurso
- Export PDF (jsPDF + html2canvas) y CSV (papaparse)
- Persistencia en IndexedDB (Dexie)
- 268 tests unitarios/integración + 6 E2E con Playwright
- Deploy: https://process-cost-platform.pages.dev

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-14 01:58:40 -03:00
commit bed161c92a
97 changed files with 19638 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
import { formatCurrency, formatPercent } from '@/lib/format'
import { heatmapLegendBounds } from '@/lib/colors'
import type { HeatmapMode } from '@/lib/colors'
import type { ActivitySimResult } from '@/domain/types'
interface HeatmapLegendProps {
perActivity: ActivitySimResult[]
mode: HeatmapMode
currency: string
}
export function HeatmapLegend({ perActivity, mode, currency }: HeatmapLegendProps) {
const bounds = heatmapLegendBounds(perActivity, mode)
function formatBound(value: number): string {
if (bounds.unit === 'percent') return formatPercent(value, value % 1 === 0 ? 0 : 1)
return formatCurrency(value, currency)
}
return (
<div className="flex items-center gap-3 mt-3">
<span className="text-xs text-slate-500 shrink-0">Bajo costo</span>
<div className="flex-1 h-3 rounded-full" style={{
background: 'linear-gradient(to right, #10b981, #f59e0b, #ef4444)'
}} />
<span className="text-xs text-slate-500 shrink-0">Alto costo</span>
<div className="h-4 border-l border-slate-200 mx-1" />
<div className="flex items-center gap-4 text-xs text-slate-400 font-mono">
<span>{formatBound(bounds.min)}</span>
<span>{formatBound(bounds.mid)}</span>
<span>{formatBound(bounds.max)}</span>
</div>
</div>
)
}