Files
inq-roi-simulador-web/CLAUDE.md
Marcos Benítez ee356e5de6
Some checks failed
/ Deploy to Cloudflare Pages (push) Has been cancelled
Etapa 7 ya estaba completamente ejecutada en esta sesión. Todo está en su lugar:
Fix A1 — isProfileLoaded en AuthContext 

useState(false) inicial
setIsProfileLoaded(true) si onAuthStateChange devuelve null (no hay usuario que sincronizar)
setIsProfileLoaded(false) en SIGNED_IN (resetea para el nuevo sync)
setIsProfileLoaded(true) en el finally del sync effect (después de syncProfileFromDB, éxito o error)
Fix A2 — Guard en LibraryPage 

if (!user || !isProfileLoaded) devuelve skeleton animado antes de cualquier contenido rol-dependiente
Fix A3 — Campo "cliente" read-only para client_editor 

GlobalSettingsPanel.tsx: <p> estático en lugar de <Input> cuando isClientRole
WorkspacePage.tsx: topbar muestra el valor sin input ni lápiz para client_editor
Fix B — Migración 016 + aplicada a DB 

Archivo supabase/migrations/016_add_simulations_update_policy.sql creado
Policy simulations_update confirmada activa en DB (pg_policies devuelve las 4 policies de simulations)
Fix adicional — 403 en POST /processes  (ejecutado en el turno inmediato anterior)

updateEditable() en process-repo.ts usa .update() en lugar de .upsert() para todos los paths de edición
Tests: 586 verdes, build limpio.

Lo que falta según el checklist del prompt es la validación visual del director (msebem@gmail.com en la app real). Eso requiere tu OK después de verificar en el navegador.

domain/types.ts — orgId: string | null agregado a Process (campo de DB ya existente, ahora mapeado en el dominio).

process-repo.ts — fromRow incluye orgId: (row.org_id as string | null) ?? null. Ambas queries (getById y getAll) usan select('*'), por lo que el campo viene gratis.

WorkspacePage.tsx:

Import supabase para el fetch de org name
Estado orgName + useEffect que hace SELECT name FROM organizations WHERE id = orgId cuando cambia currentProcess?.orgId
Variable isClientRole (solo client_editor — client_viewer ya fue redirigido)
backLabel: "Procesos" para client_editor, nombre de org (o "Volver" mientras carga) si hay orgId, "Biblioteca" si no hay
handleBack(): navega a /?org=<orgId> para admin con proceso de cliente, a / para el resto
El Home button + Tooltip fueron reemplazados por <Button variant="ghost" size="sm"> con ArrowLeft + backLabel
LibraryPage.tsx:

Import useSearch
Lee orgParam = useSearch({ from: '/' }) as { org?: string }
useEffect que, cuando orgParam está presente y la carga terminó, busca el proceso con p.orgId === orgParam, obtiene su groupId, y hace scrollIntoView al elemento group-{groupId}
Los GroupCards en el grid están ahora envueltos en <div id="group-{group.id}"> para ser alcanzables por el scroll
Tests — workspace-back-button.test.ts con 6 casos: admin+orgName, admin+orgName loading, admin sin org, member sin org, client_editor, client_viewer. Fixtures actualizados en 13 archivos con orgId: null. Mock de useSearch agregado en library-ui.test.tsx.
2026-07-07 14:12:10 -03:00

