Files
inq-roi-simulador-web/sprints/sprint-3/ETAPA_1_PROMPT.md
Marcos Benítez 67e259e6ed 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>
2026-05-27 11:49:43 -03:00

8.4 KiB

Sprint 3 — Etapa 1: Dexie v4 — fundación del modelo de biblioteca

Contexto

Sos Claude Code trabajando en InQ ROI, una herramienta web para análisis de costos de procesos BPMN y cálculo de ROI de automatización. El proyecto está en simulador-web/. 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:

Esta etapa es data layer puro. Sin cambios de UI. Sin cambios de lógica de simulación.


Objetivo

Migrar la base de datos local a Dexie v4 agregando las estructuras necesarias para la Process Library del Sprint 3:

  1. Nuevas interfaces TypeScript: ProcessGroup y AppSettings
  2. Nuevos campos en Process: groupId y tags
  3. Nuevo campo en Activity: automatedAssignedResources
  4. Versión 4 de Dexie con función de upgrade que preserva todos los datos existentes
  5. Tests de migración que verifican preservación de datos y correctos defaults

Cambios autorizados

1. src/domain/types.ts

Agregar al final de la sección de entidades del dominio (antes de los tipos del motor de simulación):

// ─── Process Library ─────────────────────────────────────────────────────────

export interface ProcessGroup {
  id: UUID            // generado con crypto.randomUUID()
  name: string
  createdAt: number   // timestamp Unix ms
  updatedAt: number   // timestamp Unix ms
}

export interface AppSettings {
  id: 'singleton'     // siempre un único registro por instalación
  groupLabel: string  // etiqueta configurable para el nivel de agrupación. Default: 'Cliente'
}

Actualizar Process agregando los dos campos nuevos al final de la interfaz (para no romper destructuring existente):

export interface Process {
  // ... campos existentes sin tocar ...
  groupId: UUID | null  // 🆕 Sprint 3 — null = proceso sin grupo asignado ("Sin clasificar")
  tags: string[]        // 🆕 Sprint 3 — tags libres para clasificación y búsqueda
}

Actualizar Activity agregando el campo nuevo al final de la interfaz:

export interface Activity {
  // ... campos existentes sin tocar ...
  automatedAssignedResources: ActivityResourceAssignment[]  // 🆕 Sprint 3 — recursos del escenario automatizado
}

2. src/persistence/db.ts

Agregar imports de los nuevos tipos:

import type { Process, Activity, GatewayConfig, Resource, Simulation, ProcessGroup, AppSettings } from '@/domain/types'

Agregar las dos tablas nuevas a la clase:

export class ProcessCostDb extends Dexie {
  processes!: Table<Process>
  activities!: Table<Activity>
  gateways!: Table<GatewayConfig>
  resources!: Table<Resource>
  simulations!: Table<Simulation>
  groups!: Table<ProcessGroup>    // 🆕 Sprint 3
  settings!: Table<AppSettings>   // 🆕 Sprint 3
  // ...
}

Agregar versión 4 después de la versión 3 existente:

// Sprint 3: agrega tabla de grupos (Process Library), tabla de settings,
// campos groupId/tags en Process, y automatedAssignedResources en Activity.
this.version(4)
  .stores({
    processes:   'id, name, updatedAt, groupId',  // groupId indexado para queries por grupo
    activities:  'id, processId, bpmnElementId',
    gateways:    'id, processId, bpmnElementId',
    resources:   'id, processId, name',
    simulations: 'id, processId, executedAt',
    groups:      'id, name, updatedAt',           // nueva tabla
    settings:    'id',                            // nueva tabla (singleton)
  })
  .upgrade(async (tx) => {
    // Process: agregar groupId (null) y tags ([])
    await tx.table('processes').toCollection().modify((proc) => {
      if (proc.groupId === undefined) proc.groupId = null
      if (!Array.isArray(proc.tags))  proc.tags = []
    })
    // Activity: agregar automatedAssignedResources ([])
    await tx.table('activities').toCollection().modify((act) => {
      if (!Array.isArray(act.automatedAssignedResources)) {
        act.automatedAssignedResources = []
      }
    })
    // Settings: crear singleton con defaults si no existe
    const existing = await tx.table('settings').get('singleton')
    if (!existing) {
      await tx.table('settings').put({ id: 'singleton', groupLabel: 'Cliente' })
    }
  })

