尚未收集儲存庫資訊。
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗Práctica 1 de la especialización de Big Data. La aplicación ejecuta y muestra un primer pipeline ETL: extrae datos meteorológicos horarios de la API histórica de Open-Meteo, los transforma, los limpia y te deja filtrar y seleccionar qué registros cargar en Supabase. Después comprueba qué ha quedado guardado.
Stack: Next.js 16 (App Router), TypeScript, Tailwind CSS 4, shadcn/ui (Base UI), @supabase/supabase-js
y Vitest.
npm install
cp .env.example .env.local # en Windows: copy .env.example .env.local
supabase/migrations/20261027000000_mediciones_meteorologicas.sql
de una de estas dos formas:
supabase link y después supabase db push..env.local:| Variable | Dónde obtenerla | Uso |
|---|---|---|
SUPABASE_URL | Project Settings → Data API | URL del proyecto |
SUPABASE_SECRET_KEY | Project Settings → API Keys → Secret key (sb_secret_…) | Lectura y escritura solo desde el servidor |
SUPABASE_SERVICE_ROLE_KEY | (opcional) clave service_role heredada (JWT) | Alternativa si el proyecto aún usa claves heredadas |
NEXT_PUBLIC_SUPABASE_URL | La misma URL del proyecto | Pareja de la clave publicable |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY | Project Settings → API Keys → Publishable key (sb_publishable_…) | Clave para el navegador. No es secreta y la carga no la usa |
NEXT_PUBLIC_MAPTILER_KEY | cloud.maptiler.com → Account → API keys | Mapa interactivo (opcional). Es pública: restríngela por dominio en MapTiler |
ETL_PERMITIR_ESCRITURA | — | Ver el apartado Seguridad |
Nunca pongas el prefijo NEXT_PUBLIC_ a SUPABASE_URL ni a la clave secreta: Next.js incluiría
esas variables en el código que se envía al navegador. Solo la clave publicable lleva ese prefijo,
porque está pensada para el navegador.
Con la clave publicable se puede comprobar que la tabla está protegida: una petición de lectura o
escritura a /rest/v1/mediciones_meteorologicas con esa clave recibe «permission denied».
Sin credenciales, la aplicación funciona igualmente hasta la vista previa de la carga. El botón de subida queda deshabilitado y la pantalla indica lo que falta. Nunca se simula una carga.
npm run dev # http://localhost:3000
npm test # pruebas unitarias (fixtures controlados, sin red)
npm run test:red # incluye la prueba de integración real con Open-Meteo
npm run typecheck
npm run lint
npm run build
La pantalla tiene un estilo de panel de control (HUD) y está pensada para que se entienda sin conocer el tema:
NEXT_PUBLIC_MAPTILER_KEY se usa MapTiler (estilo dataviz oscuro).Extracción → Transformación → Limpieza → Filtrado y selección → Carga
lib/etl/extraccion.ts).
https://archive-api.open-meteo.com/v1/archive con
timezone=UTC, °C y mm, para temperature_2m, relative_humidity_2m y precipitation.lib/etl/transformacion.ts).
time, temperature_2m… es la misma hora.
Cada posición se convierte en una fila {ciudad, fecha_hora, temperatura_c, humedad_pct, precipitacion_mm}.fecha_hora se interpreta como UTC de forma explícita (…T00:00 → …T00:00:00.000Z).lib/etl/limpieza.ts).
null, cadena vacía, texto, NaN o ausente. Ninguno de esos valores se
convierte en 0.(ciudad, fecha_hora): se buscan solo entre los registros que ya han
superado las reglas anteriores. Se conserva la primera aparición (orden de ciudades y
posición en el array) y las siguientes se rechazan con el motivo «duplicado de …».Una base de datos no conserva el orden de inserción. Para leer los datos ordenados hay que usar siempre
ORDER BY(la pestaña «Datos en Supabase» lo hace).
lib/supabase/servidor.ts importa server-only). La clave secreta
nunca llega al navegador ni se escribe en los logs.anon
y authenticated, de modo que con la clave publicable no se puede leer ni escribir. El rol de
servidor solo tiene SELECT, INSERT, UPDATE.next start o un despliegue) los endpoints de escritura responden 403, salvo que se defina
ETL_PERMITIR_ESCRITURA=true. Antes de publicarla hay que proteger app/api/supabase/* con
autenticación. Los endpoints de lectura también usan la clave secreta: protégelos igualmente.tests/pipeline.test.ts: URL y validación del periodo, 24 horas UTC para un día, transformación
de los arrays, null que no se convierte en 0, duplicados, filtros y ordenación antes de
paginar, selección entre páginas, y vista previa igual al envío.tests/carga.test.ts: lotes de 500, fallo parcial y reintento solo de los lotes fallidos,
segunda carga sin duplicados y validación en el servidor. Las pruebas de carga usan un destino
simulado en memoria; no sustituyen una prueba contra Supabase.tests/fixtures/sinteticos.ts: datos sintéticos (nulos, duplicados, longitudes incoherentes).
Solo se usan en las pruebas, nunca en la aplicación.tests/fixtures/barcelona-2026-09-01.json: respuesta real capturada de la API.lib/etl/filtrado.tslib/etl/carga.ts y app/api/supabase/).
upsert con
onConflict: "ciudad,fecha_hora".importado_en guarda la fecha de la primera inserción: un upsert posterior no la modifica.