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

```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)
