Initial commit: Vuelato - buscador de vuelos
Some checks failed
ci / ci (22, ubuntu-latest) (push) Has been cancelled
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>
This commit is contained in:
130
plans/search-queue-tracking.md
Normal file
130
plans/search-queue-tracking.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user