Módulo Conector Gaia-X / IDSA sobre EDC — Informe de arranque
Estado: Recopilación / investigación (Fase 0 del proyecto).
Objetivo del proyecto: construir un módulo conector de dataspaces (Gaia-X / IDSA) dentro de la plataforma Carbon (repoNode, antesstorelyAI), usando Eclipse Dataspace Components (EDC) como implementación de referencia del estándar.
Qué es este documento: el mapa del terreno antes de escribir código — los estándares, cómo funciona EDC, cómo es Carbon hoy, dónde encaja el conector, y un roadmap por fases.
0. TL;DR (para quien tiene 2 minutos)
- Gaia-X, IDSA y EDC no compiten: IDSA define el protocolo (Dataspace Protocol, DSP), Gaia-X define la confianza (Trust Framework, identidad federada), y EDC es la implementación que hace ambas cosas.
- EDC es un framework Java 17 / Gradle, modular por extensiones. No es un producto instalable: cada quien compila su propio conector eligiendo módulos. Se opera desde fuera vía una Management API REST (JSON-LD).
- Encaje casi perfecto con Carbon: la capa de datos ya es de tres niveles — R2 (bytes Parquet), Lakekeeper (catálogo REST de Iceberg = los punteros a las tablas) y Supabase (metadata de aplicación: datasets, lineaje, permisos). El data plane de EDC habla S3 con
endpointOverride→ lee/escribe el mismo R2, y podemos compartir tablas Iceberg apuntando al catálogo REST de Lakekeeper (modelo zero-copy). No reescribimos EDC; lo desplegamos como servicio aparte (igual queml-runner) y lo manejamos desde Node por su Management API. - Identidad — resuelta por el modelo de negocio: Carbon apunta a mid-market europeo, desplegable on-prem / cloud soberano, operable por un equipo de 3. Eso fija el modelo: un conector EDC por despliegue (cada cliente = un participante del dataspace), sin multiplexado global. La identidad descentralizada (DID/VC vía IdentityHub + Gaia-X) se ofrece llave en mano, no como algo que el equipo de 3 gestione a mano. La soberanía del dato y el AI Act son el foso, no un extra (ver §8 y sección estratégica).
- Estrategia recomendada: un microservicio
edc-service(conector Java) + un cliente Node (lib/dataspaces/edc-client.ts) + un executor (lib/executors/services/edc.executor.ts) + una pestaña de workspace ("Dataspaces") + un worker BullMQ. Todo sobre plumbing que Carbon ya tiene.
🎯 Posicionamiento y principios de diseño (el porqué)
Esta sección manda sobre todas las decisiones técnicas que siguen.
El producto: Carbon apunta al mid-market vertical europeo — la empresa industrial, agroalimentaria, logística o sanitaria de tamaño medio en España/Europa que necesita ontología + pipelines + gobernanza pero no puede pagar Palantir ni operar Databricks. La promesa: "un Foundry operable por un equipo de 3 personas, a precio de mid-market, con cumplimiento europeo de serie."
El foso (moat): soberanía del dato europea + AI Act. Una plataforma europea, desplegable on-prem o en cloud soberano, con gobernanza y lineaje nativos. No es un checkbox de compliance: es la razón por la que un cliente europeo nos elige frente a un hyperscaler estadounidense.
Por qué esto encaja con dataspaces: Gaia-X/IDSA son la infraestructura europea de soberanía del dato. El conector EDC no es "una feature más" — es la extensión natural del foso: convierte a Carbon en participante de primera clase de la economía del dato europea, con intercambio inter-organización gobernado por políticas (ODRL) y soberano (los datos no salen; se comparte acceso).
Principios de diseño que se derivan:
| Principio | Consecuencia concreta |
|---|---|
| Operable por un equipo de 3 | Identidad, políticas y despliegue del conector llave en mano. Nada de gestionar DIDs a mano. Defaults sensatos. |
| On-prem / cloud soberano | Todo self-hostable, sin dependencias propietarias US. EDC (Java, OSS), Lakekeeper (Rust, OSS), Supabase/Postgres, R2/S3-compatible → todo desplegable dentro de fronteras. Un conector por despliegue (§8). |
| Precio mid-market | Minimizar footprint de infra por cliente: reutilizar lo que ya corre (R2, Postgres, Lakekeeper) antes de sumar servicios. |
| Cumplimiento de serie | Lineaje + gobernanza nativos (DATA_LINEAGE.md); las policies ODRL del dataspace y las credenciales verificables Gaia-X son evidencia de cumplimiento vendible frente al AI Act. |
| Soberanía = no mover el dato | Preferir compute2data / zero-copy (compartir acceso gobernado a la tabla Iceberg vía catálogo) sobre copiar bytes fuera (§3.1). |
1. Los tres estándares y cómo se relacionan
Es el punto que más confusión genera, así que va primero.
| Capa | Quién | Qué aporta | Analogía |
|---|---|---|---|
| Protocolo | IDSA (International Data Spaces Association) | El Dataspace Protocol (DSP): los mensajes y API-bindings entre conectores — catálogo, negociación de contratos, proceso de transferencia. Basado en DCAT (descripción de catálogos) + ODRL (lenguaje de políticas de uso). | El "HTTP" de los dataspaces: cómo hablan dos organizaciones. |
| Confianza | Gaia-X (AISBL) | El Trust Framework: identidad federada, self-descriptions, credenciales verificables, reglas de quién puede participar. | El "TLS/PKI": en quién y por qué confían. |
| Implementación | EDC (Eclipse Dataspace Components, Eclipse Foundation) | El código real que implementa DSP y es compatible con el Trust Framework de Gaia-X. Framework modular en Java. | El "navegador + servidor web": el software que ejecuta todo lo anterior. |
Historia útil: IDSA nació del proyecto de investigación Industrial Data Space (Fraunhofer). EDC es hoy el estándar de facto porque es el que adoptan las grandes iniciativas (Catena-X / Tractus-X en automoción, y despliegues de AWS, etc.).
Conclusión para nosotros: al construir sobre EDC obtenemos DSP + compatibilidad Gaia-X "gratis". Nuestro trabajo es configurar y orquestar un conector EDC desde Carbon, no reimplementar el protocolo.
2. Anatomía de EDC — qué componentes tendríamos que desplegar
EDC separa control de datos (patrón separation of concerns). Un conector se arma eligiendo extensiones Gradle.
┌─────────────────────────────────────────────────────────────┐
│ CONECTOR EDC (participante) │
│ │
│ ┌────────────────────┐ ┌────────────────────────┐ │
│ │ CONTROL PLANE │ │ DATA PLANE │ │
│ │ (administración) │◀──────▶│ (mueve los bytes) │ │
│ │ │ signal │ │ │
│ │ · Assets │ │ · HTTP push/pull │ │
│ │ · Policies (ODRL) │ │ · S3 / AmazonS3 ◀──── │───┼─▶ R2
│ │ · Contract Defs │ │ · Kafka, Azure Blob… │ │
│ │ · Negociación │ └────────────────────────┘ │
│ │ · Transfer Process │ │
│ │ · Management API ◀──┼── REST JSON-LD (aquí engancha Node) │
│ │ · DSP endpoints ◀──┼── protocolo entre conectores │
│ └────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│ │
│ DCP (credential exchange) │ DSP (catalog / negotiation / transfer)
▼ ▼
┌──────────────────┐ ┌──────────────────────┐
│ IDENTITY HUB │ │ OTROS PARTICIPANTES │
│ DIDs + VCs (W3C) │ │ (Provider/Consumer) │
└──────────────────┘ └──────────────────────┘
| Componente | Rol | ¿Lo necesitamos? |
|---|---|---|
| Control Plane | Gestiona assets, políticas, definiciones de contrato; conduce la negociación y coordina transferencias. Expone la Management API (para nosotros) y los endpoints DSP (para otros conectores). | Sí, núcleo. |
| Data Plane | Mueve los datos de verdad. Soporta HTTP (pull/push), Kafka, Azure Blob y S3 / AmazonS3 (con endpointOverride → R2). Coordinado por Data Plane Signaling. | Sí (si somos provider o consumer de datos). |
| IdentityHub | Identidad descentralizada: guarda y presenta DIDs + Verifiable Credentials (protocolo DCP, Decentralized Claims Protocol). Genera claves dinámicamente. | Sí para producción; opcional en PoC (ver §8). |
| Federated Catalog | Descubrimiento de assets entre varios participantes (crawler de catálogos DSP). | Opcional al principio; útil cuando haya >1 contraparte. |
| Management API | REST JSON-LD. Es el punto por el que Carbon (stack no-Java) controla todo el conector: crear assets, políticas, iniciar negociaciones y transferencias, consultar estados. Actualmente v3, migrando a v4. | Sí, es nuestra interfaz principal. |
Runtime / build (importante para el fit):
- Lenguaje: Java 17+, build con Gradle (Kotlin DSL,
build.gradle.kts). - Los módulos incluidos (= capacidades del conector) se declaran en el
build.gradle.ktsde un subdirectorio launcher. - EDC no ship un binario instalable: se compila un launcher propio → imagen Docker.
- Backing services típicos en producción: PostgreSQL (persistencia) + HashiCorp Vault (secretos).
3. Modelo de datos de EDC — el "lenguaje" del conector
Estos son los objetos que crearemos/consultaremos por la Management API. Entenderlos es entender el 80% del trabajo.
| Objeto | Qué es | Lado |
|---|---|---|
| Asset | Un recurso de datos que se ofrece (una tabla, un fichero, un endpoint API). Apunta a un dataAddress (p. ej. un prefijo S3/R2 o una URL HTTP). | Provider |
| Policy (ODRL) | Reglas de acceso y uso: permisos, prohibiciones y deberes ("solo UE", "no reventa", "caduca en 30 días"). | Provider |
| Contract Definition | El emparejamiento "estos assets se ofrecen bajo estas policies". Es lo que aparece en el catálogo. | Provider |
| Contract Negotiation | El baile de oferta/contraoferta entre consumer y provider. Se inicia por API y avanza de estado de forma asíncrona (se consulta el estado por su ID). | Ambos |
| Contract Agreement | Resultado inmutable de una negociación FINALIZED: policy acordada + asset + fecha de firma. | Ambos |
| Transfer Process | La transferencia real del dato una vez hay acuerdo. Puede ser PUSH (provider empuja) o PULL (consumer tira, vía HTTP proxy). Sucede out-of-band (el data plane mueve los bytes, no el control plane). | Ambos |
Flujo end-to-end (consumer pide un dato a un provider):
Para Carbon esto significa: cada dataset del lakehouse que queramos compartir se expone como un Asset EDC; y cada dataset externo que consumamos entra por un Transfer Process cuyo destino es R2 → se registra como snapshot Iceberg con el withNativeControlPlane() que ya tenemos.
3.1 Cómo mapear un dataset de Carbon a un Asset EDC
Un dataset del lakehouse no es un fichero: es una tabla Iceberg (punteros en Lakekeeper → Parquet en R2). Hay dos formas de exponerlo como Asset, y la elección es estratégica:
| Estrategia | dataAddress del Asset | Qué pasa | Cuándo |
|---|---|---|---|
| A. Copia de objetos | Prefijo S3/R2 de los Parquet | El data plane S3 de EDC copia los bytes al bucket del consumer. Simple, nativo, sin código Java extra. | Snapshots puntuales, contrapartes sin motor Iceberg, datos pequeños. PoC / primer hito. |
| B. Zero-copy / compute2data ⭐ | URL HTTPS del catálogo REST de Lakekeeper (scopeado a tabla/warehouse) + creds temporales | El consumer lee la tabla Iceberg in situ (esquema, snapshots, time-travel) sin duplicar. El dato no se mueve; se comparte acceso gobernado. Requiere un DataSource EDC custom (extensión Java) que respete la negociación de contrato. | Preferida por soberanía ("el dato no sale"). Tablas grandes, contrapartes con Trino/Spark/pyiceberg. |
La Estrategia B es el patrón que mejor materializa el foso de soberanía: la autorización se apila en tres capas coherentes — negociación EDC (¿hay contrato?) → Lakekeeper/OpenFGA (¿este participante puede leer esta tabla?) → creds temporales sobre R2. Ver §8.
4. La plataforma Carbon hoy (lo que ya tenemos)
Resumen del mapa del código relevante para este proyecto. (Detalle completo en el informe de arquitectura; aquí solo lo que toca al conector.)
Identidad del repo: C:\Carbon es un symlink a C:\storelyAI. Es un único proyecto, nombre oficial "Node" (package.json → "name": "node"), no un monorepo separado.
Stack:
- Frontend: Next.js 16 (App Router) + React 19 + TypeScript 5.9 + Tailwind 4 + Zustand + React Query. Deploy en Vercel.
- Backend: Next.js Route Handlers (Node 20+) + workers BullMQ sobre Redis (Upstash).
- Datos (3 niveles): R2 (bytes Parquet) · Lakekeeper (catálogo REST de Iceberg = punteros a las tablas; Rust, OSS Apache-licensed, Postgres-backed, authz OpenFGA) · Supabase Postgres con RLS (metadata de aplicación: registro de datasets, lineaje, ledger de txn, permisos).
- Auth: Clerk (sesión JWT + orgs) → puente a RLS de Supabase.
- Servicios externos (contenedores orquestados por
docker-compose.yml): ml-runner (FastAPI/Python, PyIceberg+PyArrow), jupyterhub, kuzu-service.
Piezas clave para el conector:
| Pieza | Ruta | Por qué importa |
|---|---|---|
| Registro de executors (87 servicios) | lib/executors/registry.ts + lib/executors/services/*.executor.ts | El patrón para añadir "un conector externo más". EDC sería el nº 88. |
| Data Gateway / Integraciones | components/workspace/tabs/IntegrationsTab.tsx + app/api/integrations/ | Hub UI + endpoints (/execute, /load-options, /credential-metadata, /sync-config). |
| Lakehouse (control plane propio) | lib/lakehouse/iceberg-native-write.ts (withNativeControlPlane()), fanout-client.ts, read-router.ts | Aquí aterrizan los datos consumidos vía EDC: ledger de txn + commit de snapshot en R2. |
| Almacenamiento físico | R2 (S3-compatible) — S3_ENDPOINT=https://<acct>.r2.cloudflarestorage.com | El mismo bucket que el data plane S3 de EDC puede leer/escribir. |
| Catálogo Iceberg | Lakekeeper (Iceberg REST Catalog, Rust) — los punteros a las tablas; authz OpenFGA (RBAC/ReBAC/ABAC) | Vía por la que EDC comparte tablas Iceberg zero-copy (Estrategia B, §3.1). Self-hostable → soberanía. |
| Credenciales | app/api/credentials/ + tabla credentials (JSONB cifrado + RLS) | Dónde guardaríamos la config del/los conector(es) EDC por workspace. |
| Workers | lib/workers/* (BullMQ) + scripts/start-workers.ts | Dónde vive un edc-sync-worker (polling de estados de negociación/transferencia). |
| Shell del workspace + pestañas | components/workspace/WorkspaceShell.tsx + components/workspace/tabs/* | Dónde se registra una pestaña "Dataspaces". |
| Auth / permisos | lib/graphs/auth.ts (requireWorkspace, requirePermission), lib/db/supabase-rls.ts | El control de acceso interno de Carbon (distinto del de dataspace, ver §8). |
5. Encaje EDC ↔ Carbon (análisis de fit)
| Necesidad de EDC | Qué ya tiene Carbon | Veredicto |
|---|---|---|
| Data plane que lea/escriba datos | R2 (S3-compatible) con Iceberg encima | ✅ Encaje directo. El data plane S3 de EDC apunta al mismo R2 con endpointOverride. |
| Orquestar un runtime externo por HTTP | Ya orquesta ml-runner, jupyterhub, kuzu-service en docker-compose | ✅ Patrón maduro; EDC es "un runner más". |
| Añadir un conector/servicio nuevo | Registro de 87 executors + Data Gateway + credenciales | ✅ Plumbing existente. |
| Aterrizar datos consumidos en el lakehouse | withNativeControlPlane() + fan-out → snapshot Iceberg | ✅ Reutilizable tal cual. |
| Exponer datasets como assets ofertables | Registro de datasets + catálogo REST de Lakekeeper + endpoint de lectura de ml-runner | 🟡 Dos vías (§3.1): copia S3/R2 (nativa) o zero-copy vía Lakekeeper (requiere DataSource EDC custom). |
| Authz fina sobre tablas Iceberg | Lakekeeper + OpenFGA (permisos hasta tabla/vista) | ✅ Ya es la capa ideal para gobernar qué comparte cada participante zero-copy. |
| Identidad de participante de dataspace (DID/VC) | Identidad interna (Clerk/RLS) + authz catálogo (Lakekeeper/OpenFGA) | 🟡 Nueva pero acotada: 1 conector por despliegue (§8), llave en mano, sin gestión manual de DIDs. |
| Runtime Java/Gradle | Stack es TS/Python | 🟡 Nuevo tipo de servicio, pero aislado en su contenedor. Se usa un launcher EDC oficial; no escribimos Java salvo extensiones puntuales. |
Lectura: el 80% del trabajo es plomería de integración (que Carbon facilita) y DevOps (desplegar el conector Java). El 20% genuinamente nuevo es identidad de dataspace y mapear datasets↔assets.
6. Arquitectura de integración propuesta
┌────────────────────────── CARBON (repo Node) ──────────────────────────┐
│ │
│ UI: components/workspace/tabs/dataspaces/DataspacesTab.tsx │
│ │ (catálogo, negociaciones, transferencias, assets propios) │
│ ▼ │
│ API: app/api/dataspaces/* · app/api/integrations/edc/* │
│ │ │
│ ▼ │
│ Executor: lib/executors/services/edc.executor.ts │
│ │ (asset:list · catalog:browse · contract:negotiate · │
│ │ asset:transfer · testConnection) │
│ ▼ │
│ Cliente: lib/dataspaces/edc-client.ts (fetch a la Management API) │
│ │ │
│ Worker: lib/workers/dataspaces/edc-sync-worker.ts (BullMQ) │
│ │ (poll estados async de negociación/transfer → landing) │
│ ▼ │
│ Landing: lib/lakehouse/iceberg-native-write.ts (snapshot en R2) │
│ │
└──────────────────────────────────┬─────────────────────────────────────┘
│ Management API (REST JSON-LD)
▼
┌──────────────────── services/edc-service/ ────────────────────┐
│ Conector EDC (launcher Java/Gradle → imagen Docker) │
│ · Control Plane (Management API + DSP) │
│ · Data Plane (S3 → R2) │
│ · IdentityHub (DID + VC) + Postgres + Vault │
└───────────────────────────────┬────────────────────────────────┘
│ DSP / DCP
▼
Otros participantes del dataspace
Componentes a crear (nombres tentativos):
| Componente | Ruta | Análogo existente |
|---|---|---|
| Servicio conector EDC | services/edc-service/ (Dockerfile Java + build.gradle.kts launcher) | services/ml-runner/ |
| Cliente Node de Management API | lib/dataspaces/edc-client.ts | lib/lakehouse/fanout-client.ts |
| Executor | lib/executors/services/edc.executor.ts (+ alta en registry.ts) | cualquier *.executor.ts |
| Rutas API | app/api/dataspaces/* | app/api/integrations/* |
| Worker de sincronización | lib/workers/dataspaces/edc-sync-worker.ts | lib/workers/cdc/cdc-manager.ts |
| Pestaña de workspace | components/workspace/tabs/dataspaces/DataspacesTab.tsx | IntegrationsTab.tsx |
| Config / credenciales | tabla credentials (service_id edc) + .env (EDC_MANAGEMENT_URL, EDC_API_KEY) | patrón de credenciales existente |
Contrato del executor (borrador):
// lib/executors/services/edc.executor.ts
export const edcExecutor: ServiceExecutor = {
name: 'EDC / Dataspace Connector',
supportedOperations: [
'catalog:browse', // GET catálogo DSP de una contraparte
'asset:list', // assets propios publicados
'asset:publish', // envolver un dataset Carbon como Asset EDC
'policy:create', // definir una ODRL policy
'contract:negotiate', // iniciar negociación → devuelve negotiationId
'contract:status', // consultar estado (async)
'asset:transfer', // iniciar transfer → destino R2 → snapshot Iceberg
],
async execute(req) { /* switch por `${resource}:${operation}` */ },
async testConnection(creds) { /* GET /api/management/v1/version */ },
};
7. Topología de despliegue
Referencia oficial — el Minimum Viable Dataspace (MVD): dos participantes ("Provider Corp" / "Consumer Corp") en Kubernetes (KinD), cada uno con Control Plane + IdentityHub (+ Data Plane en el provider) + PostgreSQL + Vault; con Keycloak y Traefik compartidos. Es un playground, no producción.
Adaptación recomendada para Carbon (arranque):
docker-compose.yml (añadir)
└── edc-service # 1 conector (nosotros somos el participante)
├── control-plane # Management API :8081 + DSP :8282
├── data-plane # S3 → R2
├── identityhub # DID + VC
├── edc-postgres # persistencia del conector (aparte de Supabase)
└── vault # secretos del conector
- PoC / dev: stores en memoria + vault en memoria (como el MVD desde IntelliJ) → cero infra extra.
- Staging/prod: Postgres + Vault dedicados del conector. Ojo: el Postgres del conector es independiente del Supabase de Carbon (el conector persiste su propio estado DSP).
- Vercel: el frontend/API de Carbon sigue en Vercel; el conector EDC vive donde corren hoy los otros contenedores (host de
ml-runner/workers), no en Vercel (es un servicio Java de larga vida).
8. Identidad y autorización — resuelto por el modelo de negocio
El posicionamiento (mid-market, on-prem/soberano, equipo de 3) resuelve lo que antes parecía la decisión más delicada.
8.1 Modelo de despliegue → un conector por instancia
Como Carbon se despliega on-prem o en cloud soberano dedicado, cada cliente corre su propia instancia. Por tanto:
Un conector EDC por despliegue. Cada cliente = un participante del dataspace.
Nada de multiplexar un conector global entre tenants. Esto elimina de un plumazo el aislamiento multi-tenant del conector, encaja con on-prem y mantiene el footprint bajo (principio de precio mid-market).
8.2 Tres capas de autorización, cada una en su frontera
No hay "un choque de identidades" sino tres planos ortogonales que ya casi tenemos:
| Capa | Tecnología | Pregunta que responde | Frontera |
|---|---|---|---|
| App / usuario | Clerk (JWT) + Supabase RLS | ¿Qué puede hacer este usuario en este workspace? (requirePermission('admin') para publicar un asset) | Dentro de Carbon |
| Catálogo / dato | Lakekeeper + OpenFGA (RBAC/ReBAC/ABAC hasta tabla/vista) | ¿Puede este participante leer esta tabla Iceberg? | Acceso a datos |
| Dataspace / inter-org | EDC: DID + Verifiable Credentials (IdentityHub, protocolo DCP) + ODRL | ¿Es esta organización un participante legítimo y cumple la policy del contrato? | Entre organizaciones |
En un intercambio zero-copy (§3.1 Estrategia B) las tres se apilan de forma natural: EDC valida contrato+credenciales → Lakekeeper/OpenFGA valida acceso a la tabla → creds temporales sobre R2. Autorización soberana, defendible ante un auditor.
8.3 Identidad descentralizada, pero llave en mano
La identidad de participante (DID/VC + Gaia-X Trust Framework) es parte del foso, no overhead — pero no puede caer sobre el equipo de 3. Diseño: IdentityHub pre-configurado, claves generadas y rotadas automáticamente, credenciales verificables emitidas con defaults sensatos. El operador ve "conectar a un dataspace", no "gestionar un DID document".
Decisiones que quedan (menores, ya acotadas):
- ¿Emitimos las Verifiable Credentials nosotros (Carbon como issuer gestionado) o nos federamos con un emisor Gaia-X existente del vertical? → empezar auto-emitidas, federar cuando haya un dataspace real.
- Para el PoC: IAM simple (in-memory / OAuth); IdentityHub entra en Fase 6.
9. Riesgos y decisiones abiertas
| Tema | Riesgo / decisión |
|---|---|
| EDC es un objetivo en movimiento | Versiones 0.x, Management API migrando v3→v4, Data Plane Signaling reemplazó controladores antiguos. Fijar una versión y seguir releases. |
| Nuevo lenguaje en el stack | Java/Gradle. Mitigación: usar un launcher oficial + solo extensiones mínimas; tratar EDC como caja negra tras su REST API. |
| Identidad descentralizada | Curva de aprendizaje de DID/VC/DCP y del Trust Framework de Gaia-X. Es lo más nuevo (§8). |
| Multi-tenant | ¿1 conector por tenant vs 1 global? Decidir antes de diseñar el despliegue. |
| Mapeo dataset↔asset | Un dataset Iceberg no es un fichero; decidir si el dataAddress es un prefijo S3/R2 (transferencia de objetos Parquet) o un endpoint HTTP (lectura vía ml-runner). |
| Coste de infra | Cada conector suma Control+Data Plane + Postgres + Vault. Relevante si es por tenant. |
| Governance / policies | Traducir reglas de negocio a ODRL correctamente (soberanía del dato = el diferenciador de todo esto). |
| Reconciliar 3 capas de authz | Clerk/RLS + Lakekeeper/OpenFGA + EDC/ODRL (§8.2). Cada una gobierna una frontera; documentar el mapeo para que sea auditable, no una fuente de bugs de permisos. |
| DataSource Iceberg custom | El zero-copy (§3.1 Estrategia B) no es nativo de EDC: requiere una extensión Java. Mitigación: arrancar con copia S3/R2 (Estrategia A) y evolucionar a zero-copy. |
10. Roadmap por fases (estilo "Stage / Fase")
Alineado con la convención de commits del repo (
Stage N — Fase M).
- Fase 0 — Recopilación (este documento). ✅ Estándares, fit y arquitectura mapeados.
- Fase 1 — PoC local aislado. Levantar un conector EDC (stores en memoria) desde el sample oficial; ejecutar un ciclo completo catálogo → negociación → transferencia entre dos conectores locales. Sin tocar Carbon todavía. Objetivo: entender la Management API de primera mano. → approach detallado: fase-1-poc-approach.md.
- Fase 2 — Data plane sobre R2. Configurar el data plane S3 del conector contra nuestro R2; transferir un objeto Parquet de prueba a un prefijo del lakehouse.
- Fase 3 — Cliente + executor en Node.
lib/dataspaces/edc-client.ts+edc.executor.ts+ rutasapp/api/dataspaces/*. Consumir el catálogo EDC desde Carbon. - Fase 4 — Consumir → lakehouse.
edc-sync-workerque, tras una transferencia, aterriza el dato como snapshot Iceberg víawithNativeControlPlane(). - Fase 5 — Publicar datasets como assets. Empezar con copia S3/R2 (Estrategia A, §3.1); luego el DataSource Iceberg zero-copy vía Lakekeeper (Estrategia B). Cada dataset → Asset + Contract Definition + ODRL policy. Carbon como provider.
- Fase 6 — Identidad de dataspace. IdentityHub / DID + Verifiable Credentials; decidir modelo por-tenant vs global (§8).
- Fase 7 — UI + governance. Pestaña "Dataspaces" en el workspace: catálogo, editor de políticas ODRL, panel de negociaciones/transferencias.
- Fase 8 — Producción. Postgres + Vault dedicados, Federated Catalog, hardening, alta en un dataspace real (Gaia-X Trust Framework).
11. Fuentes
Estándares y visión general
- Eclipse Dataspace Components (EDC) — sitio oficial
- Proyecto EDC — Eclipse Foundation
- International Data Spaces Association — EDC & IDSA
- Gaia-X & IDSA: pilares de los espacios de datos europeos (Inverbis)
- Building a Dataspace: Technical Overview (Gaia-X Hub Austria, whitepaper)
- The EDC Connector: Driving Data Sovereignty (Think-it)
- EDC: Architecture and benefits (doubleSlash)
- A Survey of Dataspace Connector Implementations (arXiv)
- A Service Architecture for Dataspaces (arXiv, 2025)
Técnico / implementación
- EDC Connector — repo · autodoc del Connector
- EDC Samples — transfer / negotiation
- Minimum Viable Dataspace (MVD)
- EDC Technology-AWS (S3/MinIO data plane)
- Developer handbook (Java 17 / Gradle / extensiones)
- Set up a minimum viable data space (AWS Prescriptive Guidance)
- Tractus-X EDC (despliegue real, Catena-X)
- Lakekeeper — Iceberg REST Catalog (Rust, OSS) · docs · authorization (OpenFGA)
- Iceberg en EDC / compute2data (Tractus-X discussion #1541)
- Apache Iceberg REST Catalog spec
Documento vivo. Siguiente paso sugerido: Fase 1 — levantar el sample oficial de EDC y recorrer un ciclo de transferencia end-to-end.