3. Tests de migración

Crear tests/persistence/migration-v4.test.ts con los siguientes casos:

Test 1 — Proceso existente conserva todos sus campos Crear un proceso con el schema v3 (sin groupId ni tags), ejecutar la migración, verificar que todos los campos originales siguen intactos y que groupId === null y tags es un array vacío.

Test 2 — Activity existente conserva todos sus campos y recibe array vacío Crear una activity con assignedResources poblado (al menos un assignment), ejecutar migración, verificar que assignedResources no se alteró y que automatedAssignedResources es [].

Test 3 — Settings singleton creado con defaults Después de la migración, leer settings.get('singleton'), verificar que existe con groupLabel === 'Cliente'.

Test 4 — Idempotencia: upgrade no corrompe datos ya migrados Crear un proceso ya en formato v4 (con groupId: null, tags: []), ejecutar upgrade, verificar que los valores no cambian.

Test 5 — groupId puede ser un UUID válido Crear un grupo, asignar su id como groupId de un proceso, verificar que el campo persiste correctamente y que se puede hacer query processes.where('groupId').equals(groupId).


Lo que NO entra en esta etapa

  • Cambios en ningún componente de UI (features/, components/)
  • Cambios en el motor de simulación (domain/simulation.ts)
  • Cambios en domain/schemas.ts (los schemas Zod se actualizan en la etapa correspondiente)
  • Cambios en lógica de exportación de PDF o CSV
  • Cualquier otro archivo fuera de src/domain/types.ts, src/persistence/db.ts, y los tests nuevos

Si algún cambio en types.ts genera errores TypeScript en otros archivos por los nuevos campos opcionales/requeridos: DETENER y reportar el conflicto al director antes de modificar esos archivos. No resolver unilateralmente. Ver methodology/ANTI_PATTERNS.md AP.9.


Verificación antes de entregar

# 1. Build limpio
npm run build

# 2. Tests unitarios
npm run test

# 3. Control de scope — solo deben aparecer archivos autorizados
git diff --name-only HEAD

El git diff debe mostrar únicamente:

  • src/domain/types.ts
  • src/persistence/db.ts
  • tests/persistence/migration-v4.test.ts (nuevo)

Si aparece cualquier otro archivo: revertirlo y documentarlo como conflicto de scope.


Criterios de aceptación

  • ProcessGroup y AppSettings exportados desde src/domain/types.ts
  • Process.groupId y Process.tags presentes en la interfaz
  • Activity.automatedAssignedResources presente en la interfaz
  • db.ts versión 4 con tablas groups y settings registradas
  • Migración v3→v4: procesos existentes reciben groupId: null y tags: []
  • Migración v3→v4: activities existentes reciben automatedAssignedResources: []
  • Singleton de settings creado con groupLabel: 'Cliente'
  • Los 5 tests de migración verdes
  • Todos los tests previos del proyecto siguen verdes (548+)
  • Build limpio sin errores TypeScript
  • git diff --name-only HEAD muestra solo los 3 archivos autorizados

Reporte esperado al terminar

Incluir en el reporte:

  1. Resultado de git diff --name-only HEAD
  2. Cantidad de tests nuevos y resultado
  3. Resultado del build (npm run build)
  4. Confirmación de que ningún archivo fuera del scope fue modificado
  5. Si hubo alguna decisión de iniciativa (Nivel 1/2/3) tomada durante la etapa, declararla explícitamente

Referencias

  • sprints/sprint-3/BRIEF.md — scope completo del sprint, sección 3 (decisiones arquitectónicas)
  • src/persistence/db.ts — versiones anteriores como referencia de estilo
  • src/domain/types.ts — estado actual del dominio
  • methodology/ANTI_PATTERNS.md — AP.9 (restricciones contradictorias)
  • methodology/PATTERNS.md — C.7 (git diff como control preventivo)