Files
vuelato/plans/search-queue-tracking.md
Alejandro Martinez b8906efc80
Some checks failed
ci / ci (22, ubuntu-latest) (push) Has been cancelled
Initial commit: Vuelato - buscador de vuelos
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>
2026-04-10 23:37:06 +02:00

4.3 KiB

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)


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