feat(engine): add private NDC nodes and ontology bridge
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
# n8n-nodes-ndc
|
||||
|
||||
Private NODE.DC node package for provider-neutral L2 workflows. It extends n8n
|
||||
through the supported private-node mechanism and does not patch Engine or n8n
|
||||
core.
|
||||
|
||||
Every custom node has an `NDC ` display-name prefix. Runtime types are package
|
||||
qualified:
|
||||
|
||||
- `n8n-nodes-ndc.ndcDataProductPublish` — publishes canonical facts into an
|
||||
approved Data Product.
|
||||
- `n8n-nodes-ndc.ndcDataProductRead` — reads the current snapshot of an
|
||||
approved Data Product.
|
||||
- `n8n-nodes-ndc.ndcFoundryBinding` — creates or updates a declarative Foundry
|
||||
page-slot binding. This is a control-plane operation, not a runtime data
|
||||
transport.
|
||||
|
||||
## Security and scope
|
||||
|
||||
Workflow parameters contain no service URL, provider, tenant, connection, raw
|
||||
secret, or credential selector. Product selection is loaded from the catalog
|
||||
visible to the selected opaque capability. Service locations are operator-owned
|
||||
runtime overrides (the package defaults to the canonical internal service
|
||||
names, so the first deployment needs no extra Engine environment):
|
||||
|
||||
- `NDC_DATA_PLANE_BASE_URL`
|
||||
- `NDC_FOUNDRY_BASE_URL`
|
||||
|
||||
The defaults are `http://external-data-plane:18106` and
|
||||
`http://nodedc-module-foundry:3333`. They are provider-neutral Platform service
|
||||
addresses, not workflow configuration.
|
||||
|
||||
The three credential types contain only one password-protected opaque
|
||||
capability. Writer, reader, and Foundry capabilities are intentionally distinct.
|
||||
Provider identity, product version, ontology revision, persistence policy, and
|
||||
tenant scope are materialized by the receiving service from the grant. The node
|
||||
never accepts them from a workflow.
|
||||
|
||||
## Fixed routes
|
||||
|
||||
- `GET /internal/data-plane/v1/writer/data-products`
|
||||
- `GET /internal/data-plane/v1/reader/data-products`
|
||||
- `POST /internal/data-plane/v1/data-products/:dataProductId/publish`
|
||||
- `GET /internal/data-plane/v1/data-products/:dataProductId/snapshot`
|
||||
- `GET /internal/foundry/v1/data-products`
|
||||
- `POST /internal/foundry/v1/data-product-bindings`
|
||||
|
||||
There is no fallback to a legacy intake route. `NDC Foundry Binding` uses the
|
||||
dedicated internal control-plane endpoint implemented by Foundry and fails
|
||||
closed when that route or its scoped workload grant is unavailable. Its
|
||||
canonical Map entity-stream slot defaults to `points`.
|
||||
|
||||
The binding command uses the versioned
|
||||
`nodedc.foundry.binding-upsert/v1` schema. Its opaque `ndc_fndbg_*` workload
|
||||
grant is separate from the short-lived Foundry MCP capability used by AI
|
||||
Workspace and from the shared Platform service token. The receiving service
|
||||
materializes actor, owner and exact application/page/binding/product scope from
|
||||
that grant; none of those authorization claims are accepted from headers or
|
||||
workflow data.
|
||||
|
||||
`NDC Data Product Read` supports only the bounded
|
||||
`nodedc.data-product.snapshot/v1` contract. Its `Page Size` parameter is a
|
||||
safety ceiling, not pagination: the complete scoped current projection must fit
|
||||
within 5000 entity keys. A larger product returns
|
||||
`data_product_snapshot_limit_exceeded`; the node must not assemble independent
|
||||
pages or start a patch stream from an incomplete snapshot. Large products need
|
||||
stable partition Data Products or a separately versioned query contract with a
|
||||
single snapshot barrier.
|
||||
|
||||
## Publish input
|
||||
|
||||
Each incoming item must be either a canonical fact or `{ "fact": <fact> }`:
|
||||
|
||||
```json
|
||||
{
|
||||
"sourceId": "fleet.unit.42",
|
||||
"semanticType": "map.moving_object",
|
||||
"observedAt": "2026-07-15T12:00:00.000Z",
|
||||
"attributes": {},
|
||||
"geometry": { "type": "Point", "coordinates": [37.61, 55.75] }
|
||||
}
|
||||
```
|
||||
|
||||
The node emits `nodedc.data-product.publish/v1`, enforces the 5000-fact and
|
||||
64-KiB-per-attributes limits, rejects secret-like material in attributes, and
|
||||
derives stable run/idempotency identifiers from workflow execution context.
|
||||
|
||||
## Build and verification
|
||||
|
||||
```sh
|
||||
npm install
|
||||
npm test
|
||||
npm run lint
|
||||
```
|
||||
|
||||
The package must be installed as an n8n private community package under the
|
||||
runtime user's community-package root:
|
||||
|
||||
```text
|
||||
/home/node/.n8n/nodes/node_modules/n8n-nodes-ndc
|
||||
```
|
||||
|
||||
The parent `/home/node/.n8n/nodes/package.json` owns the pinned package
|
||||
registration. `~/.n8n/custom` and `N8N_CUSTOM_EXTENSIONS` are deliberately not
|
||||
used: n8n loads those through the `CUSTOM` namespace, which would destroy the
|
||||
required `n8n-nodes-ndc.*` runtime types.
|
||||
|
||||
## Deployment boundary
|
||||
|
||||
The Platform MCP catalog bridge preserves package-qualified custom runtime
|
||||
types, but Engine can expose these schemas only after this private package is
|
||||
installed through the community-package path and the bridge slice is deployed.
|
||||
Production installation uses a verified offline tarball, an immutable
|
||||
root-owned release, an atomic current/previous switch and a read-only mount; it
|
||||
does not run `npm install` inside a live container. This package deliberately
|
||||
does not patch Engine or n8n core.
|
||||
|
||||
The Platform-side release builder is:
|
||||
|
||||
```sh
|
||||
node ../../infra/deploy-runner/build-n8n-private-extension-artifact.mjs \
|
||||
n8n-nodes-ndc-release-YYYYMMDD-NNN
|
||||
```
|
||||
|
||||
Its canonical deploy component only stages and seals a digest-bound release
|
||||
under `/volume1/docker/nodedc-platform/n8n-private-extensions`; it does not
|
||||
activate anything in Engine. Activation is intentionally blocked until an
|
||||
Engine-owned deployment slice provides the exact read-only community-package
|
||||
mount, atomic release selection, all-process restart and MCP schema acceptance.
|
||||
The v2 rollback contract accepts a pre-activation, explicitly verified inactive
|
||||
baseline for the first activation; subsequent upgrades prefer a previous
|
||||
verified immutable release. The staged v1 `0.1.0` release is never overwritten:
|
||||
this contract is published as a separate `0.1.1` release.
|
||||
Reference in New Issue
Block a user