Files
dashboardAPI/wiki/Home.md

150 lines
8.3 KiB
Markdown
Raw Permalink Normal View History

# dashboardAPI
![code-ref](https://img.shields.io/badge/code--ref-a6f09d8-blue) ![s88](https://img.shields.io/badge/S88-Utility-dddddd) ![status](https://img.shields.io/badge/status-pending--review-yellow)
A `dashboardAPI` node converts EVOLV node topology into Grafana dashboards. On each inbound `child.register` event it resolves the child source, walks its direct children, loads per-`softwareType` Grafana JSON templates from `config/`, and emits one HTTP upsert request per dashboard on Port 0 to a downstream `http request` node. Sits adjacent to the S88 hierarchy as a passive HTTP emitter — **no measurements, no tick loop, no parent registration**.
> [!NOTE]
> Pending full node review (2026-05). Content reflects `CONTRACT.md` and current source only.
---
## At a glance
| Thing | Value |
|:---|:---|
| What it represents | Utility bridge between EVOLV topology and Grafana — auto-generates dashboards from `child.register` events |
| S88 level | **Utility** — not in the S88 hierarchy; sits adjacent to it |
| Use it when | You want Grafana dashboards to materialise automatically when an EVOLV node graph is deployed |
| Don't use it for | Maintaining hand-curated Grafana dashboards (will overwrite); arbitrary Grafana API calls; tick / measurement data plumbing |
| Children it accepts | Any EVOLV node whose `nodeSource.config` carries `functionality.softwareType` |
| Parents it talks to | None — dashboardAPI is a passive sink; it does not register with a parent |
---
## How it fits
```mermaid
flowchart LR
ps[pumpingStation<br/>Process Cell]:::pc -.child.register.-> dash
mgc[machineGroupControl<br/>Unit]:::unit -.child.register.-> dash
rm[rotatingMachine<br/>Equipment]:::equip -.child.register.-> dash
meas[measurement<br/>Control Module]:::ctrl -.child.register.-> dash
dash[dashboardAPI<br/>Utility]:::neutral -->|"POST /api/dashboards/db"| http[http request<br/>node-red core]:::neutral
http --> grafana[(Grafana<br/>HTTP API)]
grafana -.renders dashboards for.-> ff[FlowFuse / Browser]
classDef pc fill:#0c99d9,color:#fff
classDef unit fill:#50a8d9,color:#000
classDef equip fill:#86bbdd,color:#000
classDef ctrl fill:#a9daee,color:#000
classDef neutral fill:#dddddd,color:#000
```
Dashed arrows = inbound `child.register` events from any EVOLV process node. The solid arrow is the outbound HTTP upsert envelope on Port 0 &mdash; emitted **once per generated dashboard** in the walked graph. S88 colours and the utility-neutral `#dddddd` are anchored in `.claude/rules/node-red-flow-layout.md`.
---
## Try it &mdash; 3-minute demo
Import the basic example flow, deploy, and watch a `child.register` payload turn into a Grafana dashboard upsert request.
```bash
curl -X POST -H 'Content-Type: application/json' \
--data @nodes/dashboardAPI/examples/basic.flow.json \
http://localhost:1880/flow
```
What to click after deploy:
1. Open the inject node (`basic trigger`) and edit the payload to a `{source: {config: {...}}}` shape &mdash; see [Reference &mdash; Examples](Reference-Examples#wiring-pattern) for the minimal inline-payload shape.
2. Fire the inject. Watch the debug pane: one `topic: 'create'` HTTP envelope appears per dashboard in the walked graph (root + direct children).
3. Wire a downstream `http request` node (method `POST`) to the dashboardAPI output to actually POST the envelope to Grafana.
> [!IMPORTANT]
> **GIF needed.** Demo recording of the inject &rarr; Port-0 envelope &rarr; Grafana dashboard upsert path. Save as `wiki/_partial-gifs/dashboardAPI/01-basic-demo.gif`, target &le; 1&nbsp;MB after `gifsicle -O3 --lossy=80`.
> [!WARNING]
> The shipped `basic.flow.json` / `integration.flow.json` / `edge.flow.json` are stubs &mdash; the inject payloads do not yet conform to the `child.register` resolver's expected shape. They will trigger `Missing or invalid child node` errors until updated. Tracked in [Limitations &mdash; Example flow stubs](Reference-Limitations#example-flow-stubs).
---
## The one thing you'll send
| Topic | Aliases | Payload | What it does |
|:---|:---|:---|:---|
| `child.register` | `registerChild` | `string` (child node id) **or** `{source: {...}}` **or** `{config: {...}}` (optionally `msg.includeChildren: boolean`, default `true`) | Resolves the child source (`RED.nodes.getNode` &rarr; `node._flow.getNode` &rarr; inline payload), calls `source.generateDashboardsForGraph(child, {includeChildren})`, then emits one `topic: 'create'` HTTP-upsert message on Port 0 per generated dashboard. |
That's it. There is no `set.*`, no `cmd.*`, no `query.*` &mdash; the registry has a single canonical topic (alias-with-deprecation). The legacy `registerChild` alias logs a one-time deprecation warning on first use.
---
## What you'll see come out
Sample Port 0 message after a `child.register` for a `pumpingStation` node with two direct children:
```json
{
"topic": "create",
"url": "http://grafana:3000/api/dashboards/db",
"method": "POST",
"headers": {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": "Bearer eyJ..."
},
"payload": {
"dashboard": { "uid": "a1b2c3d4e5f6", "title": "Pumping Station Demo", "templating": {...} },
"folderId": 0,
"overwrite": true
},
"meta": {
"nodeId": "ps_demo",
"softwareType": "pumpingStation",
"uid": "a1b2c3d4e5f6",
"title": "Pumping Station Demo"
}
}
```
| Field | Meaning |
|:---|:---|
| `topic` | Always `'create'` &mdash; signals a dashboard-upsert HTTP envelope. |
| `url` | `grafanaUpsertUrl()` = `<protocol>://<host>:<port>/api/dashboards/db`. |
| `method` | Always `POST`. |
| `headers.Authorization` | Present only when `bearerToken` is configured; omitted otherwise. |
| `payload.dashboard` | The composed Grafana dashboard JSON (template + templating vars filled in). |
| `payload.dashboard.uid` | `sha1(softwareType:nodeId).slice(0, 12)` &mdash; stable across re-deploys. |
| `meta.*` | Correlation fields for the downstream consumer (nodeId, softwareType, uid, title). |
Inbound `msg` fields propagate via spread (`{...msg, ...envelope}`) so any caller-supplied correlation / trace fields survive.
> Port 1 (InfluxDB telemetry) and Port 2 (registration / control plumbing) are **unused** &mdash; dashboardAPI has no measurements and does not register with a parent. See [Reference &mdash; Architecture](Reference-Architecture#output-ports).
---
## The new bit &mdash; no BaseNodeAdapter / BaseDomain
Most EVOLV nodes extend `BaseNodeAdapter` + `BaseDomain` from `generalFunctions/`. `dashboardAPI` does **not** &mdash; per `OPEN_QUESTIONS.md` (2026-05-10) the decision is to keep a bespoke adapter until `BaseNodeAdapter` grows passive / HTTP-only flags.
Reasons:
- No `generalFunctions/src/configs/dashboardapi.json` &mdash; `BaseDomain`'s constructor unconditionally calls `configManager.getConfig(ctor.name)` and would throw. The local `dependencies/dashboardapi/dashboardapiConfig.json` is for the editor menu endpoint, not the runtime config pipeline.
- No periodic output &mdash; `BaseNodeAdapter._emitOutputs()` / `outputUtils.formatMsg` assumes a delta-compressed Port 0 / 1 stream; dashboardAPI emits HTTP-shaped messages instead.
- No registration to a parent &mdash; `BaseNodeAdapter._scheduleRegistration` would emit a spurious `child.register` of its own.
- No status badge / tick / measurements / children of its own.
dashboardAPI uses the shared `commandRegistry` (canonical-topic naming + alias-with-deprecation) and stops there. See [Reference &mdash; Architecture](Reference-Architecture#why-no-basenodeadapter--basedomain) for the full rationale.
---
## Need more?
| Page | What you'll find |
|:---|:---|
| [Reference &mdash; Contracts](Reference-Contracts) | Full topic contract, config schema, child resolution rules, template alias table |
| [Reference &mdash; Architecture](Reference-Architecture) | Code map, HTTP-endpoint lifecycle, template loader, UID stability, graph walk |
| [Reference &mdash; Examples](Reference-Examples) | Shipped example flows + debug recipes |
| [Reference &mdash; Limitations](Reference-Limitations) | Legacy filename drift, stub flows, missing template handling, open questions |
[EVOLV master wiki](https://gitea.wbd-rd.nl/RnD/EVOLV/wiki/Home) &middot; [Topology Patterns](https://gitea.wbd-rd.nl/RnD/EVOLV/wiki/Topology-Patterns) &middot; [Topic Conventions](https://gitea.wbd-rd.nl/RnD/EVOLV/wiki/Topic-Conventions)