141 lines
6.0 KiB
Markdown
141 lines
6.0 KiB
Markdown
# 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 or a bounded,
|
|
cursor-paged history window 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/data-plane/v1/data-products/:dataProductId/history`
|
|
- `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 the bounded
|
|
`nodedc.data-product.snapshot/v1` contract. Its snapshot `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.
|
|
|
|
History mode uses `nodedc.data-product.history/v1` and requires a closed
|
|
`from`/`to` interval. It supports provider-neutral `sourceIds`, a resolution
|
|
that is a multiple of the Data Product native sampling interval, a limit up to
|
|
5000 points and an opaque keyset continuation cursor. The response stays as one
|
|
envelope item so L2 logic can preserve `query` and `nextCursor` while iterating.
|
|
The workflow never selects a database, provider, tenant or connection.
|
|
|
|
## 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.
|