docs: propagate folder-naming convention + bump submodules for editor refresh
Convention: * CLAUDE.md (root): new "Folder & File Layout (READ BEFORE CREATING NEW FILES)" section with required-name table and explicit legacy-drift list (mgc, vgc, dashboardapi). * .claude/rules/node-architecture.md: file-naming convention + src/editor/ module layout sections; serving recipe for /<nodeName>/editor/:file. Submodule bumps: * generalFunctions: shared output-format picker, redesigned position SVGs, tighter asset wizard, restored curve preview size. * rotatingMachine: pump banner, circular state diagram, mode icon cards, picker integration, CLAUDE.md update. * 10 others: per-node CLAUDE.md "Folder & File Layout" sections — 3 of them (machineGroupControl, valveGroupControl, dashboardAPI) carry inline warnings about their entry-filename drift. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -23,9 +23,63 @@ Every node follows entry → nodeClass → specificClass:
|
|||||||
- Port 1: InfluxDB telemetry payload
|
- Port 1: InfluxDB telemetry payload
|
||||||
- Port 2: Registration/control plumbing (parent-child handshakes)
|
- Port 2: Registration/control plumbing (parent-child handshakes)
|
||||||
|
|
||||||
|
## File-Naming Convention
|
||||||
|
The folder name is the canonical node name and every per-node file MUST match it
|
||||||
|
exactly (case-sensitive). No abbreviations.
|
||||||
|
|
||||||
|
| Path | Required name |
|
||||||
|
|---|---|
|
||||||
|
| Folder | `nodes/<nodeName>/` |
|
||||||
|
| Entry file | `nodes/<nodeName>/<nodeName>.js` |
|
||||||
|
| Editor HTML | `nodes/<nodeName>/<nodeName>.html` |
|
||||||
|
| nodeClass | `nodes/<nodeName>/src/nodeClass.js` |
|
||||||
|
| specificClass | `nodes/<nodeName>/src/specificClass.js` |
|
||||||
|
| Editor JS modules | `nodes/<nodeName>/src/editor/*.js` |
|
||||||
|
|
||||||
|
`machineGroupControl/mgc.js`, `valveGroupControl/vgc.js`, and
|
||||||
|
`dashboardAPI/dashboardapi.js` are legacy drift. New nodes MUST use the full
|
||||||
|
folder name; legacy nodes get renamed when next touched (rename = update entry
|
||||||
|
file, HTML file, `package.json#node-red.nodes`, and any test imports in one
|
||||||
|
commit).
|
||||||
|
|
||||||
|
## Editor JS Layout — `src/editor/`
|
||||||
|
Editor-side JavaScript that exceeds a couple of dozen lines lives in modular
|
||||||
|
files under `nodes/<nodeName>/src/editor/`, served by the entry file via:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const path = require('path');
|
||||||
|
RED.httpAdmin.get(`/${nameOfNode}/editor/:file`, (req, res) => {
|
||||||
|
const safe = String(req.params.file || '').replace(/[^a-zA-Z0-9._-]/g, '');
|
||||||
|
if (!safe.endsWith('.js')) return res.status(400).send('// invalid');
|
||||||
|
res.type('application/javascript');
|
||||||
|
res.sendFile(path.join(__dirname, 'src', 'editor', safe), (err) => {
|
||||||
|
if (err && !res.headersSent) res.status(404).send('// editor module not found');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
The HTML file then loads them as plain `<script src="/<nodeName>/editor/<file>.js">`
|
||||||
|
tags. Conventional modules:
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `index.js` | Namespace setup (`window.EVOLV.nodes.<nodeName>.editor = …`), shared helpers |
|
||||||
|
| `oneditprepare.js` | Implementation called from the `.html`'s `oneditprepare` hook |
|
||||||
|
| `oneditsave.js` | Implementation called from the `.html`'s `oneditsave` hook |
|
||||||
|
| Feature modules | One per visual concern, e.g. `basin-diagram.js`, `mode-cards.js`, `timing-donut.js`, `hover-couple.js` |
|
||||||
|
|
||||||
|
The `.html` shrinks to: register defaults, declare HTML template, delegate
|
||||||
|
`oneditprepare`/`oneditsave` to the modules. Inline JS in the `.html` is fine
|
||||||
|
for **trivial** nodes (≤ ~50 lines of editor JS); past that, extract.
|
||||||
|
|
||||||
|
Reference implementations: `pumpingStation/src/editor/` and
|
||||||
|
`machineGroupControl/src/editor/`. `rotatingMachine` is currently inline and
|
||||||
|
should be migrated when the editor JS next grows.
|
||||||
|
|
||||||
## Admin Endpoints
|
## Admin Endpoints
|
||||||
- `GET /<nodeName>/menu.js` — Dynamic menu configuration for editor
|
- `GET /<nodeName>/menu.js` — Dynamic menu configuration for editor
|
||||||
- `GET /<nodeName>/configData.js` — Runtime configuration for editor
|
- `GET /<nodeName>/configData.js` — Runtime configuration for editor
|
||||||
|
- `GET /<nodeName>/editor/:file` — (when present) editor JS modules from `src/editor/`
|
||||||
|
|
||||||
## Submodule Awareness
|
## Submodule Awareness
|
||||||
Most `nodes/*` directories are git submodules. Keep edits scoped to the target node's directory.
|
Most `nodes/*` directories are git submodules. Keep edits scoped to the target node's directory.
|
||||||
|
|||||||
29
CLAUDE.md
29
CLAUDE.md
@@ -9,10 +9,35 @@ Node-RED custom nodes package for wastewater treatment plant automation. Develop
|
|||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
Each node follows a three-layer pattern:
|
Each node follows a three-layer pattern:
|
||||||
1. **Node-RED wrapper** (`<name>.js`) - registers the node type, sets up HTTP endpoints
|
1. **Node-RED wrapper** (`<nodeName>.js`) - registers the node type, sets up HTTP endpoints
|
||||||
2. **Node adapter** (`src/nodeClass.js`) - bridges Node-RED API with domain logic, handles config loading, tick loops, events
|
2. **Node adapter** (`src/nodeClass.js`) - bridges Node-RED API with domain logic, handles config loading, tick loops, events
|
||||||
3. **Domain logic** (`src/specificClass.js`) - pure business logic, no Node-RED dependencies
|
3. **Domain logic** (`src/specificClass.js`) - pure business logic, no Node-RED dependencies
|
||||||
|
|
||||||
|
## Folder & File Layout (READ BEFORE CREATING NEW FILES)
|
||||||
|
Every per-node file MUST use the folder name **exactly** (case-sensitive). No
|
||||||
|
abbreviations. Quick reference:
|
||||||
|
|
||||||
|
| Path | Required name |
|
||||||
|
|---|---|
|
||||||
|
| Entry file | `nodes/<nodeName>/<nodeName>.js` |
|
||||||
|
| Editor HTML | `nodes/<nodeName>/<nodeName>.html` |
|
||||||
|
| Node adapter | `nodes/<nodeName>/src/nodeClass.js` |
|
||||||
|
| Domain logic | `nodes/<nodeName>/src/specificClass.js` |
|
||||||
|
| Editor JS modules | `nodes/<nodeName>/src/editor/*.js` (extract when inline editor JS exceeds ~50 lines) |
|
||||||
|
| Tests | `nodes/<nodeName>/test/{basic,integration,edge}/*.test.js` |
|
||||||
|
| Example flows | `nodes/<nodeName>/examples/*.flow.json` |
|
||||||
|
|
||||||
|
Full rule + serving recipe for `src/editor/`: `.claude/rules/node-architecture.md`.
|
||||||
|
|
||||||
|
**Legacy drift to rename when the file is next touched** (do not introduce new
|
||||||
|
mismatches in the meantime):
|
||||||
|
|
||||||
|
| Node | Currently | Should be |
|
||||||
|
|---|---|---|
|
||||||
|
| `machineGroupControl` | `mgc.{js,html}` | `machineGroupControl.{js,html}` |
|
||||||
|
| `valveGroupControl` | `vgc.{js,html}` | `valveGroupControl.{js,html}` |
|
||||||
|
| `dashboardAPI` | `dashboardapi.{js,html}` | `dashboardAPI.{js,html}` |
|
||||||
|
|
||||||
## Key Shared Library: `nodes/generalFunctions/`
|
## Key Shared Library: `nodes/generalFunctions/`
|
||||||
- `logger` - structured logging (use this, NOT console.log)
|
- `logger` - structured logging (use this, NOT console.log)
|
||||||
- `MeasurementContainer` - chainable measurement storage (type/variant/position)
|
- `MeasurementContainer` - chainable measurement storage (type/variant/position)
|
||||||
@@ -27,7 +52,7 @@ Each node follows a three-layer pattern:
|
|||||||
- S88 color scheme: Area=#0f52a5, ProcessCell=#0c99d9, Unit=#50a8d9, Equipment=#86bbdd, ControlModule=#a9daee
|
- S88 color scheme: Area=#0f52a5, ProcessCell=#0c99d9, Unit=#50a8d9, Equipment=#86bbdd, ControlModule=#a9daee
|
||||||
- Config JSON files in `generalFunctions/src/configs/` define defaults, types, enums per node
|
- Config JSON files in `generalFunctions/src/configs/` define defaults, types, enums per node
|
||||||
- Tick loop runs at 1000ms intervals for time-based updates
|
- Tick loop runs at 1000ms intervals for time-based updates
|
||||||
- Output ports + 3-tier architecture: see `.claude/rules/node-architecture.md`
|
- Output ports + 3-tier architecture + file-naming + `src/editor/` layout: see `.claude/rules/node-architecture.md`
|
||||||
- **Multi-tab demo flows**: see `.claude/rules/node-red-flow-layout.md` for the tab/link-channel/spacing rule set used by `examples/`
|
- **Multi-tab demo flows**: see `.claude/rules/node-red-flow-layout.md` for the tab/link-channel/spacing rule set used by `examples/`
|
||||||
- **Output coverage** (every output, every state, every layer): see `.claude/rules/output-coverage.md` — manifest + populated/degraded tests are mandatory for any change that touches Port 0/1/2 keys, function-node fan-outs, telemetry fields, or dashboard widget sources
|
- **Output coverage** (every output, every state, every layer): see `.claude/rules/output-coverage.md` — manifest + populated/degraded tests are mandatory for any change that touches Port 0/1/2 keys, function-node fan-outs, telemetry fields, or dashboard widget sources
|
||||||
|
|
||||||
|
|||||||
Submodule nodes/dashboardAPI updated: f0a7904985...a6f09d821d
Submodule nodes/diffuser updated: 37a85690d1...4973a8bcfc
Submodule nodes/generalFunctions updated: 49c77f262f...ab481357d2
Submodule nodes/machineGroupControl updated: 6833e9f3a8...998e9bd758
Submodule nodes/measurement updated: ffc03584ed...b884c0f085
Submodule nodes/monster updated: 59ff4d230e...cd185dcd82
Submodule nodes/pumpingStation updated: 2c7fe1792f...03440e1e6c
Submodule nodes/reactor updated: d735f9485c...0e34403c5d
Submodule nodes/rotatingMachine updated: 5ea0b0bda6...426c1a606b
Submodule nodes/settler updated: 98052a16e7...a3583a3edb
Submodule nodes/valve updated: 68ebe4ebce...8c2b2c0f9c
Submodule nodes/valveGroupControl updated: 618ad27e03...b20a57360d
Reference in New Issue
Block a user