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
## 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:
1. **Node-RED wrapper ** (`<name>.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
3. **Domain logic ** (`src/specificClass.js` ) - pure business logic, no Node-RED dependencies
## 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
- 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
- Tick loop runs at 1000ms intervals for time-based updates
- Three outputs per node: [process, dbase, parent]
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/`
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)