Skip to content
11 changes: 11 additions & 0 deletions .claude/review-guidelines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Review Guidelines

Order of concern: correctness, architecture, tests, style.

- Layer dependencies respect ports and adapters: frontend, backend, and middleware only communicate through the ports in `src/middleware/shared/ports/`. `npm run validate:arch` must pass.
- DTOs cross layer boundaries, never domain entities.
- 100%-coverage directories stay at 100%; new behavior comes with tests (Jest for logic, Playwright for user flows).
- TypeScript Best Practices in CLAUDE.md apply to every diff (no `any`, no `as`, no `!`, no floating promises, boundary validation over casting).
- Named exports over default exports.
- No emojis in code, comments, or docs.
- Docs updated when documented behavior changes (README, CLAUDE.md, docs/).
19 changes: 19 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"permissions": {
"allow": [
"Bash(npm run:*)",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python - <<'PY'
import json

with open("package.json", encoding="utf-8") as f:
    scripts = json.load(f).get("scripts", {})

print("\n".join(sorted(scripts)))
PY

Repository: Autonomy-Logic/openplc-editor

Length of output: 386


🏁 Script executed:

#!/bin/bash
sed -n '1,120p' .claude/settings.json
printf '\n--- package.json scripts ---\n'
python3 - <<'PY'
import json
with open("package.json", encoding="utf-8") as f:
    scripts = json.load(f).get("scripts", {})
for name in sorted(scripts):
    print(f"{name}: {scripts[name]}")
PY

Repository: Autonomy-Logic/openplc-editor

Length of output: 2697


Narrow Bash(npm run:*) to explicit scripts.
package.json includes mutating and external-effect scripts like build, package, postinstall, prepare, and rebuild, so this rule allows arbitrary repo scripts now and in the future. Allow only the specific validation commands the workflow needs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/settings.json at line 4, Update the Bash permission entry in the
settings configuration to replace the wildcard npm script pattern with explicit
allowlisted validation commands required by the workflow. Exclude mutating or
external-effect scripts such as build, package, postinstall, prepare, and
rebuild, and avoid permitting arbitrary current or future npm scripts.

"Bash(npm test:*)",
"Bash(npx tsx:*)",
"Bash(npx playwright test:*)",
"Bash(git status:*)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Bash(git show:*)",
"Bash(git branch:*)",
"Bash(gh pr view:*)",
"Bash(gh pr list:*)",
"Bash(gh issue view:*)",
"Bash(gh issue list:*)"
]
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
}
47 changes: 34 additions & 13 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ src/
├── main/ # Electron main process (Node.js)
├── frontend/ # React UI layer (renderer process)
│ ├── components/ # Atomic Design: _atoms, _molecules, _organisms, _features, _templates
│ ├── store/ # Zustand store (19 slices)
│ ├── store/ # Zustand store (18 slices)
│ ├── hooks/ # Custom React hooks
│ ├── services/ # Business logic and side effects
│ ├── utils/ # Domain utilities (PLC, graphical, debug, formatters)
│ ├── data/ # Static data (function libraries, block definitions)
│ ├── locales/ # i18next translations
│ └── assets/ # Images, icons
├── backend/
│ ├── editor/ # Main process modules (compiler, hardware, modbus, websocket, services)
│ ├── editor/ # Main process modules (compiler, hardware, modbus, ethercat, library-manager, services)
│ └── shared/ # Platform-agnostic utilities (XML generation, project parsing, simulator)
├── middleware/ # Ports & Adapters layer
│ ├── shared/
Expand Down Expand Up @@ -131,7 +131,7 @@ Main and renderer processes communicate through typed IPC bridges:

### State Management (Zustand)

Single store composed of 19 slices (`src/frontend/store/`), accessed via auto-generated selector hooks:
Single store composed of 18 slices (`src/frontend/store/`), accessed via auto-generated selector hooks:

