feat: architecture refactor — validators, positions, menuUtils, ESLint, tests, CI
Major improvements across the codebase:
- Extract validationUtils.js (548→217 lines) into strategy pattern validators
- Extract menuUtils.js (543→35 lines) into 6 focused menu modules
- Adopt POSITIONS constants across 23 files (183 replacements)
- Eliminate all 71 ESLint warnings (0 errors, 0 warnings)
- Add 158 unit tests for ConfigManager, MeasurementContainer, ValidationUtils
- Add architecture documentation with Mermaid diagrams
- Add CI pipeline (Docker, ESLint, Jest, Makefile)
- Add E2E infrastructure (docker-compose.e2e.yml)
Test results: 377 total (230 Jest + 23 node:test + 124 legacy), all passing
Lint: 0 errors, 0 warnings
Closes #2, #3, #9, #13, #14, #18
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:37:20 +01:00
# EVOLV - Claude Code Project Guide
2026-05-18 15:48:46 +02:00
> **READ FIRST, BEFORE ANY OTHER WORK:**
2026-05-19 09:30:49 +02:00
> [`CONTRACTS.md`](./CONTRACTS.md) — front-door map: where every contract, rule, and standard lives, and how to find them.
2026-05-06 17:23:47 +02:00
feat: architecture refactor — validators, positions, menuUtils, ESLint, tests, CI
Major improvements across the codebase:
- Extract validationUtils.js (548→217 lines) into strategy pattern validators
- Extract menuUtils.js (543→35 lines) into 6 focused menu modules
- Adopt POSITIONS constants across 23 files (183 replacements)
- Eliminate all 71 ESLint warnings (0 errors, 0 warnings)
- Add 158 unit tests for ConfigManager, MeasurementContainer, ValidationUtils
- Add architecture documentation with Mermaid diagrams
- Add CI pipeline (Docker, ESLint, Jest, Makefile)
- Add E2E infrastructure (docker-compose.e2e.yml)
Test results: 377 total (230 Jest + 23 node:test + 124 legacy), all passing
Lint: 0 errors, 0 warnings
Closes #2, #3, #9, #13, #14, #18
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:37:20 +01:00
## What This Is
Node-RED custom nodes package for wastewater treatment plant automation. Developed by Waterschap Brabantse Delta R&D team. Follows ISA-88 (S88) batch control standard.
## Architecture
Each node follows a three-layer pattern:
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>
2026-05-18 21:31:23 +02:00
1. **Node-RED wrapper ** (`<nodeName>.js` ) - registers the node type, sets up HTTP endpoints
feat: architecture refactor — validators, positions, menuUtils, ESLint, tests, CI
Major improvements across the codebase:
- Extract validationUtils.js (548→217 lines) into strategy pattern validators
- Extract menuUtils.js (543→35 lines) into 6 focused menu modules
- Adopt POSITIONS constants across 23 files (183 replacements)
- Eliminate all 71 ESLint warnings (0 errors, 0 warnings)
- Add 158 unit tests for ConfigManager, MeasurementContainer, ValidationUtils
- Add architecture documentation with Mermaid diagrams
- Add CI pipeline (Docker, ESLint, Jest, Makefile)
- Add E2E infrastructure (docker-compose.e2e.yml)
Test results: 377 total (230 Jest + 23 node:test + 124 legacy), all passing
Lint: 0 errors, 0 warnings
Closes #2, #3, #9, #13, #14, #18
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:37:20 +01:00
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
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>
2026-05-18 21:31:23 +02:00
## 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
2026-05-19 16:37:05 +02:00
mismatches in the meantime). When renaming, **keep the Node-RED type id
lowercase** (`registerType('mgc', …)` etc.) so deployed flows continue to load —
only the file paths change. `dashboardAPI` was migrated this way on 2026-05-19.
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>
2026-05-18 21:31:23 +02:00
| Node | Currently | Should be |
|---|---|---|
| `machineGroupControl` | `mgc.{js,html}` | `machineGroupControl.{js,html}` |
| `valveGroupControl` | `vgc.{js,html}` | `valveGroupControl.{js,html}` |
feat: architecture refactor — validators, positions, menuUtils, ESLint, tests, CI
Major improvements across the codebase:
- Extract validationUtils.js (548→217 lines) into strategy pattern validators
- Extract menuUtils.js (543→35 lines) into 6 focused menu modules
- Adopt POSITIONS constants across 23 files (183 replacements)
- Eliminate all 71 ESLint warnings (0 errors, 0 warnings)
- Add 158 unit tests for ConfigManager, MeasurementContainer, ValidationUtils
- Add architecture documentation with Mermaid diagrams
- Add CI pipeline (Docker, ESLint, Jest, Makefile)
- Add E2E infrastructure (docker-compose.e2e.yml)
Test results: 377 total (230 Jest + 23 node:test + 124 legacy), all passing
Lint: 0 errors, 0 warnings
Closes #2, #3, #9, #13, #14, #18
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:37:20 +01:00
## Key Shared Library: `nodes/generalFunctions/`
- `logger` - structured logging (use this, NOT console.log)
- `MeasurementContainer` - chainable measurement storage (type/variant/position)
- `configManager` - loads JSON configs from `src/configs/`
- `MenuManager` - dynamic UI dropdowns
- `outputUtils` - formats messages for InfluxDB and process outputs
- `childRegistrationUtils` - parent-child node relationships
- `coolprop` - thermodynamic property calculations
## Conventions
- Nodes register under category `'EVOLV'` in Node-RED
release: palette redesign + CoreSync scaffolding + dashboardAPI MODULE_NOT_FOUND fix
PALETTE REDESIGN (2026-05-21)
Sidebar swatches switched from S88 level (all blue) to domain-hue per node.
Family hue = function (rotating=orange, valves=teal, biology=green/olive,
sampling=violet, sensor=amber, aeration=sky-blue, infrastructure=slate);
within a family, darker = higher S88 / "more controller-ish."
Editor-group rectangles in flow.json still follow S88 — only the
registerType colour changed.
Submodule bumps for palette: rotatingMachine, machineGroupControl,
pumpingStation, valve, valveGroupControl, reactor, settler, monster,
measurement, diffuser, dashboardAPI.
Docs touched:
- CLAUDE.md: palette swatch vs. editor-group bullets split out.
- .claude/rules/node-red-flow-layout.md: new §10.0 introduces the two
color systems, full 12-row palette table, and explicit warning not to
mix the two hexes.
- .claude/refactor/MODULE_SPLIT.md: per-node headers annotated with
both `group #XXX` and `palette #XXX`.
- .claude/refactor/WIKI_HOME_TEMPLATE.md + WIKI_TEMPLATE.md: clarify
Mermaid classDefs visualize hierarchy, not palette swatches.
- .claude/refactor/OPEN_QUESTIONS.md: dated decision entry with
rationale, file list, and follow-ups.
CORESYNC SUBMODULE (new)
nodes/coresync added pointing at https://gitea.wbd-rd.nl/RnD/coresync.
FROST/SensorThings handoff path — first version forwards FROST-ready HTTP
request messages on the dbase output; a downstream http-request node
performs the POST and feeds responses back on msg.topic = "frost.response".
Lazy stream resolver, latest-wins queue (keep first + latest, drop middle),
knot-emit on slope change, provenance preserved in Observation parameters.
- .gitmodules: add nodes/coresync entry.
- package.json: register coresync as a Node-RED node.
- generalFunctions bump: new frostFormatter + 4 node config schemas
expose the dbase format option.
- measurement bump: "frost" option added to dbaseOutputFormat dropdown
(plus the in-flight data.measurement unit-handling work).
- machineGroupControl bump: small editor compact-fields tweak alongside
the palette change.
- CORESYNC_FROST_INTERVIEW_HANDOFF.md added at root with interview state
(Q20 open: slope angle vs. relative delta comparison).
DASHBOARDAPI MODULE_NOT_FOUND FIX
package.json: dashboardapi entry path corrected to
nodes/dashboardAPI/dashboardAPI.js. Commit e04c4a1 renamed the files to
camelCase but missed package.json; on case-sensitive filesystems
(Linux/Docker, where the tarball lands) the require resolved to nothing
and the node showed MODULE_NOT_FOUND in the Node-RED palette.
MISC CLEANUP
- examples/README.md + examples/pumpingstation-complete-example/ removal
(build_flow.py, flow.json, README.md superseded by per-node examples).
- jest.config.js: in-progress tweak.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 15:09:33 +02:00
- Two color systems (don't confuse):
- **Palette swatch** (Node-RED sidebar, set in `<node>.html` ) = domain-hue per node — full table in `.claude/rules/node-red-flow-layout.md` §10.0. Changed 2026-05-21; see `.claude/refactor/OPEN_QUESTIONS.md` .
- **Editor-group rectangle** (flow.json `style.fill` ) = S88 level (unchanged): Area=#0f52a5 , ProcessCell=#0c99d9 , Unit=#50a8d9 , Equipment=#86bbdd , ControlModule=#a9daee
feat: architecture refactor — validators, positions, menuUtils, ESLint, tests, CI
Major improvements across the codebase:
- Extract validationUtils.js (548→217 lines) into strategy pattern validators
- Extract menuUtils.js (543→35 lines) into 6 focused menu modules
- Adopt POSITIONS constants across 23 files (183 replacements)
- Eliminate all 71 ESLint warnings (0 errors, 0 warnings)
- Add 158 unit tests for ConfigManager, MeasurementContainer, ValidationUtils
- Add architecture documentation with Mermaid diagrams
- Add CI pipeline (Docker, ESLint, Jest, Makefile)
- Add E2E infrastructure (docker-compose.e2e.yml)
Test results: 377 total (230 Jest + 23 node:test + 124 legacy), all passing
Lint: 0 errors, 0 warnings
Closes #2, #3, #9, #13, #14, #18
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:37:20 +01:00
- Config JSON files in `generalFunctions/src/configs/` define defaults, types, enums per node
2026-05-19 09:30:49 +02:00
- Tick loop is **opt-in per node ** — default cadence 1000 ms, but each node sets `static tickInterval` (or skips it). See `.claude/refactor/OPEN_QUESTIONS.md` (2026-05-10 entry) for the design decision
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>
2026-05-18 21:31:23 +02:00
- Output ports + 3-tier architecture + file-naming + `src/editor/` layout: see `.claude/rules/node-architecture.md`
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
- **Multi-tab demo flows**: see `.claude/rules/node-red-flow-layout.md` for the tab/link-channel/spacing rule set used by `examples/`
2026-05-14 22:32:39 +02:00
- **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
feat: architecture refactor — validators, positions, menuUtils, ESLint, tests, CI
Major improvements across the codebase:
- Extract validationUtils.js (548→217 lines) into strategy pattern validators
- Extract menuUtils.js (543→35 lines) into 6 focused menu modules
- Adopt POSITIONS constants across 23 files (183 replacements)
- Eliminate all 71 ESLint warnings (0 errors, 0 warnings)
- Add 158 unit tests for ConfigManager, MeasurementContainer, ValidationUtils
- Add architecture documentation with Mermaid diagrams
- Add CI pipeline (Docker, ESLint, Jest, Makefile)
- Add E2E infrastructure (docker-compose.e2e.yml)
Test results: 377 total (230 Jest + 23 node:test + 124 legacy), all passing
Lint: 0 errors, 0 warnings
Closes #2, #3, #9, #13, #14, #18
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:37:20 +01:00
2026-05-19 09:30:49 +02:00
## Agents and Skills (use them — don't reinvent)
- **Skills** at `.claude/skills/evolv-*/SKILL.md` (15 domain skills) — auto-discovered, invoke via the `Skill` tool. Load them when you need domain reasoning (rotating equipment, biology, telemetry, security, instrumentation, hydraulics, alarms, OT integration, regulatory, quality, commissioning, frontend, …).
- **Subagents** at `.claude/agents/*.md` (10 Claude Code subagents) — spawnable via `Agent(subagent_type: '<name>')` . Use for independent work: `evolv-orchestrator` (multi-domain decomposition + `team` workflows), `mechanical-process-engineer` , `biological-process-engineer` , `instrumentation-measurement` , `node-red-runtime` , `telemetry-database` , `quality-test-engineer` , `commissioning-compliance` , `ot-security-integration` , `general-functions-library` .
- **Routing table**: [`.agents/AGENTS.md` ](./.agents/AGENTS.md ) maps task patterns → which skill/subagent to invoke.
- **`team` keyword**: when the user says "team", spawn `evolv-orchestrator` (subagent) — it picks specialists, runs an alignment pass, returns one integrated answer.
## Tooling (Docker-first, local now, central later)
Custom EVOLV tooling lives in `tools/` and is intended to run inside the local Docker compose stack (`tools/docker-compose.yml` ). **Always prefer these tools over ad-hoc grep/curl/manual checks ** — they encode the rules in `.claude/rules/` and catch regressions the human review would miss:
- `tools/flow-lint/` — validates `examples/*.flow.json` against `.claude/rules/node-red-flow-layout.md` . Run before committing any flow change.
- `tools/output-manifest-verify/` — diffs declared Port 0/1/2 keys vs. runtime emissions. Run on any output-shape change.
- `tools/contract-verify/` — diffs `nodes/<n>/CONTRACT.md` vs. `src/commands/index.js` . Run after touching a command registry.
- `tools/wiki-gen/` — regenerates topic-contract + data-model sections of `nodes/<n>/wiki/` . Run after a CONTRACT change.
- `tools/physics-sanity/` — cross-node mass/hydraulic/energy balance assertions. Run as part of `node --test` for cross-node changes.
- **MCP services** (Node-RED admin, InfluxDB, headless browser) live under `tools/mcp/` as Docker services. **Migration note ** : these will move to a central MCP server later; the local stack is interim. The Dockerfile + compose entry stays in this repo as the canonical definition.
- **Why use them**: every tool encodes a rule that we've previously discovered through a bug (η-null crash, ui-chart blank renders, output-key drift). Skipping them re-opens those bugs.
2026-05-18 15:48:46 +02:00
## Sources of truth (the canonical files)
- **Front-door map**: [`CONTRACTS.md` ](./CONTRACTS.md ) — read first; lists every standard and where it lives
- **Platform API shapes** (BaseDomain, BaseNodeAdapter, commands registry, UnitPolicy, …): `.claude/refactor/CONTRACTS.md`
- **Code conventions** (file/function size, comments, naming): `.claude/refactor/CONVENTIONS.md`
- **Per-node module layout**: `.claude/refactor/MODULE_SPLIT.md`
- **Per-node API contract**: `nodes/<n>/CONTRACT.md` + `nodes/<n>/src/commands/index.js` (source of truth for accepted `msg.topic` values)
- **Shared library API**: `nodes/generalFunctions/CONTRACT.md` (exported classes + utilities)
- **Live decisions log**: `.claude/refactor/OPEN_QUESTIONS.md` — append, don't invent
feat: architecture refactor — validators, positions, menuUtils, ESLint, tests, CI
Major improvements across the codebase:
- Extract validationUtils.js (548→217 lines) into strategy pattern validators
- Extract menuUtils.js (543→35 lines) into 6 focused menu modules
- Adopt POSITIONS constants across 23 files (183 replacements)
- Eliminate all 71 ESLint warnings (0 errors, 0 warnings)
- Add 158 unit tests for ConfigManager, MeasurementContainer, ValidationUtils
- Add architecture documentation with Mermaid diagrams
- Add CI pipeline (Docker, ESLint, Jest, Makefile)
- Add E2E infrastructure (docker-compose.e2e.yml)
Test results: 377 total (230 Jest + 23 node:test + 124 legacy), all passing
Lint: 0 errors, 0 warnings
Closes #2, #3, #9, #13, #14, #18
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:37:20 +01:00
## Development Notes
- No build step required - pure Node.js
- Install: `npm install` in root
- Submodule URLs were rewritten from `gitea.centraal.wbd-rd.nl` to `gitea.wbd-rd.nl` for external access
- Dependencies: mathjs, generalFunctions (git submodule)