294 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md — InQ ROI · Contexto de implementación
> Leído automáticamente por Claude Code al arrancar desde este directorio.
> Contiene reglas de código, arquitectura, marca y convenciones de implementación.
> Para contexto estratégico y de colaboración ver `cowork/InQ ROI - Simulador de procesos/CLAUDE.md`.
---
## ⚠️ Reglas de Marca — NO NEGOCIABLES
Estas reglas aplican a TODO string que aparezca en código, PDFs, CSVs, tests y documentación.
### Ortografía de "InQ" — SIEMPRE I-n-Q
```
✅ InQ ← correcto
✅ InQuality ← correcto (nombre completo)
✅ InQ ROI ← nombre del producto
❌ INQ ❌ Inq ❌ inq ❌ inQ ← todos son bugs
```
### Paleta protagonista
```
Primario: #F59845 (naranja InQ)
Gradiente: #F59845 → #ED3E8F (naranja → magenta InQ)
```
El gradiente se usa SOLO en KPI Hero y banners principales.
**NO usar colores CONCILIA** (`#572FA2`, `#CB1889`) en este producto.
### Assets de logo
Logos disponibles en `assets/`:
- `MARCA FINAL 2023 AREA DE SEGURIDAD 1 COLOR.png` — logo horizontal color (uso principal)
- `MARCA FINAL 2023 AREA DE SEGURIDAD 1 BCO.png` — logo horizontal blanco (sobre fondos oscuros)
- `MARCA FINAL 2023 AREA DE SEGURIDAD 2 COLOR.png` — versión con área de seguridad 2
- `MARCA FINAL 2023 AREA DE SEGURIDAD 2 ISO COLOR LOGO BCO.png` — isotipo + logo blanco
Usar el logo PNG en lugar de texto "InQ" / "InQuality" en headers de PDF y en la UI cuando corresponda.
### Footer de PDFs
Tagline obligatorio: `"Powered by InQuality"` — en todos los footers de PDF, siempre.
---
## Identidad del Proyecto
**Nombre de trabajo:** InQ ROI
**Una frase:** Plataforma web para que consultores de procesos cuantifiquen costos operativos y calculen ROI de automatización a partir de archivos BPMN 2.0.
**Deploy:** Cloudflare Pages — https://process-cost-platform.pages.dev
**Estado:** Sprint 2 en curso (ver `sprints/sprint-2/BRIEF.md`)
---
## Stack Tecnológico (sin cambios hasta nuevo aviso)
| Capa | Tecnología |
|---|---|
| Lenguaje | TypeScript estricto |
| Framework | React 18 + Vite |
| Routing | TanStack Router |
| Estado | Zustand |
| Canvas BPMN | bpmn-js (Viewer, no Modeler) |
| UI | shadcn/ui sobre Tailwind CSS |
| Iconos | Lucide React |
| Gráficos | Apache ECharts (vía echarts-for-react) |
| Persistencia | IndexedDB vía Dexie (actualmente v2) |
| Validación | Zod |
| Export PDF | jsPDF + jsPDF-autotable + html2canvas |
| Export CSV | papaparse |
| Testing | Vitest + Playwright |
| Deploy | Cloudflare Pages |
**No introduzcas librerías fuera de esta lista sin justificación explícita y consulta al director.**
---
## Arquitectura de Carpetas
```
src/
├── main.tsx
├── App.tsx
├── router.tsx
├── domain/ ← lógica de negocio pura, sin React, testeable
│ ├── types.ts ← tipos TypeScript del dominio
│ ├── simulation.ts ← motor de simulación (acepta scenario: 'actual' | 'automated')
│ ├── roi.ts ← cálculos puros de ROI
│ ├── bpmn-parser.ts
│ └── schemas.ts ← Zod schemas
├── store/ ← Zustand stores
├── persistence/ ← Dexie / IndexedDB
│ └── db.ts ← schema + migraciones (versión actual: v2)
├── features/ ← organizado por feature, no por tipo
│ ├── import/
│ ├── workspace/ ← ActivityPanel, ResourcesPanel, BpmnCanvas, WorkspacePage
│ ├── simulation/
│ └── report/ ← ReportPage, ActivitiesTable, CostByResourceChart, etc.
├── components/ui/ ← shadcn copy-pastes
├── lib/ ← utilidades transversales (format, colors, pdf, csv)
│ └── export/ ← pdf-sections.ts, pdf-sections-roi.ts, csv.ts
└── styles/
```
### Reglas de dependencia (no negociables)
- `domain/` **NO** importa de React, ni de `store/`, ni de `features/`. Es puro.
- `features/` puede importar de `domain/`, `store/`, `persistence/`, `lib/`, `components/`.
- `store/` puede importar de `domain/` y `persistence/`. Nada más.
---
## Estado del modelo de recursos (pre-Sprint 2)
El modelo de recursos está **parcialmente implementado** desde el MVP. Lo que existe:
- `Resource` en `types.ts`: `{ id, processId, name, type, costPerHour }`
- `ActivityResourceAssignment` embebido en `Activity`: `{ resourceId, utilizationPercent: number (0-1) }`
- Tabla `resources` en Dexie desde v1
- `ResourcesPanel.tsx`: CRUD de recursos por proceso
- `ActivityPanel.tsx`: asignación con slider de porcentaje
- Motor de simulación: ya calcula `cost = costPerHour × (executionTimeMinutes/60) × utilizationPercent`
- `CostByResourceChart.tsx`: gráfico en reporte
**Sprint 2 mejora este modelo.** No construye desde cero. Ver `sprints/sprint-2/BRIEF.md` para scope exacto.
---
## Principios de Código
1. **TypeScript strict** activado. Nada de `any` salvo en bordes con librerías sin tipos.
2. **Dominio puro**: funciones en `domain/` son puras, testeables sin DOM.
3. **Componentes tontos, hooks inteligentes**: lógica en custom hooks, JSX limpio.
4. **Sin lógica de negocio en componentes**.
5. **Convenciones de naming**:
- Componentes: `PascalCase.tsx`
- Hooks: `useCamelCase.ts`
- Utilidades: `kebab-case.ts`
- Tipos: `PascalCase`, interfaces con prefijo `I` PROHIBIDO
6. **Comentarios en español**, código (variables, funciones) en inglés.
7. **Errores con mensajes accionables** para el usuario, nunca traces crudos en UI.
8. **Migraciones de schema**: SIEMPRE incrementar versión en Dexie, escribir función de upgrade y test que valide preservación de datos.
---
## Diferencial Visual
El reporte es el corazón del producto. Reglas:
- Tipografía: **Inter** para UI, **JetBrains Mono** para números/datos
- Paleta heatmap: verde `#10b981` → amarillo `#f59e0b` → rojo `#ef4444` (saturados, calibrados en E2E)
- Paleta ROI:
- Ahorro positivo: verde `#10b981`
- Ahorro marginal: gris `#64748b`
- Ahorro negativo: rojo `#ef4444`
- Advertencias de transparencia: amarillo `#f59e0b`
- Cifras de dinero: siempre con separadores y símbolo de moneda
- KPIs de ROI más grandes que KPIs de costos
- Export PDF igual o mejor que pantalla
- Densidad de información media-alta (audiencia: consultor profesional)
---
## Definition of Done — Cada Feature
- [ ] Funciona en happy path
- [ ] Maneja datos vacíos sin crashear
- [ ] Maneja edge cases (división por cero, valores negativos, cero)
- [ ] Persiste en IndexedDB cuando corresponde (con migración si cambió schema)
- [ ] Estilo consistente con el resto de la app
- [ ] Si toca dominio: al menos un test en Vitest
- [ ] Si toca flujo end-to-end: cobertura en Playwright
---
## Comandos del Proyecto
```bash
npm run dev # desarrollo
npm run build # producción
npm run test # tests unitarios con Vitest
npm run lint # eslint
npm run preview # previsualizar build de producción
npx playwright test # tests E2E (Playwright headless)
```
---
## Verificación final antes de entregar artefactos
Antes de presentar cualquier PDF o pantalla:
1. El header/footer dice "InQ ROI" (no "Process Cost Platform" ni otro)
2. El footer incluye "Powered by InQuality"
3. No hay caracteres rotos
4. La marca "InQ" se escribe siempre I-n-Q
---
## Gestión de versiones y commits
> Aplica a partir de Sprint 8. Claude Code es responsable del ciclo completo de versionado.
### Conventional Commits — obligatorio en todos los commits
```
feat(scope): descripción ← feature nueva visible al usuario
fix(scope): descripción ← corrección de bug
refactor(scope): descripción ← refactor sin cambio de comportamiento externo
test(scope): descripción ← solo tests, sin cambio de código de producción
docs(scope): descripción ← solo documentación
chore(scope): descripción ← tareas de infra, build, deps
```
`scope` es el área afectada: `auth`, `workspace`, `library`, `report`, `pdf`, `admin`, `db`, `e2e`, etc.
Ejemplos correctos:
```
feat(workspace): back button contextual con navegación a biblioteca del cliente
fix(process-repo): cambiar upsert por update para evitar 403 en client_editor
refactor(auth): agregar isProfileLoaded para evitar race condition de roles
```
### CHANGELOG.md
Actualizar al cerrar cada etapa. Formato Keep a Changelog:
```markdown
## [Unreleased]
### Added
- Back button contextual en workspace para admin
### Fixed
- 403 en Guardar configuración para client_editor (upsert → update)
```
Al cerrar un sprint, mover `[Unreleased]` a `[vX.Y.Z] - YYYY-MM-DD`.
### SemVer — criterios
- **MAJOR:** cambio incompatible (nuevo modelo de datos, cambio de rol fundamental, migración forzada de usuarios)
- **MINOR:** feature nueva visible al usuario (nueva página, nueva funcionalidad en workspace)
- **PATCH:** corrección de bug o mejora de UX sin feature nueva
Sprint 7 = `v0.7.x` (MVP multi-tenant). Sprint 8 arranca en `v0.8.0`.
### Secuencia de cierre de etapa
Al completar una etapa con cambios en producción:
```bash
git add -A
git commit -m "feat(scope): descripción concisa"
# Actualizar CHANGELOG.md
git add CHANGELOG.md
git commit -m "docs(changelog): etapa N sprint X"
git push origin main
```
Al cerrar un sprint completo, agregar además:
```bash
git tag -a vX.Y.Z -m "Release vX.Y.Z: descripción del sprint"
git push --tags
```
### Versión visible en la app
La versión se lee de `package.json` (`version` field) y se muestra en el footer de todas las páginas (o al menos en `/library` y `/report`). Formato: `InQ ROI v1.2.3`.
Si no existe un componente de footer global, crearlo al implementar esta feature por primera vez.
---
## Política de iniciativa proactiva
Antes de aplicar un cambio fuera del scope del prompt actual, evaluar en orden:
1. ¿Resuelve un ítem listado en `TECH_DEBT.md`, `BACKLOG.md` o archivos de planificación? → **Nivel 3** (consultar antes)
2. ¿Choca con restricción explícita del prompt ("NO entra", "NO tocar")? → **Nivel 3**
3. ¿Modifica paginación, layout, estructura de salida, o contenido visible? → **Nivel 2** mínimo (ejecutar y reportar)
4. ¿Afecta marca, identidad, dependencias o configuración? → **Nivel 3**
5. Si nada aplica → **Nivel 1** (ejecutar libremente)
Argumentos **NO válidos** para evitar consulta:
- "Es mejora de legibilidad"
- "Es consistencia con etapa anterior"
- "Es trivial de revertir"
- "Resuelve un bug menor" (si está en TECH_DEBT.md, es Nivel 3)
Ver `methodology/PATTERNS.md` C.6 y `methodology/ANTI_PATTERNS.md` AP.8.