# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## What This Is

LmxProxy is a gRPC proxy that bridges ScadaLink's Data Connection Layer to AVEVA System Platform via the ArchestrA MXAccess COM API. It has two projects:

- **Host** (`ZB.MOM.WW.LmxProxy.Host`) — .NET Framework 4.8, x86-only Windows service. Hosts a gRPC server (Grpc.Core) that fronts an MxAccessClient talking to ArchestrA MXAccess. Runs as a Windows service via Topshelf.
- **Client** (`ZB.MOM.WW.LmxProxy.Client`) — .NET 10, AnyCPU library. Code-first gRPC client (protobuf-net.Grpc) consumed by ScadaLink's DCL. This is a NuGet-packable library.

The two projects use **different gRPC stacks**: Host uses proto-file-generated code (`Grpc.Core` + `Grpc.Tools`), Client uses code-first contracts (`protobuf-net.Grpc` with `[DataContract]`/`[ServiceContract]` attributes). They are wire-compatible because both target the same `scada.ScadaService` gRPC service.

## Build Commands

```bash
dotnet build ZB.MOM.WW.LmxProxy.slnx           # Build entire solution
dotnet build src/ZB.MOM.WW.LmxProxy.Host        # Host only (requires x86 platform)
dotnet build src/ZB.MOM.WW.LmxProxy.Client      # Client only
```

The Host project requires the `ArchestrA.MXAccess.dll` COM interop assembly in `lib/`. It targets x86 exclusively (MXAccess is 32-bit COM).

## Architecture

### Host Service Startup Chain

`Program.Main` → Topshelf `HostFactory` → `LmxProxyService.Start()` which:
1. Validates configuration (`appsettings.json` bound to `LmxProxyConfiguration`)
2. Creates `MxAccessClient` (the `IScadaClient` impl that wraps ArchestrA.MXAccess COM)
3. Connects to MxAccess synchronously at startup
4. Starts connection monitor loop (auto-reconnect)
5. Creates `SubscriptionManager`, `SessionManager`, `PerformanceMetrics`, `ApiKeyService`
6. Creates `ScadaGrpcService` (the proto-generated service impl) with all dependencies
7. Starts Grpc.Core `Server` on configured port (default 50051)
8. Starts HTTP status web server (default port 8080)

### Key Host Components

- `MxAccessClient` — Partial class split across 6 files (Connection, ReadWrite, Subscription, EventHandlers, NestedTypes, main). Wraps `LMXProxyServer` COM object. Uses semaphores for concurrency control.
- `ScadaGrpcService` — Inherits proto-generated `ScadaService.ScadaServiceBase`. All RPCs validate session first, then delegate to `IScadaClient`. Values are string-serialized on the wire (v1 protocol).
- `SessionManager` — Tracks client sessions by GUID.
- `SubscriptionManager` — Manages MxAccess subscriptions, fans out updates via `System.Threading.Channels`.
- `ApiKeyInterceptor` — gRPC server interceptor for API key validation.

### Client Architecture

- `ILmxProxyClient` — Public interface for consumers. Connect/Read/Write/Subscribe/Dispose.
- `LmxProxyClient` — Partial class split across multiple files (Connection, Subscription, Metrics, etc.). Uses `protobuf-net.Grpc` code-first contracts (`IScadaService` in `Domain/ScadaContracts.cs`).
- `LmxProxyClientBuilder` — Fluent builder for configuring client instances.
- `Domain/ScadaContracts.cs` — All gRPC message types as `[DataContract]` POCOs and the `IScadaService` interface with `[ServiceContract]`.
- Value conversion: Client parses string values from wire using double → bool → string heuristic in `ConvertToVtq()`. Writes use `.ToString()` via `ConvertToString()`.

### Protocol

Proto definition: `src/ZB.MOM.WW.LmxProxy.Host/Grpc/Protos/scada.proto`

Currently v1 protocol (string-encoded values, string quality). A v2 protocol spec exists in `docs/lmxproxy_updates.md` that introduces `TypedValue` (protobuf oneof) and `QualityCode` (OPC UA status codes) — not yet implemented.

RPCs: Connect, Disconnect, GetConnectionState, Read, ReadBatch, Write, WriteBatch, WriteBatchAndWait, Subscribe (server streaming), CheckApiKey.

### Configuration

Host configured via `appsettings.json` bound to `LmxProxyConfiguration`. Key sections: GrpcPort, Connection (timeouts, auto-reconnect), Subscription (channel capacity), Tls, WebServer, Serilog, RetryPolicies, HealthCheck.

## Important Constraints

- Host **must** target x86 and .NET Framework 4.8 (ArchestrA.MXAccess is 32-bit COM interop).
- Host uses `Grpc.Core` (the deprecated C-core gRPC library), not `Grpc.Net`. This is required because .NET 4.8 doesn't support `Grpc.Net.Server`.
- Client uses `Grpc.Net.Client` and targets .NET 10 — it runs in the ScadaLink central/site clusters.
- The solution file is `.slnx` format (XML-based, not the older text format).