```typescript
import { useOpenPLCStore } from '@root/frontend/store'
Expand Down Expand Up @@ -160,7 +160,7 @@ const createPou = useOpenPLCStore((s) => s.projectActions.createPou)
| `console` | Log output |
| `library` | System + user function block libraries |
| `file` | File save states (dirty tracking) |
| `ai`, `clipboard`, `history`, `modal`, `search`, `shared`, `version-control`, `webrtc` | Supporting features |
| `ai`, `history`, `modal`, `readme`, `search`, `shared`, `version-control`, `webrtc` | Supporting features |

**Conventions:**
- Actions are grouped under a `*Actions` namespace (e.g., `projectActions`, `deviceActions`)
Expand Down Expand Up @@ -205,14 +205,14 @@ Flow state is stored per-POU in dedicated slices (`ladder`, `fbd`). Flows must b
Orchestrated by `CompilerModule` (`src/backend/editor/compiler/compiler-module.ts`):

```
PLCProjectData -> Preprocess POUs -> XML Generation -> xml2st -> iec2c -> C code
|
defines.h (pins, Modbus, MD5)
|
Arduino CLI / openplc-compiler -> firmware
PLCProjectData -> Preprocess POUs -> XML Generation -> xml2st -> STruC++ compile() -> C++ code
|
defines.h (pins, Modbus, MD5)
|
Arduino CLI / openplc-compiler -> firmware
```

Platform-specific binaries in `/resources/bin/[platform]/[arch]/`. Board configs in `/resources/sources/boards/hals.json`.
Platform-specific binaries in `/resources/bin/[platform]/[arch]/`. Board configs in `src/backend/shared/firmware/hals.json`.

### Debugging

Expand Down Expand Up @@ -241,9 +241,22 @@ When adding new code to covered directories, you must add corresponding tests to
- ESLint flat config (`eslint.config.mjs`) with TypeScript strict type checking
- Prettier: 120 char width, no semicolons, single quotes, trailing commas
- Import sorting enforced via `simple-import-sort` plugin
- Pre-commit hooks via Husky run lint-staged on `./src/**/*`
- Pre-commit hooks via Husky run lint-staged on `./src/**/*.{ts,tsx}`
- Path alias: `@root/*` -> `./src/*`

### TypeScript Best Practices

- No type assertions: `as` hides real type errors — fix the type at the source or narrow with type guards. `as const` is fine; `as unknown as T` is forbidden.
- No non-null assertions (`!`): handle the undefined case or narrow explicitly.
- For truly unknown data use `unknown` and narrow before use — never `any`.
- No `@ts-ignore`/`@ts-expect-error` without a one-line justification.
- Validate external data at the boundary (IPC payloads, project files, downloaded binaries metadata) with schemas (zod) or type guards instead of casting.
- No floating promises: `await` or handle rejection explicitly — async errors must not disappear.
- Prefer `??` over `||` for defaults when `0`, `''`, or `false` are valid values.
- Model variant states as discriminated unions; make `switch` exhaustive with a `never` check.
- Named exports over default exports.
- Zustand state changes only through slice actions — never mutate store values from components.

## Key Technologies

- **Electron 35** / **React 18** / **TypeScript** (target ES2022)
Expand Down Expand Up @@ -311,7 +324,7 @@ on its `main` push. (Ideally `package.json.version` should be derived from

### IEC address allocation + alias registry

Located in `src/backend/shared/utils/iec-address/` (byte-identical on
Located in `src/middleware/shared/utils/iec-address/` (byte-identical on
openplc-web). Pure functions, no IPC, no electron coupling.

- **Address pool** (`address-pool.ts`): producer-only, target-scoped
Expand Down Expand Up @@ -353,7 +366,15 @@ new alias.

## Environment

- **Node.js:** >= 20.x < 24
- **Node.js:** >= 22.x < 24
- **Dev server port:** 1313
- **Supported platforms:** macOS, Windows, Linux (x64 & ARM64)
- **Binaries:** Auto-downloaded via `scripts/download-binaries.ts` during `npm install`

## Git Workflow

Follow the Workflow section in CONTRIBUTING.md (base branch, branch naming, Conventional Commits). `<type>` maps from the Jira issue type: Story → `feature`, Bug → `bugfix`, Task → `task`, Improvement → `improvement`.

## Issue Tracker

Jira, project key `DOPE`. Fetch and update tickets via the Atlassian MCP tools. Reference the ticket key (`DOPE-<n>`) in branch names and PR descriptions. GitHub Issues (`.github/ISSUE_TEMPLATE/`) receives external bug reports; planned work lives in Jira.
35 changes: 35 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Contributing

## Setup

Requires Node.js >= 22 < 24. See README.md for the full step by step.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use “step-by-step” wording.

Change “full step by step” to “full step-by-step guide” for grammatical correctness.

🧰 Tools
🪛 LanguageTool

[grammar] ~5-~5: Use a hyphen to join words.
Context: ...22 < 24. See README.md for the full step by step. ```bash npm install npm run dev ...

(QB_NEW_EN_HYPHEN)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CONTRIBUTING.md` at line 5, Update the setup reference in CONTRIBUTING.md to
say “full step-by-step guide” instead of “full step by step,” preserving the
existing README.md link and surrounding wording.

Source: Linters/SAST tools


```bash
npm install
npm run dev # dev server on port 1313
```

## Workflow

1. Internal work is tracked in Jira, project DOPE (internal tracker). External contributors: open a GitHub issue using the provided templates.
2. Branch from `development`, named `<type>/DOPE-<n>-<kebab-slug>` (`<type>`: feature, bugfix, task, improvement). Maintenance without a ticket uses `chore/`, `ci/`, `docs/`. External contributors without Jira access: use the GitHub issue number instead (`<type>/gh-<n>-<kebab-slug>`); a maintainer files the DOPE ticket when needed.
3. Commit style: Conventional Commits, concise, focused on why.
4. Open a PR targeting `development` and fill in the PR template.

## Before pushing

```bash
npm run test # unit tests (Jest, with coverage)
npm run test:e2e # end-to-end (Playwright, requires a build)
npm run validate:arch # architecture layer dependencies
```

Lint and format run on commit via Husky.

## Docs

If your change alters documented behavior (commands, endpoints, env vars, architecture, setup steps), update the affected docs (README, CLAUDE.md, docs/) in the same PR.

## Review

PRs are reviewed against `.claude/review-guidelines.md`.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ In order to run the development version, clone the repository, and install depen
You'll need the following tools:

- [Git](https://git-scm.com/)
- [NodeJS](https://nodejs.org/en/download/), version `>=20 <24`
- [NodeJS](https://nodejs.org/en/download/), version `>=22 <24`

### Step by step

Expand All @@ -38,6 +38,14 @@ npm install
npm run dev
```

### Running tests

```bash
npm run test # Unit tests (Jest, with coverage)
npm run test:watch # Unit tests in watch mode (no coverage)
npm run test:e2e # End-to-end tests (Playwright, builds the app first)
```

## Releasing a New Version

The project uses GitHub Actions to automatically build and release new versions for all supported platforms (macOS, Windows, and Linux) in both x64 and ARM64 architectures.
Expand Down
12 changes: 6 additions & 6 deletions docs/debugger-scalability-analysis.md
Original file line number Diff line number Diff line change
Expand Up @@ -1193,9 +1193,9 @@ Implement **Strategy F** (lazy registration) only if needed for extreme-scale pr
### openplc-editor
| File | Changes |
|------|---------|
| `src/main/modules/compiler/compiler-module.ts` | Pass target platform to xml2st |
| `src/utils/debug-parser.ts` | Support JSON manifest parsing |
| `src/renderer/utils/debugger-session.ts` | Array index handling, protocol v2 |
| `src/main/modules/modbus/modbus-client.ts` | Array element request method |
| `src/main/modules/websocket/websocket-debug-client.ts` | Array element request method |
| `src/renderer/screens/workspace-screen.tsx` | Array polling in debug loop |
| `src/backend/editor/compiler/compiler-module.ts` | Pass target platform to xml2st |
| `src/frontend/utils/debug-parser.ts` | Support JSON manifest parsing |
| `src/frontend/utils/debugger-session.ts` | Array index handling, protocol v2 |
| `src/backend/editor/modbus/modbus-client.ts` | Array element request method |
| `src/backend/shared/debug/websocket-debug-transport.ts` | Array element request method |
| `src/frontend/screens/workspace-screen.tsx` | Array polling in debug loop |
Loading
Loading