feat(sprint-3): biblioteca, recursos TO-BE, ROI mejorado e identidad de marca
Sprint 3 completo — 7 etapas: - Etapa 1-2: biblioteca de procesos con agrupación por cliente (Dexie v4, LibraryPage, library-store, groupId/tags en Process) - Etapa 3: modal de configuración global por proceso (horizonte, frecuencia, inversión, moneda) con validación y persistencia - Etapa 4: panel de recursos rediseñado con soporte de unidades y minutos de utilización (utilizationMinutes + units) - Etapa 5: recursos en escenario automatizado — motor de simulación, UI de edición en ActivityPanel, comparación AS-IS/TO-BE en reporte - Etapa 6: PDF recursos automatizados, automatedAssignedResources requerido, 561 tests pasando - Etapa 7: identidad de marca — AppHeader gradiente naranja/magenta con logo InQuality en 5 páginas, favicon con logo real, logo/marca navegan a home Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
242
sprints/sprint-3/ETAPA_3_PROMPT.md
Normal file
242
sprints/sprint-3/ETAPA_3_PROMPT.md
Normal file
@@ -0,0 +1,242 @@
|
||||
# Sprint 3 — Etapa 3: Tags + búsqueda + configuración de groupLabel
|
||||
|
||||
## Contexto
|
||||
|
||||
Sos Claude Code trabajando en **InQ ROI**. Las reglas de implementación están en `simulador-web/CLAUDE.md`. El brief del sprint está en `sprints/sprint-3/BRIEF.md`.
|
||||
|
||||
**Estado al iniciar esta etapa:**
|
||||
- Etapa 1 completada: Dexie v4 en producción. `Process.groupId` y `Process.tags` requeridos. `Activity.automatedAssignedResources?` opcional.
|
||||
- Etapa 2 completada: `LibraryPage` es la home (`/`). `ImportPage` en `/import`. `library-store.ts` con `groups`, `processes`, `settings`. `groupRepo` y `settingsRepo` en `repositories.ts`. La biblioteca muestra grupos, "Sin clasificar", búsqueda global y filtro por tags en modo AND.
|
||||
|
||||
**Esta etapa agrega la edición de tags desde el workspace, la configuración de `groupLabel`, y una SettingsPage accesible desde la biblioteca.**
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Tarea preflight — verificar antes de cualquier trabajo nuevo
|
||||
|
||||
Antes de escribir código nuevo, verificar y corregir el siguiente bug en `src/features/library/LibraryPage.tsx`:
|
||||
|
||||
**Bug:** El contador de clientes en el header (`"N procesos · N clientes"`) usa un campo heredado:
|
||||
|
||||
```typescript
|
||||
// LÍNEA ~524 — código actual (INCORRECTO):
|
||||
const totalClients = new Set(processes.map((p) => p.clientName).filter(Boolean)).size
|
||||
```
|
||||
|
||||
`clientName` es un campo del modelo anterior que ya no refleja la agrupación por grupos. El contador no se actualiza cuando se crea un nuevo grupo porque ningún proceso cambia de `clientName`.
|
||||
|
||||
**Fix requerido:**
|
||||
|
||||
```typescript
|
||||
// CORRECTO:
|
||||
const { load, isLoading, processes, groups } = useLibraryStore()
|
||||
// ...
|
||||
const totalClients = groups.length
|
||||
```
|
||||
|
||||
Verificar también que el destructuring en la línea `const { load, isLoading, processes } = useLibraryStore()` (dentro de `LibraryPage`) incluya `groups`.
|
||||
|
||||
**Clasificación de iniciativa:** Nivel 2 — cambio visible al usuario (el contador ahora refleja grupos reales). Reportar en el reporte final.
|
||||
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
1. **Tags en WorkspacePage:** chip input para agregar y quitar tags al proceso actual. Con autocompletado de tags existentes (case-insensitive). Persiste via `updateProcess({ tags: [...] })`.
|
||||
2. **Configuración de `groupLabel`:** nueva `SettingsPage` en ruta `/settings`. Permite cambiar el label del nivel de agrupación. Persiste en `AppSettings`. Reactivo: la UI entera refleja el cambio sin recargar.
|
||||
3. **Acceso a settings desde biblioteca:** ícono ⚙ en el header de `LibraryPage` que navega a `/settings`.
|
||||
4. **`updateSettings` en `library-store.ts`:** nueva acción que actualiza `AppSettings` en Dexie y en el estado Zustand.
|
||||
5. **Verificar filtro de tags en biblioteca:** el filtro AND ya existe desde Etapa 2 — confirmar que funciona correctamente con tags reales (test o validación manual).
|
||||
|
||||
---
|
||||
|
||||
## Cambios autorizados y arquitectura
|
||||
|
||||
### `src/store/library-store.ts`
|
||||
|
||||
Agregar la acción `updateSettings` a la interfaz y al store:
|
||||
|
||||
```typescript
|
||||
interface LibraryState {
|
||||
// ... existentes ...
|
||||
updateSettings: (updates: Partial<Omit<AppSettings, 'id'>>) => Promise<void>
|
||||
getAllTags: () => string[] // computed — retorna tags únicos de todos los procesos (sin async)
|
||||
}
|
||||
```
|
||||
|
||||
Implementación:
|
||||
|
||||
```typescript
|
||||
updateSettings: async (updates) => {
|
||||
await settingsRepo.update(updates)
|
||||
set((state) => ({ settings: { ...state.settings, ...updates } }))
|
||||
},
|
||||
|
||||
getAllTags: () => {
|
||||
const set = new Set<string>()
|
||||
get().processes.forEach((p) => p.tags.forEach((t) => set.add(t)))
|
||||
return [...set].sort()
|
||||
},
|
||||
```
|
||||
|
||||
`getAllTags()` es sincrónico porque `processes` ya está cargado en el store desde `load()`. Si el store no está cargado aún, retorna `[]` — el componente maneja este caso.
|
||||
|
||||
### `src/features/workspace/WorkspacePage.tsx`
|
||||
|
||||
Agregar chip input de tags justo **después del campo `clientName`** (línea ~220 en el archivo actual, después del bloque `{/* Cliente — editable inline */}`).
|
||||
|
||||
**Comportamiento:**
|
||||
- Tags existentes del proceso aparecen como chips removibles con ícono `×`.
|
||||
- Input inline para agregar nuevos tags: placeholder `"Agregar tag..."`.
|
||||
- Al escribir, mostrar dropdown con sugerencias de tags existentes (filtradas por lo que se escribe, case-insensitive). Máximo 6 sugerencias.
|
||||
- Confirmar tag: `Enter` o click en sugerencia.
|
||||
- Si el tag ingresado ya existe en el proceso (case-insensitive): ignorar silenciosamente.
|
||||
- Normalización: guardar tags en lowercase para evitar fragmentación (`"BPMN"` → `"bpmn"`).
|
||||
- Quitar tag: click en el `×` del chip.
|
||||
- Guardar: llamar `updateProcess({ tags: newTags })` después de cada cambio (add o remove).
|
||||
|
||||
**Fuente de tags para autocompletado:** `useLibraryStore().getAllTags()`. Si `library-store` no está inicializado aún (puede ocurrir si el usuario navega directo a `/workspace/...`), hacer `load()` perezoso o simplemente mostrar sugerencias vacías — no bloquear la UI.
|
||||
|
||||
**Nota de arquitectura:** `WorkspacePage` importa de `useProcessStore` para mutaciones y puede importar de `useLibraryStore` para leer la lista de tags globales. Esto es un import de lectura entre stores — aceptable. **No** importar directamente de `repositories.ts`.
|
||||
|
||||
**Estilo de chips:**
|
||||
- Chip de tag: `text-[10px] px-2 py-0.5 rounded-full bg-secondary border border-border text-secondary-foreground`. Mismo estilo que en `ProcessCard` (ya existe en `LibraryPage.tsx`).
|
||||
- Input de agregar: `text-xs bg-transparent border-b border-muted outline-none w-24` — línea subtil, sin box, para no romper el layout del sidebar.
|
||||
- Dropdown de sugerencias: posición absolute, `bg-background border border-border rounded-md shadow-sm`, ancho mínimo del input. Z-index 50.
|
||||
|
||||
### `src/features/settings/SettingsPage.tsx` (NUEVO)
|
||||
|
||||
Nueva ruta `/settings`. Componente simple, sin tabs en esta etapa.
|
||||
|
||||
**Layout:**
|
||||
- Header: título `"Configuración"` (18px, weight 500), subtítulo `"Personalización del workspace"` (12px, color tertiary).
|
||||
- Botón `"← Volver"` que navega a `/`. Color `#F59845`.
|
||||
- Sección `"Biblioteca"`:
|
||||
- Label: `"Etiqueta de grupos"` (13px, weight 500).
|
||||
- Descripción: `"Cómo se llama el nivel de agrupación en la biblioteca. Por defecto: 'Cliente'."` (12px, color tertiary).
|
||||
- Input de texto con el valor actual de `settings.groupLabel`. Al blur o al hacer Enter: guardar via `updateSettings({ groupLabel: value.trim() || 'Cliente' })`.
|
||||
- Preview inline: `"Los procesos se organizarán por [valor]."` que se actualiza mientras se escribe (sin guardar hasta blur/Enter).
|
||||
- Si el input está vacío o en blanco al salir del foco: revertir a `'Cliente'` (valor default).
|
||||
|
||||
**Reactividad:** Como `settings` vive en `useLibraryStore`, cualquier componente que lea `settings.groupLabel` del store se actualiza automáticamente al hacer `updateSettings`. Verificar que `LibraryPage`, `HomeView`, `GroupView` y `GroupCard` usan `settings.groupLabel` del store (ya deberían desde Etapa 2).
|
||||
|
||||
### `src/router.tsx`
|
||||
|
||||
Agregar ruta `/settings`:
|
||||
|
||||
```typescript
|
||||
import { SettingsPage } from '@/features/settings/SettingsPage'
|
||||
|
||||
const settingsRoute = createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
path: '/settings',
|
||||
component: SettingsPage,
|
||||
})
|
||||
|
||||
// Agregar settingsRoute al routeTree
|
||||
```
|
||||
|
||||
### `src/features/library/LibraryPage.tsx`
|
||||
|
||||
Dos cambios:
|
||||
1. Fix del bug del contador (ver sección preflight).
|
||||
2. Agregar ícono de settings en el header: botón con ícono `Settings` (Lucide) que navega a `/settings`. Posicionarlo a la izquierda del botón "Importar BPMN", con estilo ghost (sin fondo, color `text-muted-foreground`, hover `text-foreground`).
|
||||
|
||||
---
|
||||
|
||||
## Versión con wow (recomendada)
|
||||
|
||||
Si el costo de implementación es < 40% sobre la versión mínima, agregar:
|
||||
|
||||
**Tag cloud en home de biblioteca:**
|
||||
- Visible cuando hay al menos 3 tags distintos en la base y no hay búsqueda activa.
|
||||
- Ubicación: entre la barra de búsqueda y la sección de grupos (igual que la fila de tags actual).
|
||||
- Los chips de tags muestran tamaño de fuente proporcional a la frecuencia de uso: tags con más procesos → ligeramente más grandes (rango: `text-[10px]` a `text-[13px]`). Máximo 12 tags.
|
||||
- Click en un chip activa el filtro AND (comportamiento idéntico al existente).
|
||||
- Si ya hay una fila de tags (línea `{tags.length > 0 && ...}`), reemplazarla con el tag cloud. No duplicar.
|
||||
|
||||
**Autocompletado fuzzy en WorkspacePage:**
|
||||
- En lugar de filtrar por `startsWith`, usar `includes` (substring match). Ejemplo: escribir `"proc"` sugiere `"proceso"` y `"subprocess"`.
|
||||
|
||||
---
|
||||
|
||||
## ❌ Lo que NO entra en esta etapa
|
||||
|
||||
- Renombrar o eliminar grupos desde la biblioteca — pendiente
|
||||
- Eliminar procesos desde la biblioteca — backlog
|
||||
- Múltiples niveles de etiquetas configurables — Sprint 4+
|
||||
- Indicador de simulación desactualizada — Etapa 4
|
||||
- Zoom/fit canvas BPMN — Etapa 4
|
||||
- Recursos en escenario automatizado — Etapa 5
|
||||
- Cambios en el motor de simulación, export PDF/CSV
|
||||
- Cambios en `process-store.ts` o `simulation-store.ts`
|
||||
- `Activity.automatedAssignedResources` sigue siendo opcional — no promover a requerido
|
||||
|
||||
---
|
||||
|
||||
## Verificación antes de entregar
|
||||
|
||||
```bash
|
||||
# 1. Build limpio
|
||||
npm run build
|
||||
|
||||
# 2. Tests (todos los previos deben seguir verdes)
|
||||
npm run test
|
||||
|
||||
# 3. Control de scope
|
||||
git diff --name-only HEAD
|
||||
```
|
||||
|
||||
El diff debe mostrar únicamente archivos de:
|
||||
- `src/features/library/LibraryPage.tsx` (fix bug contador + botón settings)
|
||||
- `src/store/library-store.ts` (nuevas acciones `updateSettings`, `getAllTags`)
|
||||
- `src/features/workspace/WorkspacePage.tsx` (chip input de tags)
|
||||
- `src/features/settings/SettingsPage.tsx` (nuevo)
|
||||
- `src/router.tsx` (nueva ruta `/settings`)
|
||||
|
||||
Si aparece cualquier archivo de `src/features/report/`, `src/lib/export/`, `src/domain/simulation.ts`, `src/persistence/db.ts`, `src/store/process-store.ts`, o `src/store/simulation-store.ts`: **revertir y reportar**.
|
||||
|
||||
---
|
||||
|
||||
## Criterios de aceptación
|
||||
|
||||
- [ ] Bug preflight resuelto: el contador `"N clientes"` refleja `groups.length` y se actualiza al crear un grupo.
|
||||
- [ ] Tags del proceso se muestran como chips removibles en el sidebar de WorkspacePage.
|
||||
- [ ] Agregar tag funciona: Enter confirma, el tag se guarda en el proceso (persiste al recargar).
|
||||
- [ ] Autocompletado muestra tags existentes (case-insensitive, substring match en versión wow).
|
||||
- [ ] Tags normalizados a lowercase al guardar.
|
||||
- [ ] SettingsPage en `/settings` permite cambiar `groupLabel`.
|
||||
- [ ] El nuevo label se refleja en toda la UI sin recargar (reactivo via Zustand).
|
||||
- [ ] Botón ⚙ en LibraryPage navega a `/settings`.
|
||||
- [ ] Build sin errores TypeScript.
|
||||
- [ ] Todos los tests previos siguen verdes.
|
||||
- [ ] Validación visual del director aprobada.
|
||||
|
||||
---
|
||||
|
||||
## Criterio de wow
|
||||
|
||||
Un chip input bien ejecutado es la diferencia entre "edito tags" y "organizo mis procesos naturalmente". El autocomplete que aparece mientras escribís y desaparece sin molestar al salir del foco marca esa diferencia. Apuntar a esa experiencia.
|
||||
|
||||
---
|
||||
|
||||
## Reporte esperado al terminar
|
||||
|
||||
1. Confirmación del fix del bug preflight (línea exacta modificada).
|
||||
2. Resultado de `git diff --name-only HEAD` con la lista de archivos modificados.
|
||||
3. Resultado de `npm run build` y `npm run test`.
|
||||
4. Si se implementó versión wow (tag cloud, fuzzy): declararlo.
|
||||
5. Cualquier decisión de iniciativa tomada (Nivel 1/2/3).
|
||||
6. Si hubo algún archivo fuera del scope que requirió modificación: declararlo explícitamente con justificación.
|
||||
|
||||
---
|
||||
|
||||
## Referencias
|
||||
|
||||
- `sprints/sprint-3/BRIEF.md` — sección 4, Feature C
|
||||
- `src/features/library/LibraryPage.tsx` — estructura actual de la home (chip de tags ya existe en `ProcessCard`)
|
||||
- `src/features/workspace/WorkspacePage.tsx` — bloque `clientName` editable (~línea 192-220) — el chip input de tags va después
|
||||
- `src/store/library-store.ts` — store a extender con `updateSettings` y `getAllTags`
|
||||
- `src/persistence/repositories.ts` — `settingsRepo.update` ya existe
|
||||
- `methodology/ANTI_PATTERNS.md` — AP.8 (adelanto silencioso), AP.9 (restricciones contradictorias)
|
||||
- `methodology/PATTERNS.md` — C.7 (git diff como control preventivo)
|
||||
Reference in New Issue
Block a user