Some checks failed
ci / ci (22, ubuntu-latest) (push) Has been cancelled
Nuxt 4 + Supabase + Flightics API. Incluye búsqueda de vuelos, inspiraciones, watchlist, tracking de precios y mapa interactivo. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
131 lines
4.3 KiB
Markdown
131 lines
4.3 KiB
Markdown
# 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
|