Omnigraph
Graph engine for context assembly. Object-storage native. Agents work with graph data the way engineers work with code: branched, typed, reviewed, merged, audited, and governed.
Práctica de Big Data: extracción, transformación, limpieza, filtrado y carga.
Translation pending
DataGitHub @TheWavecallerOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Repository information has not been collected yet.
No updates detected yet. GitHub releases will appear here.
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Primera práctica de Big Data. Es una aplicación web para ejecutar y observar un pipeline ETL completo: extraer datos horarios de la API histórica de Open-Meteo, transformarlos, limpiarlos, filtrarlos y seleccionarlos, y cargarlos en Supabase. Cada fase muestra su estado, los registros de entrada y salida y su duración real.
Stack: Next.js 16 (App Router), TypeScript, Tailwind CSS 4, shadcn/ui (Base UI) y @supabase/supabase-js.
npm install
cp .env.example .env.local # y rellena los valores
| Variable | Dónde se usa | Descripción |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL | servidor | URL del proyecto (Project Settings → API) |
SUPABASE_SECRET_KEY | solo servidor | Clave secreta sb_secret_… (o la antigua service_role). Nunca con el prefijo NEXT_PUBLIC_ |
ETL_PERMITIR_ESCRITURA | servidor | En producción la escritura está desactivada salvo que valga true (ver Seguridad) |
NEXT_PUBLIC_MAPTILER_KEY | navegador | Clave de MapTiler para el mapa. Es pública por diseño: restríngela por origen HTTP en cloud.maptiler.com |
El mapa usa MapLibre GL con los estilos dataviz / dataviz-dark de MapTiler. MapLibre 6 carga su
worker desde un archivo aparte: npm install lo copia a public/ (script postinstall).
Aplica la migración supabase/migrations/20261026120000_crear_mediciones_meteorologicas.sql:
npx supabase link --project-ref <ref> y después npx supabase db push.La tabla mediciones_meteorologicas tiene la restricción única (ciudad, fecha_hora) y comprueba
que la humedad está en [0, 100], que la precipitación es ≥ 0 y que ningún valor es NaN ni infinito.
Tiene RLS activado y no tiene políticas.
npm run dev # http://localhost:3000
npm test # pruebas unitarias con fixtures controlados
npm run test:integracion # API real de Open-Meteo y endpoints (requiere npm run dev)
npm run typecheck && npm run lint && npm run build
https://archive-api.open-meteo.com/v1/archive con timezone=GMT, °C y mm. Cada extracción
cubre como máximo 365 días. El JSON original se guarda durante la sesión y se puede descargar.
Si una ciudad falla, se puede reintentar solo esa ciudad; su respuesta sustituye a la anterior,
así que no se acumulan duplicados.lib/etl/transformacion.ts): convierte los
arrays paralelos de hourly en un registro por ciudad y hora. Las horas llegan sin zona
(2026-09-01T00:00) y se interpretan explícitamente como UTC. Si los arrays tienen
longitudes distintas, se avisa y se recorre la longitud máxima, de modo que ningún valor se
pierde sin que se note. Esta fase no corrige ningún valor.lib/etl/limpieza.ts): una fila se rechaza si le falta la
ciudad, si la fecha no es válida o si alguna medición es null, está vacía, es texto o no es
finita. Nunca se convierte nada en 0. También se rechaza la humedad fuera de [0, 100] y la
precipitación negativa. No hay umbrales para temperaturas extremas. Ante un duplicado
(ciudad, fecha_hora) se conserva la primera aparición en el orden de extracción. Cada
rechazo indica su motivo y su tipo (calidad o duplicado).lib/etl/filtros.ts): el orden es
válidos → filtros → ordenación → selección → carga. La paginación solo afecta a la vista. Solo
se suben las filas seleccionadas que siguen cumpliendo los filtros actuales. Las que no los
cumplen se cuentan aparte y no se seleccionan automáticamente filas nuevas.lib/etl/carga.ts, app/api/carga):
al pulsar el botón se congela una copia del conjunto y de su orden. Se envía en lotes de hasta
500 registros, siempre en serie y sin envíos simultáneos. Cada lote hace un por
. El servidor vuelve a validar los datos y el tamaño de la petición, y
devuelve una huella de lo que recibió, que se compara con la de la vista previa. Si un lote
falla, los anteriores conservan su estado y se pueden reintentar solo los fallidos. Después, la
aplicación consulta el destino para comprobar que todas las claves enviadas existen.
Supabase no indica en un upsert qué filas se insertaron y cuáles se actualizaron, así que solo
se informa de las filas «procesadas».El paso 6 · Destino lee la tabla real a través de /api/mediciones, con paginación,
filtros y ORDER BY explícito. Una base de datos no garantiza el orden de inserción: el orden de
lectura hay que pedirlo siempre.
pd.read_csv("validos-filtrados.csv", parse_dates=["fecha_hora"]).df.describe() (n, media,
desviación típica muestral, mínimo, percentiles 25/50/75 y máximo) sobre los registros filtrados.supabase-js, y cómo abrir en pandas el CSV exportado, con botón de copiar.text, timestamptz, float8).localStorage).SUPABASE_SECRET_KEY como Secret; NEXT_PUBLIC_MAPTILER_KEY como Config (va al
navegador por diseño, Vercel avisa si se marca como Secret).localhost y el dominio de producción). Desde las URLs de despliegue o de rama de Vercel el
mapa da 403 salvo que se añada un patrón como <proyecto>-*-<usuario>.vercel.app.lib/supabase/servidor.ts importa server-only). La clave secreta
no llega al navegador; se ha comprobado que no aparece en .next/static.anon y authenticated./api/carga está abierta. En producción
(Vercel) devuelve 403 salvo que ETL_PERMITIR_ESCRITURA=true. Antes de activarla, protege la ruta,
por ejemplo con Supabase Auth, Vercel Deployment Protection o un middleware.tests/fixtures/barcelona-2026-09-01.json: respuesta real guardada (1 ciudad, 1 día).tests/fixtures/respuesta-con-problemas.json: fixture controlado con nulls, cadena vacía,
texto, humedad 104, precipitación negativa, fecha imposible, hora duplicada y un array más corto.
Solo se usa en los tests; nunca se mezcla con las extracciones reales.supabase-js y pandas.| Comando | Qué cubre | Resultado |
|---|---|---|
npm test | 38 pruebas unitarias en 6 archivos: transformación de arrays paralelos, interpretación UTC, limpieza (null, vacíos, textos, rangos, fechas, duplicados, balance válidos + rechazados), filtros y orden antes de paginar, selección entre páginas, lotes y reintentos, validación del servidor, exportación CSV, resúmenes, perfil estadístico y consulta equivalente | 38 superadas |
npm run test:integracion | API real de Open-Meteo, validación del servidor (422 y 413) y, con Supabase configurado, carga, verificación, idempotencia y fallo parcial | 3 superadas; las 3 de Supabase se omiten si no hay credenciales |
npm run typecheck, npm run lint, npm run build | Tipos, estilo y compilación de producción | Sin errores |
| Prueba manual en Vercel | Flujo completo en el despliegue: extracción, limpieza, selección, carga en Supabase y lectura en Destino | Correcta |
| Revisión manual en móvil | Lectura y uso de la interfaz en pantalla pequeña | Correcta |
ETL_PERMITIR_ESCRITURA=true; antes de activarla hay que
proteger /api/carga (ver Seguridad)..env.local y sin ellas se omiten indicando el motivo. La carga real se ha comprobado a mano
en el despliegue de Vercel.(ciudad, fecha_hora)