# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## What this repository is `scadaproj` is primarily an umbrella/index workspace that aggregates a family of related SCADA / OT / Wonderware / OPC UA "sister projects" that live as **sibling directories under `~/Desktop/`**. It now also **hosts two pieces of source itself** — the shared [`ZB.MOM.WW.Auth/`](ZB.MOM.WW.Auth/) library and the shared [`ZB.MOM.WW.Theme/`](ZB.MOM.WW.Theme/) UI kit — both the realized output of their respective component normalizations (see [Component normalization](#component-normalization)). The point of this file is to give a high-level scan of each sister project — its purpose, location, stack, and primary commands — so a fresh Claude Code session can orient across the whole family without opening each repo first. Each sister project keeps its own authoritative `CLAUDE.md`. This index is a **summary of those files**; when you actually work in a project, open that project's own `CLAUDE.md` for the full picture. See [Refreshing this index](#refreshing-this-index). > The project list below is **curated manually**. Add or remove entries as the family > changes — do not assume every directory under `~/Desktop/` belongs here. ## Sister projects (core SCADA/OT family) ### Runtime / implementation (active code) | Project | Location | Stack | Repo | Summary | |---|---|---|---|---| | **OtOpcUa** | `~/Desktop/OtOpcUa` | .NET 10, OPC UA, gRPC | `gitea.dohertylan.com/dohertj2/lmxopcua` | OPC UA server that exposes AVEVA System Platform (Wonderware) Galaxy tags as an OPC UA address space. Galaxy access flows through an in-process `GalaxyDriver` → gRPC → the **mxaccessgw** gateway. | | **MxAccessGateway** (`mxaccessgw`) | `~/Desktop/MxAccessGateway` | .NET 10 gateway (x64) + .NET 4.8 worker (**x86**), gRPC | `gitea.dohertylan.com/dohertj2/mxaccessgw` | gRPC gateway giving modern clients full MXAccess parity without loading 32-bit COM. Two-process: gateway (ASP.NET Core gRPC + Blazor dashboard) + per-session x86 worker that owns the MXAccess COM STA. **OtOpcUa depends on this.** | | **ScadaBridge** | `~/Desktop/ScadaBridge` | .NET 10, Akka.NET, Docker | _git_ | Full implementation of the distributed SCADA platform — hub-and-spoke (1 central cluster + N site clusters). Projects prefixed `ZB.MOM.WW.ScadaBridge.*`; solution `ZB.MOM.WW.ScadaBridge.slnx`. Ships `src/`, `tests/`, `docker/` topology, and the design docs that are the spec. | ## Cross-project relationships The three indexed projects are **separate repos and separate processes**, coupled at **runtime over wire protocols (gRPC + OPC UA)** — not by project/compile references. They share the `ZB.MOM.WW.*` product namespace (`ZB.MOM.WW.OtOpcUa.*`, `ZB.MOM.WW.ScadaBridge.*`; the gateway uses `MxGateway.*`). The common subject is **AVEVA System Platform (Wonderware) "Galaxy"** data, and `mxaccessgw` is the linchpin that the other two connect through. ### Data flow ``` AVEVA System Platform — Wonderware "Galaxy" (OT source of truth: runtime tags + Galaxy Repository SQL DB) ▲ │ MXAccess COM (32-bit, STA message pump) │ ┌────────────────┴─────────────────┐ │ MxAccessGateway (mxaccessgw) │ gateway x64 .NET10 + worker x86 net48 │ gRPC service; OWNS the 32-bit │ protos: mxaccess_gateway / mxaccess_worker │ COM bitness + STA pump │ / galaxy_repository └──────┬─────────────────────┬──────┘ gRPC (MxCommand/MxEvent + │ gRPC (ScadaBridge "MxGateway" adapter: GalaxyRepository browse) │ native MxAccess data + A&C alarms) │ │ ┌─────┴──────┐ │ │ OtOpcUa │ GalaxyDriver maps │ │ OPC UA srv │ Galaxy hierarchy → │ │ (.NET 10) │ OPC UA addr space │ └─────┬──────┘ │ │ OPC UA (opc.tcp; data + A&C alarms) ▼ ▼ ┌──────────────────────────────────────────────┐ │ ScadaBridge — Data Connection Layer (DCL) │ │ OPC UA adapter │ MxGateway adapter │ custom │ └─────────────────────────┬────────────────────┘ ▼ Instance Actors → site clusters → central cluster / UI ``` ### Edge-by-edge - **MxAccessGateway is the foundation.** It is the *only* component that loads 32-bit MXAccess COM (its x86 net48 worker owns the COM apartment + STA pump). It exposes that to modern x64/.NET-10 callers over gRPC, and also serves Galaxy Repository SQL browse RPCs. This is *why* the other two exist as .NET 10 / x64 and never touch COM directly. - **OtOpcUa → MxAccessGateway** (gRPC client). OtOpcUa's in-process `GalaxyDriver` (`src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/`) uses two gateway channels: the `GalaxyRepositoryClient` for the static hierarchy, and an MXAccess session (`MxCommand`/`MxEvent` protos) for live read/write/subscribe. A `DeployWatcher` polls the gateway's deploy-event signal to rebuild the OPC UA address space on Galaxy redeploy. OtOpcUa's job is purely a **protocol bridge**: it republishes Galaxy as an OPC UA address space for *any* OPC UA client. - **ScadaBridge → OPC UA** (OPC UA client). ScadaBridge's DCL has an OPC UA adapter that collects data and mirrors native OPC UA Alarms & Conditions. OtOpcUa is exactly such a server, so ScadaBridge can ingest Wonderware data **indirectly via OtOpcUa**. - **ScadaBridge → MxAccessGateway** (gRPC client). The DCL *also* has a dedicated **MxGateway adapter** that talks to `mxaccessgw` directly for native MxAccess data and alarms — so ScadaBridge can reach Wonderware data **directly, bypassing OtOpcUa**. Both adapters implement the same `IAlarmSubscribableConnection` seam, and a read-only `NativeAlarmActor` unifies OPC-UA-A&C and MxAccess alarms onto one condition model. ### Net effect - `mxaccessgw` is a shared dependency of **both** OtOpcUa and ScadaBridge. - ScadaBridge has **two paths** to the same Wonderware data: (1) OPC UA → OtOpcUa → gateway, or (2) MxGateway adapter → gateway directly. Path 1 gives standards-based OPC UA decoupling; path 2 gives a more direct/native feed. - Coupling is loose: each repo references the others only as **sibling context** (the `## Sister Projects` note in ScadaBridge's own `CLAUDE.md` lists `MxAccessGateway` and `OtOpcUa` with their Gitea URLs but states they are *not part of its solution*). - **The break surface is the wire contracts, not code.** Because coupling is by network protocol, the things that break across repo boundaries are: the gateway's `.proto` files (`mxaccess_gateway.proto`, `mxaccess_worker.proto`, `galaxy_repository.proto`), and the OPC UA address-space shape OtOpcUa publishes (browse paths, node IDs, A&C alarm model). Changes to any of these must be coordinated across the affected repos — a green build in one repo does not prove the others still interoperate. ## Component normalization Because the sister repos re-implement the same cross-cutting concerns separately and drift apart, [`components/`](components/) normalizes them: per component, the **one target** spec, each project's **code-verified current state**, and the **gaps** between. See [`components/README.md`](components/README.md) for the convention and workflow. | Component | Status | Goal | Design | Implementation | |---|---|---|---|---| | Auth (login / identity / authz) | Built (lib `0.1.0`) | Shared `ZB.MOM.WW.Auth` lib | [`components/auth/`](components/auth/) | [`ZB.MOM.WW.Auth/`](ZB.MOM.WW.Auth/) | | UI Theme (layout / tokens / components) | Built (lib `0.1.0`) | Shared `ZB.MOM.WW.Theme` RCL | [`components/ui-theme/`](components/ui-theme/) | [`ZB.MOM.WW.Theme/`](ZB.MOM.WW.Theme/) | The auth component is fully populated: a normalized [`spec`](components/auth/spec/SPEC.md), a proposed [`shared-contract`](components/auth/shared-contract/ZB.MOM.WW.Auth.md), three [`current-state`](components/auth/current-state/) docs, and an adoption [`GAPS`](components/auth/GAPS.md) backlog. Common ground = LDAP/GLAuth identity + peppered-HMAC API keys; left per-project = the authz vocabularies (OPC-UA permissions / gRPC scopes / roles + site-scoping). The shared library is **built and lives in this repo** at [`ZB.MOM.WW.Auth/`](ZB.MOM.WW.Auth/) (its own nested git repo; .NET 10; 4 packages — `Abstractions`, `Ldap`, `ApiKeys`, `AspNetCore`; 172 tests; `dotnet pack` → 4 nupkgs @ 0.1.0). The implementation plan is at [`docs/plans/2026-06-01-zb-mom-ww-auth-shared-library.md`](docs/plans/2026-06-01-zb-mom-ww-auth-shared-library.md). **Not yet adopted** by the three apps — that's the follow-on tracked in [`components/auth/GAPS.md`](components/auth/GAPS.md) (#8). Build/test from `ZB.MOM.WW.Auth/`: `dotnet test`. Consumer matrix: OtOpcUa → Abstractions+Ldap+AspNetCore; MxAccessGateway & ScadaBridge → all four (ApiKeys not used by OtOpcUa). The UI-theme component is fully populated: a normalized [`spec`](components/ui-theme/spec/SPEC.md), a [`design-tokens`](components/ui-theme/spec/DESIGN-TOKENS.md) reference, a [`shared-contract`](components/ui-theme/shared-contract/ZB.MOM.WW.Theme.md), three [`current-state`](components/ui-theme/current-state/) docs, and an adoption [`GAPS`](components/ui-theme/GAPS.md) backlog. Shared = Technical-Light tokens + IBM Plex fonts + side-rail shell + widgets; left per-project = each app's `site.css` page layout, route content, scoped `.razor.css`. The shared RCL is **built and lives in this repo** at [`ZB.MOM.WW.Theme/`](ZB.MOM.WW.Theme/) (.NET 10 Razor Class Library; single package; 32 bUnit tests; `dotnet pack` → 1 nupkg @ 0.1.0). The implementation plan is at [`docs/plans/2026-06-01-zb-mom-ww-theme-shared-library.md`](docs/plans/2026-06-01-zb-mom-ww-theme-shared-library.md). **Not yet adopted** by the three apps — that's the follow-on tracked in [`components/ui-theme/GAPS.md`](components/ui-theme/GAPS.md). Build/test from `ZB.MOM.WW.Theme/`: `dotnet test`. Consumer matrix: all three apps consume the single `ZB.MOM.WW.Theme` package (OtOpcUa AdminUI, MxGateway Server, ScadaBridge Host + CentralUI). ## Per-project primary commands Run these from inside each project directory (not from `scadaproj`). ```bash # OtOpcUa dotnet build ZB.MOM.WW.OtOpcUa.slnx dotnet test ZB.MOM.WW.OtOpcUa.slnx dotnet test --filter "FullyQualifiedName~MyTestClass.MyMethod" # single test # Docker fixtures run on shared host 10.100.0.35; control via `lmxopcua-fix` (in ~/bin) # MxAccessGateway (PowerShell on Windows) dotnet build src/MxGateway.sln dotnet build src/MxGateway.Worker/MxGateway.Worker.csproj -p:Platform=x86 # worker MUST be x86 dotnet test src/MxGateway.Tests/MxGateway.Tests.csproj # no MXAccess needed (fake worker) dotnet run --project src/MxGateway.Server/MxGateway.Server.csproj # ScadaBridge (~/Desktop/ScadaBridge) dotnet build ZB.MOM.WW.ScadaBridge.slnx bash docker/deploy.sh # rebuild + redeploy the 8-node cluster cd infra && docker compose up -d # local test services (LDAP, SQL, OPC UA, SMTP, REST, Traefik) ``` ## Refreshing this index This file is meant to be re-scanned when `scadaproj` is opened in Claude Code: 1. List sibling SCADA/OT directories: `find ~/Desktop -maxdepth 2 -iname "claude.md"`. 2. For each project the user wants indexed, read the **top of its `CLAUDE.md`** (project overview + build/run sections) and update its row above. 3. Keep the project set **curated** — only the SCADA/OT/Wonderware/OPC-UA family belongs here. 4. Flag new duplicates/overlaps and namespace mismatches rather than silently merging them. ## Other workspace projects with a CLAUDE.md (not indexed — promote on request) Listed so they can be pulled into the index above if you decide they belong. **SCADA/OT, de-indexed (still have a `CLAUDE.md` under `~/Desktop/`):** - **OpcUaTestServer** — dual-instance OPC UA test server (.NET 10) for testing OPC UA clients / simulating automation. - **scada** (ScadaLink) — design docs + scaffolding for the distributed SCADA platform (`ZB.MOM.ScadaLink.*`). - **scadalink-design-opcua-browser** — ScadaBridge variant focused on OPC UA browser / Data Connection Layer work. - **DARS** — DARS → Wonderware SCADA migration (design phase, Q2 2026 go-live). - **DARS_BU** — backup snapshot of DARS. - **plan** — 3-year SCADA IT/OT modernization roadmap (markdown). **Outside the SCADA family:** - **delmia** — DELMIA / Apriso (Intercim Velocity) MES customization export (ASP.NET `.asmx`); MES-adjacent. - **lightctrl** — Raspberry Pi Python I/O control (edge hardware). - **codestats** — Rust CLI for code statistics on .NET solutions/dirs (dev tooling for the .NET repos). - **servecli** — Rust portable SSH/SFTP server for Windows remote task management (greenfield). - **JdeScopingTool** — JD Edwards "LotFinder" .NET 4.8 → .NET 10 migration (ERP, not SCADA). - **chat** — local-first roleplay chat engine. - **candy2** — candy.ai chat scraping / browser automation. - **menardslist** — Menards.com cart → printable picklist PDF.