Files
EVOLV/CLAUDE.md
znetsixe 025bdb4c7e 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

7.2 KiB

EVOLV - Claude Code Project Guide

READ FIRST, BEFORE ANY OTHER WORK: CONTRACTS.md — front-door map: where every contract, rule, and standard lives, and how to find them.

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 (<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
  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). 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.

Node Currently Should be
machineGroupControl mgc.{js,html} machineGroupControl.{js,html}
valveGroupControl vgc.{js,html} valveGroupControl.{js,html}

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
  • 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
  • Config JSON files in generalFunctions/src/configs/ define defaults, types, enums per node
  • 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
  • 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/
  • 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

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 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.

Sources of truth (the canonical files)

  • Front-door map: 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

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)