# Plan: Sistema de cola de busquedas y seguimiento de precios ## Contexto Vuelato tiene watchlist manual (check precio uno a uno) y busquedas recientes, pero no hay: - Busquedas automaticas en segundo plano - Historico de precios con graficos - Cache de resultados entre usuarios El usuario quiere un sistema completo: definir busquedas recurrentes desde la UI, ver fluctuaciones de precio en tablas/graficos, y ademas una capa de cache que evite llamadas duplicadas a Flightics (TTL 1h) reutilizable tanto por el worker como por busquedas manuales. --- ## 1. Esquema de base de datos **Archivo: `supabase/migrations/00002_search_queue.sql`** ### Tabla `search_cache` — Cache de resultados (publica, sin RLS) - `id` SERIAL PRIMARY KEY - `params_hash` TEXT UNIQUE — SHA-256 del JSON de SearchParams normalizado - `search_params` JSONB — el payload completo - `trips` JSONB — array completo de trips devueltos - `cheapest_price` NUMERIC(10,2) - `total_results` INTEGER - `fetched_at` TIMESTAMPTZ DEFAULT now() ### Tabla `tracked_searches` — Busquedas recurrentes (RLS por user_id) - `id` UUID PK DEFAULT gen_random_uuid() - `user_id` UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE - `name` TEXT NOT NULL - `search_params` JSONB NOT NULL - `route_summary` TEXT NOT NULL - `interval_hours` INTEGER NOT NULL DEFAULT 24 - `is_active` BOOLEAN DEFAULT true - `next_run_at` TIMESTAMPTZ DEFAULT now() - `last_run_at` TIMESTAMPTZ - `run_count` INTEGER DEFAULT 0 - `last_error` TEXT - `expires_at` TIMESTAMPTZ - `created_at` TIMESTAMPTZ DEFAULT now() ### Tabla `search_runs` — Log de ejecuciones (RLS via tracked_search_id) - `id` UUID PK - `tracked_search_id` UUID NOT NULL REFERENCES tracked_searches(id) ON DELETE CASCADE - `status` TEXT DEFAULT 'pending' - `cheapest_price` NUMERIC(10,2) - `total_trips_found` INTEGER DEFAULT 0 - `top_trips` JSONB - `from_cache` BOOLEAN DEFAULT false - `error_message` TEXT - `started_at` TIMESTAMPTZ - `completed_at` TIMESTAMPTZ - `created_at` TIMESTAMPTZ DEFAULT now() ### Tabla `price_snapshots` — Datos para graficos (RLS via tracked_search_id) - `id` UUID PK - `tracked_search_id` UUID NOT NULL REFERENCES tracked_searches(id) ON DELETE CASCADE - `search_run_id` UUID NOT NULL REFERENCES search_runs(id) ON DELETE CASCADE - `cheapest_price` NUMERIC(10,2) NOT NULL - `avg_price` NUMERIC(10,2) - `median_price` NUMERIC(10,2) - `total_results` INTEGER DEFAULT 0 - `recorded_at` TIMESTAMPTZ DEFAULT now() --- ## 2. Cache de busquedas — Flujo integrado ### Hash de parametros (`server/utils/search-hash.ts`) - Normaliza SearchParams (ordena keys, elimina `_poll`), genera SHA-256 - Compartido entre `/api/search` y el worker ### Endpoint `/api/search` modificado (cache-aware) 1. Calcular params_hash 2. Buscar en search_cache WHERE params_hash = hash AND fetched_at > now() - 1 hour 3. Si hay cache fresco → devolver trips del cache 4. Si no → llamar a Flightics, guardar en search_cache, devolver ### Worker usa el mismo cache - Lee cache antes de llamar a Flightics - Escribe al cache tras cada busqueda nueva --- ## 3. Worker (`server/plugins/search-worker.ts`) - Nitro plugin con `setInterval(processQueue, 60_000)` - Mutex para evitar solapamiento - Procesa hasta 5 jobs por ciclo con 10s entre cada uno - Usa `server/utils/supabase-admin.ts` (cliente Supabase con service_role sin H3 event) --- ## 4. API Endpoints (`server/api/tracking/`) | Archivo | Metodo | Funcion | |---------|--------|---------| | `index.get.ts` | GET | Listar tracked_searches con ultimo snapshot | | `index.post.ts` | POST | Crear tracked_search | | `[id].patch.ts` | PATCH | Editar configuracion | | `[id].delete.ts` | DELETE | Eliminar + cascade | | `[id]/history.get.ts` | GET | Price snapshots para graficos | | `[id]/runs.get.ts` | GET | Log de ejecuciones | --- ## 5. Composable (`app/composables/useTrackedSearches.ts`) Patron identico a useWatchlist.ts con watch(user) para auto-load/cleanup. --- ## 6. UI: vue-chartjs + chart.js ## 7. Componentes: tracking/PriceChart, TrackedSearchCard, CreateTrackingForm, RunHistory, TrackingConfig ## 8. Paginas: /tracking (dashboard) + /tracking/[id] (detalle con grafico) ## 9. Integracion: boton en /results, icono en recientes, link en nav --- ## Orden de implementacion ### Fase 1: DB + Cache ### Fase 2: Worker ### Fase 3: API tracking ### Fase 4: Composable + UI basica ### Fase 5: Graficos y detalle ### Fase 6: Integracion