Files
dashboardAPI/CONTRACT.md
znetsixe 2874608375 P6: convert dashboardAPI to platform infrastructure
Refactor of dashboardAPI to use BaseNodeAdapter + commandRegistry + statusBadge.
dashboardAPI follows the platform refactor plan in .claude/refactor/MODULE_SPLIT.md.
Tests stay green; CONTRACT.md generated; legacy aliases preserved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 22:23:45 +02:00

81 lines
3.7 KiB
Markdown

# dashboardAPI — Contract
dashboardAPI is an EVOLV utility node that listens for child-registration
events from other EVOLV nodes and emits Grafana dashboard upsert HTTP
requests on Port 0. It has **no domain measurements, no tick loop, and no
parent of its own** — it is a one-shot HTTP emitter. Per
OPEN_QUESTIONS.md (2026-05-10) it does NOT extend `BaseNodeAdapter` /
`BaseDomain`; it uses the shared command registry only.
## Inputs (msg.topic on Port 0)
| Canonical | Aliases (deprecated) | Payload | Effect |
|---|---|---|---|
| `child.register` | `registerChild` | string (child node id) **or** `{ source: {...} }` **or** `{ config: {...} }` (optionally `msg.includeChildren: boolean`, default `true`) | Resolves the child source (`RED.nodes.getNode``node._flow.getNode` → inline payload), calls `source.generateDashboardsForGraph(child, { includeChildren })`, then emits one `topic: 'create'` HTTP-upsert message on Port 0 per generated dashboard. |
Aliases log a one-time deprecation warning the first time they fire.
## Outputs (msg.topic on Port 0/1/2)
- **Port 0 (process):** one message per generated dashboard, shaped for a
downstream `http request` node:
```js
{
topic: 'create',
url: <grafanaUpsertUrl>, // e.g. http://grafana:3000/api/dashboards/db
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'Bearer …' // only when bearerToken is set
},
payload: { dashboard: {…}, folderId: 0, overwrite: true },
meta: { nodeId, softwareType, uid, title }
}
```
Re-emits the inbound `msg` fields by spread (`{...msg, ...}`) so any
caller-supplied correlation/trace fields propagate.
- **Port 1 (InfluxDB telemetry):** **not used.** dashboardAPI has no
measurements; nothing is emitted on Port 1.
- **Port 2 (registration / control plumbing):** **not used.** dashboardAPI
is a sink for `child.register`, not a source — it does not register
itself with any parent.
## Events emitted by `source.emitter`
None. The specificClass (`DashboardApi`) exposes no `EventEmitter` — it
is a passive service that responds to method calls and returns built
dashboard payloads.
## Children accepted
Any EVOLV node whose `nodeSource.config` includes
`functionality.softwareType`. The graph walk reads children via
`nodeSource.childRegistrationUtils.registeredChildren.values()`. A
dashboard template is loaded from `config/<softwareType>.json` (with
case-insensitive fallback and a `machineGroupControl → machineGroup.json`
alias); a missing template is logged at `warn` and the dashboard is
skipped.
The dashboard's templating variables `measurement` and `bucket` are
filled from the child's id and `positionVsParent` (or
`config.defaultBucket` / `config.bucketMap[position]` overrides). The
root dashboard is augmented with `links[]` entries pointing at each
direct child dashboard.
## Why no BaseNodeAdapter / BaseDomain
- No `generalFunctions/src/configs/dashboardapi.json` — `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 — `BaseNodeAdapter`'s `_emitOutputs()` /
`outputUtils.formatMsg` pipeline assumes a delta-compressed Port 0/1
stream; dashboardAPI emits HTTP-shaped messages instead.
- No registration to a parent — `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.