Some checks failed
/ Deploy to Cloudflare Pages (push) Has been cancelled
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.
294 lines
10 KiB
Markdown
294 lines
10 KiB
Markdown
# 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.
|