### Fase 2a — Lista de la Compra (CRUD) **Duración estimada: 2 semanas** **Objetivo: funcionalidad completa de listas sin sincronización en tiempo real.** #### 2a.1 Base de datos - [ ] Migración: tabla `shopping_lists` con `status enum(active | completed | archived)` - [ ] Migración: tabla `shopping_items` con `name`, `quantity`, `unit`, `is_checked`, `checked_by`, `sort_order` - [ ] RLS: solo miembros del colectivo pueden leer/escribir listas e ítems - [ ] Índice en `shopping_items.list_id` y `shopping_items.sort_order` - [ ] Job `pg_cron`: cada noche, mueve a `archived` las listas completadas hace > 7 días en estado borrado - [ ] Migración: tabla `item_frequency` y trigger de recomendaciones (ver sección 2a.3) #### 2a.2 Frontend - [ ] Pantalla `/lists` — listado de listas activas del colectivo - [ ] Pantalla `/lists/[id]` — vista normal de lista: - Añadir ítem (input rápido: name + quantity + unit) con recomendaciones de ítems frecuentes - Editar ítem inline - Eliminar ítem con swipe (confirmación) - Reordenar con drag & drop (`svelte-dnd-action`) - [ ] Papelera de listas: retención 7 días, restauración, borrado definitivo - [ ] Store Svelte `lists` — listas del colectivo activo, optimistic updates #### 2a.3 Recomendaciones de ítems frecuentes Registra automáticamente la frecuencia de uso de cada ítem del colectivo y la usa como sistema de sugerencias al añadir nuevos ítems. Sin IA — solo frecuencia de uso basada en registros de la base de datos. **Tabla:** ```sql CREATE TABLE item_frequency ( collective_id UUID NOT NULL REFERENCES collectives(id) ON DELETE CASCADE, name TEXT NOT NULL, -- normalized: lower(trim(name)) use_count INTEGER NOT NULL DEFAULT 1, last_used_at TIMESTAMPTZ NOT NULL DEFAULT now(), PRIMARY KEY (collective_id, name) ); CREATE INDEX idx_item_frequency_collective_count ON item_frequency(collective_id, use_count DESC); ``` **Trigger** — se dispara en cada `INSERT` en `shopping_items`, normaliza el nombre y hace upsert: ```sql CREATE OR REPLACE FUNCTION fn_record_item_frequency() RETURNS TRIGGER AS $$ DECLARE v_collective_id UUID; BEGIN SELECT collective_id INTO v_collective_id FROM shopping_lists WHERE id = NEW.list_id; INSERT INTO item_frequency (collective_id, name, use_count, last_used_at) VALUES (v_collective_id, lower(trim(NEW.name)), 1, now()) ON CONFLICT (collective_id, name) DO UPDATE SET use_count = item_frequency.use_count + 1, last_used_at = now(); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_item_frequency AFTER INSERT ON shopping_items FOR EACH ROW EXECUTE FUNCTION fn_record_item_frequency(); ``` **Consulta de sugerencias** — llamada desde el cliente al escribir en el input de añadir ítem: ```sql -- Input vacío: top 5 más usados del colectivo (chips de acceso rápido) SELECT name, use_count FROM item_frequency WHERE collective_id = $1 ORDER BY use_count DESC LIMIT 5; -- Con prefijo: filtro por lo que el usuario va escribiendo SELECT name, use_count FROM item_frequency WHERE collective_id = $1 AND name LIKE lower(trim($2)) || '%' ORDER BY use_count DESC LIMIT 10; ``` **RLS:** los miembros del colectivo solo pueden leer las frecuencias de su colectivo. Escritura solo vía trigger (el rol de la app no tiene `INSERT`/`UPDATE` directo sobre esta tabla). **Comportamiento en UI:** - Input vacío → muestra los 5 ítems más frecuentes como chips de acceso rápido bajo el input - Usuario escribe → sustituye los chips por resultados filtrados por prefijo (máx. 10) - Tap en chip/sugerencia → rellena el input con ese nombre (el usuario puede ajustar cantidad/unidad antes de añadir) - Al confirmar el ítem, el trigger registra la frecuencia automáticamente **Tareas:** - [ ] Migración: tabla `item_frequency` con índice - [ ] Función `fn_record_item_frequency` + trigger `trg_item_frequency` - [ ] RLS en `item_frequency` - [ ] Componente `ItemSuggestions.svelte` — chips + lista filtrada - [ ] Integrar `ItemSuggestions` en el input de añadir ítem de `/lists/[id]` **Criterio de aceptación:** crear, editar, reordenar y eliminar ítems funciona fluidamente. Al añadir un ítem, aparecen sugerencias basadas en el historial del colectivo; añadir un ítem actualiza su frecuencia automáticamente. ---