Omnigraph
그래프 엔진으로 컨텍스트를 조립하고, 객체 저장소 기반에서 에이전트가 코드처럼 그래프 데이터를 분기·타입·검토·병합·감사·거버넌스합니다
저장소 정보는 아직 수집하지 않았습니다.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Práctica 1 de Big Data. Aplicación Next.js para ver y ejecutar un pipeline ETL: extraer datos horarios de la API histórica de Open-Meteo, transformarlos, limpiarlos, filtrarlos y seleccionarlos, y cargarlos en una tabla de Supabase.
Stack: Next.js 16 (App Router), TypeScript, Tailwind 4, shadcn/ui (Base UI),
@supabase/supabase-js, MapLibre GL + MapTiler, Vitest.
npm install
cp .env.example .env.local # y rellena los valores
supabase/migrations/20261027000000_mediciones_meteorologicas.sql:
pégala en el SQL Editor del panel o ejecuta supabase db push con la CLI..env.local define:| Variable | Dónde se obtiene | Notas |
|---|---|---|
SUPABASE_URL | Project Settings → Data API | |
SUPABASE_SECRET_KEY | Project Settings → API Keys → Secret keys (sb_secret_…) | Salta RLS. Solo servidor. |
SUPABASE_SERVICE_ROLE_KEY | Clave heredada service_role | Alternativa si no tienes claves nuevas. |
ETL_PERMITIR_SIN_AUTENTICACION | — | Ver «Seguridad». |
NEXT_PUBLIC_MAPTILER_KEY | cloud.maptiler.com → Account → Keys | Mapa (estilo Ocean v4). Es pública: restríngela por dominio. |
Nunca uses NEXT_PUBLIC_ para estas variables. Sin credenciales, la app extrae,
transforma y filtra con normalidad, pero la carga queda deshabilitada y los
endpoints responden 503: no se simula ninguna carga.
npm run dev # http://localhost:3000
npm run typecheck
npm run lint
npm run build
npx vitest run # pruebas (la extracción real necesita red)
.env.local no se sube al repositorio, así que Vercel no ve sus valores. Si en
producción aparece el aviso «Para ver el mapa, define NEXT_PUBLIC_MAPTILER_KEY…»,
falta la variable en Vercel:
NEXT_PUBLIC_MAPTILER_KEY (y las de Supabase) para Production, Preview y
Development.NEXT_PUBLIC_ se incrustan al
compilar: sin un nuevo despliegue no se aplican.https://tu-proyecto.vercel.app) a los orígenes permitidos de la clave.Encima del pipeline hay un mapa de España (MapLibre GL con el estilo Ocean v4 de MapTiler) con las cinco ciudades. Cada marcador muestra el estado de su extracción y, cuando hay datos, la temperatura media de sus registros válidos; al pasar el ratón se ven también el número de registros y la precipitación total.
| Marcador | Significado |
|---|---|
Verde claro (B7E4C7) | Ciudad no extraída |
Verde medio (74C69D) | Pendiente |
| Azul | Descargando |
Verde oscuro (1B4332) | Extraída |
| Rojo | Error |
NEXT_PUBLIC_MAPTILER_KEY (gratuita en cloud.maptiler.com). Esta
clave sí es pública: va al navegador. Restríngela en MapTiler a tus
orígenes (http://localhost:3000 y tu dominio de Vercel). Sin clave, la app
funciona igual y muestra un aviso en lugar del mapa.La interfaz y el mapa usan la misma paleta verde:
D8F3DC · B7E4C7 · 95D5B2 · 74C69D · 52B788 · 40916C · 2D6A4F · 1B4332 · 081C15.
Está definida una sola vez como variables en app/globals.css (--verde-50 …
--verde-800, modo claro y oscuro). En el mapa se aplica sobre las capas del
estilo al cargarlo (components/etl/mapa-ciudades.tsx): el mar se oscurece con
la profundidad y la tierra queda clara para que destaquen las ciudades.
GET por ciudad a
https://archive-api.open-meteo.com/v1/archive con timezone=GMT (UTC),
temperature_unit=celsius y precipitation_unit=mm. Máximo 31 días. El JSON
se guarda sin tocar durante la sesión y se puede descargar. Si una ciudad
falla, se reintenta sola; su respuesta se sustituye, no se acumula.time, temperature_2m, …) se
convierten en un registro por ciudad y hora:
ciudad, fecha_hora, temperatura_c, humedad_pct, precipitacion_mm. Las horas
se interpretan como UTC de forma explícita (se añade Z). Se comprueban las
longitudes de los arrays, el desfase horario y las unidades.null, "" o valores ausentes
nunca se convierten en 0. Se rechaza lo que no tenga ciudad, fecha válida o
alguna medición, la humedad fuera de 0–100 y la precipitación negativa. Las
temperaturas extremas no se descartan. Duplicados por (ciudad, fecha_hora): se
conserva la primera aparición válida en el orden de llegada. Cada rechazo
guarda su motivo.POST /api/carga, que vuelve a validar
y hace un upsert con onConflict: ciudad,fecha_hora (recargar no duplica).
Si un lote falla, los demás conservan su estado y puedes reintentar solo los
fallidos. Después, POST /api/verificar comprueba por lotes que las claves
existen en destino. Supabase no distingue insertadas de actualizadas en un
upsert, así que la app no muestra esa división.La tabla no guarda el orden de inserción: para leer ordenado usa ORDER BY
(la pestaña «Datos en Supabase» siempre lo hace).
lib/supabase/servidor.ts importa server-only).anon/authenticated no pueden leer
ni escribir.NODE_ENV=production los endpoints responden 403 salvo que definas
ETL_PERMITIR_SIN_AUTENTICACION=true. Antes de publicarla, protege los
endpoints (por ejemplo, con Supabase Auth).tests/*.test.ts: transformación, nulos, duplicados, filtros, selección entre
páginas, lotes con fallo parcial y validación de los endpoints. Usan fixtures
inventados de tests/fixtures/, que la app nunca carga.tests/integracion/open-meteo.test.ts: extracción real (Barcelona, 1 día = 24 h UTC).tests/integracion/supabase.test.ts: integración real de los endpoints. Se
omite si no hay SUPABASE_URL y clave. Escribe y borra filas de 1950.
Contra tu proyecto: exporta las variables de .env.local (y opcionalmente
SUPABASE_PUBLISHABLE_KEY para comprobar RLS) y ejecuta npx vitest run tests/integracion.
En local, sin cuenta (requiere Docker): Postgres + PostgREST con la migración aplicada.
docker compose -p etl-pruebas -f tests/integracion/local/docker-compose.yml up -d
node tests/integracion/local/proxy.mjs & # expone /rest/v1 en :54331
export SUPABASE_URL=http://127.0.0.1:54331
export SUPABASE_SECRET_KEY=$(node tests/integracion/local/jwt.mjs service_role)
export SUPABASE_PUBLISHABLE_KEY=$(node tests/integracion/local/jwt.mjs anon)
npx vitest run tests/integracion