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

10 KiB
Raw Permalink Blame History

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.

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.

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

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:

## [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:

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:

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.