# Sprint 8 BRIEF — InQ ROI > **Estado:** borrador pendiente aprobación del director > **Abierto:** 2026-07-07 > **Sprint anterior:** Sprint 7 — multi-tenancy (organizations, 4 roles, Edge Functions, Admin UI) > **Versión base:** v0.8.0 (según SemVer: Sprint 8 arranca en v0.8.0) --- ## Contexto y dirección estratégica Sprint 7 entregó la fundación de multi-tenancy. El producto puede invitar clientes, asignarles roles, y que vean solo sus procesos. Ahora hay tres gaps que bloquean el uso real con clientes: 1. **El modelo de "cliente" en la UI es inconsistente** — `process_groups` (agrupador visual), `clientName` (texto libre), y `org_id` (FK real) son tres conceptos que intentan modelar lo mismo sin coordinación. Un admin que invita a Solar Banco no puede ver sus procesos agrupados como "Solar Banco" en la biblioteca. 2. **client_editor no puede subir su propio BPMN** — si Solar Banco tiene un proceso que quiere modelar, necesita pedirle a InQuality que lo importe. Esto no escala. 3. **No hay versión visible ni changelog** — el producto está en producción sin que nadie sepa qué versión está corriendo ni qué cambió. **Objetivo del sprint:** consolidar el modelo de cliente, habilitar autonomía de client_editor para BPMN, y establecer el ciclo profesional de versiones. Sprint relativamente arquitectónico — ~40% DB/repos, ~40% UI/features, ~20% infra/deuda. --- ## Prioridades del sprint ### Bloque A — Comprometidas (must have) | # | Feature | Tipo | |---|---|---| | Etapa 0 | Versionado: Conventional Commits + CHANGELOG + footer versión | Infra | | Etapa 1 | DB: tabla `areas`, `area_id` en `processes`, drop `process_groups` y `clientName` | DB/migración | | Etapa 2 | Repositorios: `area-repo.ts`, actualizar `process-repo.ts`, tipos y stores | Backend | | Etapa 3 | LibraryPage: agrupar por org → área + ocultar Settings para roles cliente | UI | | Etapa 4 | Workspace sidebar: selector de área reemplaza `clientName` + Admin CRUD de áreas | UI + Admin | | Etapa 5 | client_editor BPMN: política INSERT + UPDATE bpmn_xml, botón importar visible | DB/UI | ### Bloque B — Si hay tiempo (prioridad 2) | # | Feature | Tipo | |---|---|---| | Etapa 6 | Deuda técnica: guards → `beforeLoad` + hard delete + email en admin | Refactor | | Etapa 7 | Página `/help` con documentación de uso para todos los roles | UI | **Nota del director al Bloque B:** si las Etapas 0-5 consumen el sprint, Etapas 6-7 pasan a BACKLOG. No forzar a sprint siguiente sin capacidad real. --- ## Reglas del sprint (no negociables) - `simulador-web/CLAUDE.md` tiene la guía completa de stack, reglas de marca, y la nueva sección de versionado (agregada como Etapa 0) - **Validación visual mandatoria** en cada etapa que modifique UI antes del OK formal - **Brief como contrato:** ninguna etapa arranca sin `ETAPA_X_PROMPT.md` aprobado - **git diff antes de reportar:** incluir en cada reporte la lista de archivos modificados vs. los autorizados - **Iniciativa agéntica clasificada** — Nivel 3 (marca, arquitectura, datos, TECH_DEBT.md) requiere consulta antes de ejecutar - **`isProfileLoaded` como prerequisito** en cualquier componente nuevo condicionado por rol (aprendizaje Sprint 7) - **JOIN vs fetch separado** — cuando un componente necesita datos relacionales para display, preferir JOIN en repo (aprendizaje Sprint 7) --- ## Etapa 0: Versionado profesional **Objetivo:** establecer el ciclo de versiones antes de abrir cualquier feature nueva. ### Alcance **1. Actualizar `simulador-web/CLAUDE.md`** — agregar sección "Gestión de versiones y commits" con: ``` Conventional Commits: feat(scope): descripción fix(scope): descripción refactor(scope): descripción test(scope): descripción docs(scope): descripción chore(scope): descripción scopes comunes: auth, workspace, library, report, pdf, admin, db, e2e, help SemVer: MAJOR: cambio incompatible (nuevo modelo de datos, cambio de rol fundamental) MINOR: feature nueva visible al usuario PATCH: fix de bug o mejora de UX sin feature nueva Sprint 8 arranca en v0.8.0 ``` **2. Crear `CHANGELOG.md`** en raíz de `simulador-web/`, formato Keep a Changelog: ```markdown # Changelog All notable changes to InQ ROI will be documented in this file. ## [Unreleased] ## [0.7.0] - 2026-07-07 ### Added - Multi-tenancy: tabla organizations, 4 roles de plataforma - Edge Functions invite-user y revoke-user - Panel de administración /admin (Organizations, Users) - Login email/password + página /reset-password - back button contextual en workspace (orgName via JOIN en getById) - Política simulations_update (fix para client_editor) ### Fixed - Race condition AuthContext: isProfileLoaded guard - syncProfileFromDB leyendo platform_role desde DB (no inferido por email) - normalizeGroupLabel: limpia artículos iniciales de labels de grupos ## [0.6.0] - 2026-06-24 ... ``` Completar el historial con los sprints anteriores hasta v0.1.0 (MVP). **3. Actualizar `package.json`** — `"version": "0.8.0"` (actualmente tiene algún valor anterior, verificar). **4. Footer con versión visible** — crear `src/components/AppFooter.tsx`: - Muestra `InQ ROI v{version}` leyendo de `src/lib/version.ts` (que importa de `package.json`) - Visible en todas las páginas (LibraryPage, ReportPage, al menos) - Texto pequeño, discreto, esquina inferior **5. Tag de cierre de sprint:** al finalizar Sprint 8, `git tag -a v0.8.0 -m "Release v0.8.0: Sprint 8"`. ### Criterios de validación - [ ] `CHANGELOG.md` existe con historial desde v0.1.0 hasta v0.7.0 - [ ] `package.json` tiene `"version": "0.8.0"` - [ ] Footer visible en LibraryPage mostrando "InQ ROI v0.8.0" - [ ] Build sin errores ### NO entra - Página de "qué hay de nuevo" o modal de release notes - Versionado de procesos (FASE-2) --- ## Etapa 1: Migración DB — tabla `areas` **Objetivo:** crear la infraestructura de datos para el modelo `organizations → areas → processes`. ### Contexto Los tres conceptos de "cliente" actuales: | Concepto | Tabla/Campo | Problema | |---|---|---| | Agrupador visual | `process_groups` | Nombre confuso, sin FK a organizations | | Campo libre | `clientName` (text en processes) | Sin normalización, sin validación | | Tenant real | `org_id` en processes | Correcto pero desconectado de la UI | ### Alcance — Migración 017 ```sql -- 1. Crear tabla areas CREATE TABLE public.areas ( id uuid DEFAULT gen_random_uuid() PRIMARY KEY, org_id uuid REFERENCES public.organizations(id) ON DELETE CASCADE NOT NULL, name text NOT NULL, description text, created_at timestamptz DEFAULT now() NOT NULL, updated_at timestamptz DEFAULT now() NOT NULL ); -- 2. Agregar area_id en processes (reemplaza group_id) ALTER TABLE public.processes ADD COLUMN area_id uuid REFERENCES public.areas(id) ON DELETE SET NULL; -- 3. Eliminar client_name (texto libre) de processes -- Verificar que clientName existe con su nombre exacto en la tabla ALTER TABLE public.processes DROP COLUMN IF EXISTS client_name; -- Nota: verificar nombre exacto antes de ejecutar (puede ser "client_name" o "clientName" en postgres) -- 4. RLS para areas ALTER TABLE public.areas ENABLE ROW LEVEL SECURITY; CREATE POLICY "areas_select" ON public.areas FOR SELECT USING ( -- InQuality ve todas; otros ven solo las de su org public.is_inquality() OR org_id = public.current_org() ); CREATE POLICY "areas_insert" ON public.areas FOR INSERT WITH CHECK ( -- Solo platform_admin puede crear áreas public.current_platform_role() = 'platform_admin' ); CREATE POLICY "areas_update" ON public.areas FOR UPDATE USING ( public.current_platform_role() = 'platform_admin' ); CREATE POLICY "areas_delete" ON public.areas FOR DELETE USING ( public.current_platform_role() = 'platform_admin' ); -- 5. Eliminar process_groups si existe -- Primero verificar que processes.group_id existe y hacer SET NULL antes de drop UPDATE public.processes SET area_id = NULL WHERE area_id IS NULL; -- no-op, sanity check -- Si process_groups existe: -- ALTER TABLE public.processes DROP COLUMN IF EXISTS group_id; -- DROP TABLE IF EXISTS public.areas_old; -- nombre provisional -- DROP TABLE IF EXISTS public.process_groups; -- 6. Migración de datos: bulk-assign procesos sin org a InQuality -- UPDATE public.processes SET org_id = '' WHERE org_id IS NULL; -- (ejecutar con el UUID real de InQuality — buscar en SELECT id FROM organizations WHERE name = 'InQuality') ``` **Precaución importante:** antes de escribir los DROP/ALTER, auditar el schema real con: ```sql SELECT column_name, data_type FROM information_schema.columns WHERE table_name = 'processes' AND table_schema = 'public'; SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name LIKE '%group%'; ``` Reportar nombres exactos antes de ejecutar cualquier DROP. ### Criterios de validación - [ ] Tabla `areas` creada con RLS activa - [ ] `area_id` en `processes` nullable con FK - [ ] `client_name` (o equivalente) eliminado de `processes` - [ ] `process_groups` eliminada (verificar si existe) - [ ] `group_id` en `processes` eliminado (si existía) - [ ] Bulk-assign: todos los procesos tienen `org_id NOT NULL` (o decision explícita sobre los NULL) - [ ] Tests unitarios de RLS: platform_admin puede CRUD en areas, client_editor no puede ### NO entra - CRUD en la UI (eso es Etapa 4) - Cambios en los repositorios de TypeScript (eso es Etapa 2) --- ## Etapa 2: Repositorios y tipos **Objetivo:** crear `area-repo.ts` y actualizar `process-repo.ts` y los tipos de dominio para reflejar el nuevo modelo. ### Alcance **1. Actualizar `src/domain/types.ts`:** ```typescript // Nuevo tipo export interface Area { id: string orgId: string name: string description: string | null createdAt: string } // Actualizar Process — eliminar clientName, agregar areaId y areaName export interface Process { // ... campos existentes ... orgId: string | null orgName?: string | null // poblado via JOIN, no se persiste areaId: string | null // ← nuevo, reemplaza groupId areaName?: string | null // ← nuevo, poblado via JOIN // eliminar: clientName, groupId (si existían) } ``` **2. Crear `src/persistence/supabase/area-repo.ts`:** ```typescript export interface AreaRepo { getByOrg(orgId: string): Promise create(data: { orgId: string; name: string; description?: string }): Promise update(id: string, data: { name?: string; description?: string }): Promise delete(id: string): Promise } ``` **3. Actualizar `src/persistence/supabase/process-repo.ts`:** - `fromRow()`: extraer `areaId` y `areaName` (via JOIN cuando el query lo incluya) - `getById()`: JOIN con `areas` para traer `areaName` embebido (patrón ya establecido con `orgName`) - `getAll()` / `getByOrg()`: incluir `area_id` en select, agregar optional JOIN para `areaName` - `create()`: incluir `area_id` en el objeto de insert (si está presente) - `updateEditable()`: incluir `area_id` en los campos actualizables - Eliminar cualquier referencia a `clientName` o `groupId` **4. Actualizar Zustand store** (`src/store/process-store.ts` o equivalente): - Si el store tenía lógica de `clientName`, actualizarla - Verificar que el tipo `Process` del store usa los nuevos campos **5. Actualizar `src/persistence/supabase/settings-repo.ts`** (si mantenía `process_groups`): - Identificar si hay lógica ligada a `process_groups` y eliminarla o migrarla ### Criterios de validación - [ ] `Area` type definido en `domain/types.ts` - [ ] `Process.areaId` y `Process.areaName` presentes; `clientName`/`groupId` eliminados - [ ] `area-repo.ts` con CRUD completo - [ ] `process-repo.ts` actualizado: fromRow, getById (con JOIN), create, updateEditable - [ ] Build TypeScript sin errores - [ ] Tests unitarios de `area-repo.ts` ### NO entra - Cambios en componentes React (Etapas 3 y 4) - Settings page todavía puede romper — se verá en Etapa 3 --- ## Etapa 3: LibraryPage — agrupación org → área **Objetivo:** reemplazar la agrupación actual por `clientName` con agrupación real por `org → área`. ### Contexto de la UI actual LibraryPage muestra procesos agrupados por `clientName` (texto libre). Hay un panel de "Clientes" (renderizado desde `process_groups`). Para roles cliente, muestra lista plana. El ícono de Settings (⚙) lleva a la página de configuración de grupos — visible para todos los roles. ### Alcance **1. Lógica de agrupación:** - Para `platform_admin` (InQuality): agrupar por `orgName` → dentro de cada org, sub-agrupar por `areaName` - Para `client_editor` / `client_viewer`: mostrar lista plana de sus procesos (sin agrupación — la org es implícita) - Grupos sin área asignada: mostrar en sección "Sin área" dentro de la org correspondiente **2. Estructura visual (admin view):** ``` ┌─ Solar Banco ───────────────────────────────────────────┐ │ ┌─ Área: Operaciones ──────────────────────────────┐ │ │ │ [proceso A] [proceso B] │ │ │ └──────────────────────────────────────────────────┘ │ │ ┌─ Área: Recursos Humanos ─────────────────────────┐ │ │ │ [proceso C] │ │ │ └──────────────────────────────────────────────────┘ │ │ ┌─ Sin área ───────────────────────────────────────┐ │ │ │ [proceso D] │ │ │ └──────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘ ┌─ InQuality ─────────────────────────────────────────────┐ │ ... │ └─────────────────────────────────────────────────────────┘ ``` **3. Eliminar el panel de "Clientes" (process_groups):** - El componente o sección que renderizaba grupos desde `process_groups` se elimina - Verificar qué componentes lo referencian **4. Ocultar Settings para roles cliente:** - El ícono ⚙ en LibraryPage se oculta para `client_editor` y `client_viewer` - Agregar guard en la ruta `/settings` (o el path real): `client_editor` y `client_viewer` redirigen a `/library` - Verificar si `/recursos` también debe ocultarse para clientes (reportar, no decidir unilateralmente) **5. Criterio de wow:** al colapsar/expandir grupos, usar animación suave (Tailwind `transition-all`). Los grupos de org colapsan con click en el header. ### Criterios de validación - [ ] Admin ve procesos agrupados por org → área (validación visual del director) - [ ] client_editor ve lista plana de sus procesos (sin panel de grupos) - [ ] ⚙ Settings no visible para client_editor y client_viewer - [ ] Ruta `/settings` tiene guard de rol - [ ] Animación de colapso funciona - [ ] Build sin errores, tests existentes pasan ### NO entra - CRUD de áreas (Etapa 4) - Workspace sidebar (Etapa 4) --- ## Etapa 4: Workspace sidebar + Admin CRUD de áreas **Objetivo:** (a) reemplazar el campo `clientName` libre en el workspace por un selector de área normalizado; (b) habilitar a admin para crear/editar/eliminar áreas desde `/admin`. ### 4A — Workspace sidebar **Campo "Área" en el panel de configuración del proceso:** - Reemplaza el campo de texto libre "Cliente" (`clientName`) - Para `platform_admin`: dropdown de todas las áreas de la org del proceso (si tiene org asignada) + opción "Sin área". Si el proceso no tiene org, mostrar selector de org primero. - Para `client_editor`: dropdown de áreas de su propia org (su org es implícita — no puede cambiarla) - Para `client_viewer`: read-only, muestra nombre del área si existe - Al cambiar área, actualizar `processStore` y hacer persist en Supabase vía `updateEditable()` **Campo "Organización" en el workspace:** - Para `platform_admin`: selector de org (dropdown de todas las orgs) — permite reasignar un proceso a otra org - Para `client_editor`: read-only, muestra el nombre de su org - Actualizar `org_id` en Supabase cuando el admin cambia la org **Eliminar campo "Cliente" (clientName):** - El campo de texto libre que existía en el sidebar se elimina completamente ### 4B — Admin CRUD de áreas En `/admin/organizations/[orgId]` (o en la página de detalle de org que exista): - Agregar sección "Áreas" con lista de áreas de la org - CRUD: crear área (nombre + descripción opcional), renombrar, eliminar - Al eliminar: si hay procesos con esa área, mostrar confirmación "X procesos quedarán sin área asignada" - RLS garantiza que solo platform_admin puede hacer CRUD **Estructura sugerida:** ``` /admin /organizations → lista de orgs (ya existe) /[orgId] → detalle de org: nombre, miembros, ÁREAS (nuevo) ``` Si `/admin/organizations/[orgId]` no existe, crear la página. Si ya existe (verificar), agregar la sección de Áreas. ### Criterios de validación - [ ] Campo "Cliente" (texto libre) eliminado del workspace sidebar - [ ] Selector de área funciona para platform_admin y client_editor (validación visual) - [ ] Cambio de área persiste en Supabase (verificar Network tab) - [ ] CRUD de áreas en admin funciona (crear, editar, eliminar con confirmación) - [ ] Tests E2E: admin crea área, asigna proceso, client_editor ve sus procesos con área correcta ### NO entra - Jerarquía de áreas (sub-áreas) — FASE-2 - Migrar todos los procesos existentes a áreas manualmente — eso se hace en bulk en la migración DB --- ## Etapa 5: client_editor — permisos de BPMN **Objetivo:** habilitar a `client_editor` para importar nuevos procesos y actualizar el BPMN de procesos existentes de su org. ### Contexto En Sprint 7 Etapa 5, `client_editor` fue bloqueado explícitamente de: - Ver el botón "Importar BPMN" (redireccionado desde `/import`) - Actualizar `bpmn_xml` vía `updateEditable()` (el campo no estaba en la lista de campos editables para ese rol) Esta decisión fue provisional. Sprint 8 la revierte con las restricciones correctas. ### Alcance **1. Migración 018 — política INSERT en `processes` para client_editor:** ```sql -- Ampliar la política de INSERT para incluir client_editor -- (auditar el nombre real de la política INSERT actual antes de DROP) DROP POLICY IF EXISTS "processes_insert" ON public.processes; CREATE POLICY "processes_insert" ON public.processes FOR INSERT WITH CHECK ( -- platform_admin y member pueden insertar sin restricción de org public.current_platform_role() IN ('platform_admin', 'member') OR ( -- client_editor puede crear procesos solo en su propia org public.current_platform_role() = 'client_editor' AND org_id = public.current_org() ) ); ``` **2. Actualizar `updateEditable()` en `process-repo.ts`:** - Incluir `bpmn_xml` en los campos actualizables cuando el caller tiene permisos - Verificar que la política UPDATE existente ya permite que `client_editor` actualice `bpmn_xml` (debería estar cubierta por la política general de UPDATE que verifica org_id) - Si no, agregar rama en la política UPDATE **3. Botón "Importar BPMN" visible para client_editor:** - En `ImportPage.tsx`: eliminar el guard que redirigía a `client_editor` - `client_editor` accede a `/import`, selecciona BPMN, el proceso se crea con `org_id = current_org()` - El `owner_id` se asigna como `auth.uid()` (el client_editor que importó) **4. Restricciones que NO cambian:** - `client_editor` no puede mover procesos entre orgs (no puede cambiar `org_id` a otra org) - `client_editor` no puede cambiar `owner_id` - `client_editor` no puede ver ni modificar procesos de otra org ### Criterios de validación - [ ] Validar con el director usando cambio temporal de rol en Supabase Studio (técnica de Sprint 7) - [ ] `client_editor` puede importar un BPMN nuevo → proceso creado con `org_id` correcto (verificar en Supabase Studio) - [ ] `client_editor` puede abrir un proceso de su org y actualizar el BPMN (re-import) - [ ] `client_editor` NO puede crear procesos con `org_id` de otra org (test E2E adversarial) - [ ] Tests E2E: flujo completo import → workspace → update bpmn como client_editor ### NO entra - client_editor con permisos en `resources` o en `admin` — no cambia - Eliminar procesos (sigue siendo solo platform_admin) --- ## Etapa 6: Deuda técnica consolidada **Objetivo:** resolver items de TECH_DEBT.md acumulados de Sprint 7. Bloque B — solo si hay tiempo. ### 6A — Guards de rol → `beforeLoad` (3 componentes) Migrar de `useEffect` a `beforeLoad` de TanStack Router en: - `AdminLayout.tsx` - `WorkspacePage.tsx` - `ImportPage.tsx` Ejemplo de patrón correcto: ```typescript // En el router (router.tsx o route file) export const adminRoute = createRoute({ getParentRoute: () => rootRoute, path: '/admin', beforeLoad: ({ context }) => { if (!context.auth.isProfileLoaded) return // esperar if (context.auth.user?.platformRole !== 'platform_admin') { throw redirect({ to: '/library' }) } }, }) ``` **Restricción:** no cambiar el comportamiento de los guards, solo el mecanismo. Los tests E2E existentes deben seguir pasando. ### 6B — Hard delete de usuarios Crear Edge Function `delete-user`: - Llama a Supabase Auth Admin API: `supabase.auth.admin.deleteUser(userId)` - Elimina registro de `public.users` - Solo accesible para `platform_admin` - Agregar botón "Eliminar permanentemente" en Admin → Users (con AlertDialog de confirmación doble: "Esta acción no puede deshacerse. El usuario perderá acceso permanentemente.") - Diferencia respecto al soft delete (revoke-user): hard delete borra el auth record ### 6C — Email visible en Admin → Users La tabla de usuarios en admin no muestra el email (que está en `auth.users`, no en `public.users`). Fix: - En la Edge Function de listado de usuarios (o crear una nueva `list-users`), hacer join con `auth.users` via service_role - Mostrar email en la tabla de Admin → Users ### Criterios de validación - [ ] Guards migrados: no hay flash visual al navegar a ruta protegida (verificar con conexión lenta) - [ ] Hard delete funciona y el usuario desaparece de la auth - [ ] Email visible en Admin → Users --- ## Etapa 7: Página `/help` **Objetivo:** documentación de uso del producto para todos los roles. Bloque B — solo si hay tiempo. ### Alcance **Nueva ruta `/help`** accesible para todos los roles autenticados. **Contenido mínimo (4 secciones):** 1. **Cómo parametrizar actividades** - Tiempos de ejecución (tiempo nominal y AS-IS/TO-BE) - Probabilidad de ejecución - Recursos asignados y minutos de utilización - Costo fijo por actividad 2. **Cómo simular y leer el reporte** - Qué hace el botón "Simular" - Indicador de simulación desactualizada - Qué significa cada KPI del reporte - Cómo leer el heatmap - Columnas de la tabla comparativa (ahorro, eficiencia) 3. **Cómo exportar** - PDF: qué incluye cada documento (Actual, Automatizado, ROI) - CSV: estructura del archivo exportado - Cuándo usar PDF vs. CSV 4. **Configuración del proceso (panel Global)** - Campos del panel: nombre, descripción, volumen mensual, horas laborables - Escenario automatizado: costo fijo TO-BE, inversión inicial, ROI **UX:** - Layout con sidebar de navegación a las 4 secciones - Link a `/help` en el footer (junto a la versión) - Criterio de wow: buscador simple de texto en la página ### Criterios de validación - [ ] Las 4 secciones tienen contenido completo y preciso (validación visual del director) - [ ] Link desde footer funciona - [ ] Accesible para todos los roles --- ## Definiciones estables durante Sprint 8 (no reabrir) - Stack tecnológico (sin cambios) - Paleta cromática y sistema de componentes (sin cambios) - Modelo de escenarios Modelo A (sin cambios) - ROI: cálculos nominales simples (sin cambios) - 4 roles de plataforma: `platform_admin`, `member`, `client_editor`, `client_viewer` (sin cambios) --- ## Convención de commits para Sprint 8 ``` feat(areas): tabla areas + RLS en migración 017 feat(area-repo): CRUD de áreas por organización feat(library): agrupación por org → área reemplaza clientName feat(workspace): selector de área reemplaza campo clientName libre feat(admin): CRUD de áreas en panel de organización feat(client-editor): permisos BPMN insert + update vía migración 018 feat(help): página /help con 4 secciones de documentación de uso fix(import): botón importar visible para client_editor refactor(router): guards AdminLayout + WorkspacePage + ImportPage → beforeLoad chore(version): v0.8.0, CHANGELOG.md, footer con versión docs(changelog): etapa N sprint 8 ``` --- ## Archivos de referencia | Archivo | Por qué leerlo antes | |---|---| | `simulador-web/CLAUDE.md` | Reglas de implementación, stack, marca, versionado | | `simulador-web/STRATEGIC_DIRECTION.md` | Decisiones estratégicas para Sprint 8 (sección final) | | `simulador-web/BACKLOG.md` | Item `[SPRINT-8]` con scope de org→areas | | `simulador-web/TECH_DEBT.md` | Items guards + auth para Etapa 6 | | `supabase/migrations/` | Auditar schema actual antes de escribir migraciones 017-018 | | `src/persistence/supabase/process-repo.ts` | Entender fromRow y getById para extender con areaId | | `src/features/library/LibraryPage.tsx` | Entender agrupación actual para reemplazarla | | `src/features/workspace/WorkspacePage.tsx` | Entender sidebar actual para reemplazar clientName | | `src/features/admin/` | Entender estructura de Admin UI para agregar CRUD de áreas |