# 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:** - Dexie v3 en producción. Schema actual: `processes`, `activities`, `gateways`, `resources`, `simulations`. - 548 tests verdes (Vitest + Playwright). - Deploy activo: https://process-cost-platform.pages.dev **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): ```typescript // ─── 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): ```typescript 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**: ```typescript 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: ```typescript import type { Process, Activity, GatewayConfig, Resource, Simulation, ProcessGroup, AppSettings } from '@/domain/types' ``` Agregar las dos tablas nuevas a la clase: ```typescript export class ProcessCostDb extends Dexie { processes!: Table activities!: Table gateways!: Table resources!: Table simulations!: Table groups!: Table // 🆕 Sprint 3 settings!: Table // 🆕 Sprint 3 // ... } ``` Agregar versión 4 **después** de la versión 3 existente: ```typescript // 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 ```bash # 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)