Published

Módulo Conector Gaia-X / IDSA sobre EDC — Informe de arranque

Connect any source, model it as an ontology, transform it, and operationalize it, analytics, automation and machine learning, under one governed, self-hostable roof. --- Most teams stitch the...

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 (repo Node, antes storelyAI), 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 nivelesR2 (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 que ml-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:

PrincipioConsecuencia concreta
Operable por un equipo de 3Identidad, políticas y despliegue del conector llave en mano. Nada de gestionar DIDs a mano. Defaults sensatos.
On-prem / cloud soberanoTodo 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-marketMinimizar footprint de infra por cliente: reutilizar lo que ya corre (R2, Postgres, Lakekeeper) antes de sumar servicios.
Cumplimiento de serieLineaje + 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 datoPreferir 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.

CapaQuiénQué aportaAnalogía
ProtocoloIDSA (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.
ConfianzaGaia-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ónEDC (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) │
└──────────────────┘              └──────────────────────┘
ComponenteRol¿Lo necesitamos?
Control PlaneGestiona 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 PlaneMueve los datos de verdad. Soporta HTTP (pull/push), Kafka, Azure Blob y S3 / AmazonS3 (con endpointOverrideR2). Coordinado por Data Plane Signaling. (si somos provider o consumer de datos).
IdentityHubIdentidad 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 CatalogDescubrimiento de assets entre varios participantes (crawler de catálogos DSP).Opcional al principio; útil cuando haya >1 contraparte.
Management APIREST 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.kts de 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.

ObjetoQué esLado
AssetUn 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 DefinitionEl emparejamiento "estos assets se ofrecen bajo estas policies". Es lo que aparece en el catálogo.Provider
Contract NegotiationEl 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 AgreementResultado inmutable de una negociación FINALIZED: policy acordada + asset + fecha de firma.Ambos
Transfer ProcessLa 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:

EstrategiadataAddress del AssetQué pasaCuándo
A. Copia de objetosPrefijo S3/R2 de los ParquetEl 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 / compute2dataURL HTTPS del catálogo REST de Lakekeeper (scopeado a tabla/warehouse) + creds temporalesEl 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:

PiezaRutaPor qué importa
Registro de executors (87 servicios)lib/executors/registry.ts + lib/executors/services/*.executor.tsEl patrón para añadir "un conector externo más". EDC sería el nº 88.
Data Gateway / Integracionescomponents/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.tsAquí aterrizan los datos consumidos vía EDC: ledger de txn + commit de snapshot en R2.
Almacenamiento físicoR2 (S3-compatible) — S3_ENDPOINT=https://<acct>.r2.cloudflarestorage.comEl mismo bucket que el data plane S3 de EDC puede leer/escribir.
Catálogo IcebergLakekeeper (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.
Credencialesapp/api/credentials/ + tabla credentials (JSONB cifrado + RLS)Dónde guardaríamos la config del/los conector(es) EDC por workspace.
Workerslib/workers/* (BullMQ) + scripts/start-workers.tsDónde vive un edc-sync-worker (polling de estados de negociación/transferencia).
Shell del workspace + pestañascomponents/workspace/WorkspaceShell.tsx + components/workspace/tabs/*Dónde se registra una pestaña "Dataspaces".
Auth / permisoslib/graphs/auth.ts (requireWorkspace, requirePermission), lib/db/supabase-rls.tsEl control de acceso interno de Carbon (distinto del de dataspace, ver §8).

5. Encaje EDC ↔ Carbon (análisis de fit)

Necesidad de EDCQué ya tiene CarbonVeredicto
Data plane que lea/escriba datosR2 (S3-compatible) con Iceberg encimaEncaje directo. El data plane S3 de EDC apunta al mismo R2 con endpointOverride.
Orquestar un runtime externo por HTTPYa orquesta ml-runner, jupyterhub, kuzu-service en docker-compose✅ Patrón maduro; EDC es "un runner más".
Añadir un conector/servicio nuevoRegistro de 87 executors + Data Gateway + credenciales✅ Plumbing existente.
Aterrizar datos consumidos en el lakehousewithNativeControlPlane() + fan-out → snapshot Iceberg✅ Reutilizable tal cual.
Exponer datasets como assets ofertablesRegistro 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 IcebergLakekeeper + 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/GradleStack 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):

ComponenteRutaAnálogo existente
Servicio conector EDCservices/edc-service/ (Dockerfile Java + build.gradle.kts launcher)services/ml-runner/
Cliente Node de Management APIlib/dataspaces/edc-client.tslib/lakehouse/fanout-client.ts
Executorlib/executors/services/edc.executor.ts (+ alta en registry.ts)cualquier *.executor.ts
Rutas APIapp/api/dataspaces/*app/api/integrations/*
Worker de sincronizaciónlib/workers/dataspaces/edc-sync-worker.tslib/workers/cdc/cdc-manager.ts
Pestaña de workspacecomponents/workspace/tabs/dataspaces/DataspacesTab.tsxIntegrationsTab.tsx
Config / credencialestabla 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:

CapaTecnologíaPregunta que respondeFrontera
App / usuarioClerk (JWT) + Supabase RLS¿Qué puede hacer este usuario en este workspace? (requirePermission('admin') para publicar un asset)Dentro de Carbon
Catálogo / datoLakekeeper + OpenFGA (RBAC/ReBAC/ABAC hasta tabla/vista)¿Puede este participante leer esta tabla Iceberg?Acceso a datos
Dataspace / inter-orgEDC: 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):

  1. ¿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.
  2. Para el PoC: IAM simple (in-memory / OAuth); IdentityHub entra en Fase 6.

9. Riesgos y decisiones abiertas

TemaRiesgo / decisión
EDC es un objetivo en movimientoVersiones 0.x, Management API migrando v3→v4, Data Plane Signaling reemplazó controladores antiguos. Fijar una versión y seguir releases.
Nuevo lenguaje en el stackJava/Gradle. Mitigación: usar un launcher oficial + solo extensiones mínimas; tratar EDC como caja negra tras su REST API.
Identidad descentralizadaCurva 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↔assetUn 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 infraCada conector suma Control+Data Plane + Postgres + Vault. Relevante si es por tenant.
Governance / policiesTraducir reglas de negocio a ODRL correctamente (soberanía del dato = el diferenciador de todo esto).
Reconciliar 3 capas de authzClerk/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 customEl 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 + rutas app/api/dataspaces/*. Consumir el catálogo EDC desde Carbon.
  • Fase 4 — Consumir → lakehouse. edc-sync-worker que, tras una transferencia, aterriza el dato como snapshot Iceberg vía withNativeControlPlane().
  • 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

Técnico / implementación


Documento vivo. Siguiente paso sugerido: Fase 1 — levantar el sample oficial de EDC y recorrer un ciclo de transferencia end-to-end.