name: nodedc-platform # This is intentionally an overlay, not a provider service. It is composed # with docker-compose.platform-http.yml by the canonical deploy runner. services: external-data-plane-postgres: image: ${EXTERNAL_DATA_PLANE_TIMESCALE_IMAGE:-timescale/timescaledb-ha:pg16.14-ts2.28.2-all} restart: unless-stopped env_file: - ${NODEDC_SYNOLOGY_ENV_FILE:-.env.synology} environment: POSTGRES_DB: ${EXTERNAL_DATA_PLANE_PG_DB:-nodedc_data_plane} POSTGRES_USER: ${EXTERNAL_DATA_PLANE_PG_USER:-nodedc_data_plane} POSTGRES_PASSWORD: ${EXTERNAL_DATA_PLANE_PG_PASS:?external data plane database password required} healthcheck: test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"] interval: 30s timeout: 5s retries: 5 start_period: 30s volumes: - external-data-plane-database:/home/postgres/pgdata/data networks: - external-data-plane external-data-plane: image: nodedc/external-data-plane:local restart: unless-stopped env_file: - ${NODEDC_SYNOLOGY_ENV_FILE:-.env.synology} environment: NODE_ENV: production PORT: 18106 EXTERNAL_DATA_PLANE_DATABASE_URL: postgresql://${EXTERNAL_DATA_PLANE_PG_USER:-nodedc_data_plane}:${EXTERNAL_DATA_PLANE_PG_PASS:?external data plane database password required}@external-data-plane-postgres:5432/${EXTERNAL_DATA_PLANE_PG_DB:-nodedc_data_plane} EXTERNAL_DATA_PLANE_DATABASE_POOL_SIZE: ${EXTERNAL_DATA_PLANE_DATABASE_POOL_SIZE:-10} EXTERNAL_DATA_PLANE_RAW_RETENTION_DAYS: ${EXTERNAL_DATA_PLANE_RAW_RETENTION_DAYS:-14} EXTERNAL_DATA_PLANE_MAX_BATCH_BYTES: ${EXTERNAL_DATA_PLANE_MAX_BATCH_BYTES:-5242880} EXTERNAL_DATA_PLANE_MAX_FACTS_PER_PUBLISH: ${EXTERNAL_DATA_PLANE_MAX_FACTS_PER_PUBLISH:-5000} EXTERNAL_DATA_PLANE_MAX_ATTRIBUTES_BYTES_PER_FACT: ${EXTERNAL_DATA_PLANE_MAX_ATTRIBUTES_BYTES_PER_FACT:-65536} EXTERNAL_DATA_PLANE_MAX_PATCH_OPERATIONS: ${EXTERNAL_DATA_PLANE_MAX_PATCH_OPERATIONS:-500} EXTERNAL_DATA_PLANE_MAX_PATCH_BYTES: ${EXTERNAL_DATA_PLANE_MAX_PATCH_BYTES:-262144} EXTERNAL_DATA_PLANE_PATCH_RETENTION_MS: ${EXTERNAL_DATA_PLANE_PATCH_RETENTION_MS:-3600000} EXTERNAL_DATA_PLANE_RECEIPT_RETENTION_MS: ${EXTERNAL_DATA_PLANE_RECEIPT_RETENTION_MS:-604800000} EXTERNAL_DATA_PLANE_RETENTION_DELETE_LIMIT: ${EXTERNAL_DATA_PLANE_RETENTION_DELETE_LIMIT:-10000} EXTERNAL_DATA_PLANE_STREAM_HEARTBEAT_MS: ${EXTERNAL_DATA_PLANE_STREAM_HEARTBEAT_MS:-20000} EXTERNAL_DATA_PLANE_STREAM_POLL_MS: ${EXTERNAL_DATA_PLANE_STREAM_POLL_MS:-1000} EXTERNAL_DATA_PLANE_MAX_READER_STREAMS: ${EXTERNAL_DATA_PLANE_MAX_READER_STREAMS:-10} EXTERNAL_DATA_PLANE_WRITER_BINDING_MAX_TTL_DAYS: ${EXTERNAL_DATA_PLANE_WRITER_BINDING_MAX_TTL_DAYS:-90} EXTERNAL_DATA_PLANE_MAX_FUTURE_SKEW_SECONDS: ${EXTERNAL_DATA_PLANE_MAX_FUTURE_SKEW_SECONDS:-300} EXTERNAL_DATA_PLANE_RETENTION_SWEEP_MS: ${EXTERNAL_DATA_PLANE_RETENTION_SWEEP_MS:-3600000} # Migration-only shared-token routes stay closed in a canonical install. EXTERNAL_DATA_PLANE_LEGACY_INTAKE_ENABLED: ${EXTERNAL_DATA_PLANE_LEGACY_INTAKE_ENABLED:-false} NODEDC_INTERNAL_ACCESS_TOKEN: ${NODEDC_INTERNAL_ACCESS_TOKEN:-} # Legacy manual one-time issuance uses this EDP-only bearer. Managed # Engine ensure/revoke never accepts it and uses the Ed25519 boundary # below. Neither credential is exposed to a graph, MCP client or provider. EXTERNAL_DATA_PLANE_PROVISIONER_TOKEN_FILE: /run/nodedc-secrets/external-data-plane-provisioner-token # Disabled until the atomic native NDC L2 ensure-grant control-plane # operation is present. This legacy API returns plaintext capabilities; # a root/UI transfer is emergency diagnostics only. EXTERNAL_DATA_PLANE_PROVISIONING_ENABLED: ${EXTERNAL_DATA_PLANE_PROVISIONING_ENABLED:-false} # Digest-only, idempotent writer-binding ensure path. Enable only after # Engine owns the matching private key and the public trust file exists. EXTERNAL_DATA_PLANE_MANAGED_PROVISIONING_ENABLED: ${EXTERNAL_DATA_PLANE_MANAGED_PROVISIONING_ENABLED:-false} EXTERNAL_DATA_PLANE_MANAGED_PROVISIONER_PUBLIC_KEY_FILE: /run/nodedc-trust/engine-managed-provisioner/public-key.pem EXTERNAL_DATA_PLANE_MANAGED_PROVISIONER_SERVICE_ID: ${EXTERNAL_DATA_PLANE_MANAGED_PROVISIONER_SERVICE_ID:-nodedc-engine} EXTERNAL_DATA_PLANE_MANAGED_PROVISIONER_KEY_ID: ${EXTERNAL_DATA_PLANE_MANAGED_PROVISIONER_KEY_ID:-engine-edp-managed-provisioner-v1} EXTERNAL_DATA_PLANE_MANAGED_PROVISIONER_AUDIENCE: ${EXTERNAL_DATA_PLANE_MANAGED_PROVISIONER_AUDIENCE:-nodedc-external-data-plane.managed-provisioning.v1} EXTERNAL_DATA_PLANE_MANAGED_PROVISIONER_MAX_SKEW_SECONDS: ${EXTERNAL_DATA_PLANE_MANAGED_PROVISIONER_MAX_SKEW_SECONDS:-60} EXTERNAL_DATA_PLANE_MANAGED_PROVISIONER_REPLAY_CACHE_MAX_ENTRIES: ${EXTERNAL_DATA_PLANE_MANAGED_PROVISIONER_REPLAY_CACHE_MAX_ENTRIES:-10000} # Foundry owns a separate managed-provisioner identity. It submits only # a consumer target digest and Data Product id; EDP resolves the active # writer scope internally and returns no provider identity. EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONING_ENABLED: ${EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONING_ENABLED:-true} EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONER_PUBLIC_KEY_FILE: /run/nodedc-trust/foundry-managed-provisioner/public-key.pem EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONER_SERVICE_ID: ${EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONER_SERVICE_ID:-nodedc-module-foundry} EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONER_KEY_ID: ${EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONER_KEY_ID:-foundry-edp-managed-provisioner-v1} EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONER_AUDIENCE: ${EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONER_AUDIENCE:-nodedc-external-data-plane.managed-provisioning.v1} EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONER_MAX_SKEW_SECONDS: ${EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONER_MAX_SKEW_SECONDS:-60} EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONER_REPLAY_CACHE_MAX_ENTRIES: ${EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONER_REPLAY_CACHE_MAX_ENTRIES:-10000} volumes: - type: bind source: /volume1/docker/nodedc-platform/secrets/external-data-plane-provisioner/token target: /run/nodedc-secrets/external-data-plane-provisioner-token read_only: true bind: create_host_path: false - type: bind source: /volume1/docker/nodedc-platform/trust/engine-managed-provisioner target: /run/nodedc-trust/engine-managed-provisioner read_only: true bind: create_host_path: false - type: bind source: /volume1/docker/nodedc-platform/trust/foundry-managed-provisioner target: /run/nodedc-trust/foundry-managed-provisioner read_only: true bind: create_host_path: false expose: - "18106" ports: - "${EXTERNAL_DATA_PLANE_HOST_BIND:-127.0.0.1:18106}:18106" depends_on: external-data-plane-postgres: condition: service_healthy healthcheck: test: - CMD - node - -e - "fetch('http://127.0.0.1:18106/healthz').then((response) => process.exit(response.ok ? 0 : 1)).catch(() => process.exit(1))" interval: 30s timeout: 5s retries: 3 start_period: 15s networks: - engine - external-data-plane networks: engine: external: true name: ${NODEDC_ENGINE_DOCKER_NETWORK:-nodedc-demo_default} external-data-plane: internal: true volumes: external-data-plane-database: