Files
lmxopcua/docs/reqs/ClientRequirements.md
Joseph Doherty 48970af416 Doc refresh (task #205) — requirements updated for multi-driver OtOpcUa three-process deploy
Per-file summary:

- docs/reqs/OpcUaServerReqs.md — rewritten driver-agnostic. OPC-001..OPC-013 re-scoped to multi-driver address-space composition + capability dispatch; OPC-014 AuthorizationGate + permission trie; OPC-015 dynamic ServiceLevel via RedundancyCoordinator; OPC-017 surgical generation-apply rebuild; OPC-012 capability dispatch via CapabilityInvoker (decision #143 idempotence-aware retry); OPC-013 per-host Polly isolation (decision #144); OPC-019 OpenTelemetry metrics. Transport-security profile matrix (OPC-010) + UserName/LDAP (OPC-011) preserved.

- docs/reqs/GalaxyRepositoryReqs.md — scope clarified as Galaxy-driver-only (not platform). GR-001..GR-004 tied to ITagDiscovery.DiscoverAsync + IRediscoverable; all SQL runs inside OtOpcUa.Galaxy.Host and streams to Proxy via named pipe. GR-008 capability wrapping via CapabilityInvoker added. Cross-links to docs/v2/driver-specs.md + docs/GalaxyRepository.md.

- docs/reqs/MxAccessClientReqs.md — scope clarified as Galaxy-Host-only. MXA-001..MXA-009 preserved (STA pump, register/unregister, subscription refcount, auto-reconnect, probe, COM cleanup, operation metrics, error translation). MXA-010 Proxy-side capability wrapping + MXA-011 pipe ACL + per-process shared secret (OTOPCUA_ALLOWED_SID / OTOPCUA_GALAXY_SECRET) added.

- docs/reqs/ServiceHostReqs.md — rewritten for three-process deployment. Shared section (SVC-SHARED-001/002) for Serilog + bootstrap-only appsettings. SRV-* for OtOpcUa.Server (net10 x64, Microsoft.Extensions.Hosting + AddWindowsService, in-process driver hosting, redundancy-node bootstrap). ADM-* for OtOpcUa.Admin (Blazor Server, cookie+LDAP auth, CanEdit/CanPublish policies, sole DB writer, Prometheus /metrics, audit logging). GHX-* for OtOpcUa.Galaxy.Host (TopShelf, net48 x86, named-pipe IPC bootstrap, STA backend lifecycle, crash handling tied to supervisor).

- docs/reqs/ClientRequirements.md — restructured as numbered, verifiable requirements. SHR-* for Client.Shared (single IOpcUaClientService, ConnectionSettings, failover, cross-platform certs, type-coercing write, UI-thread neutrality). CLI-001..CLI-011 cover connect/read/write/browse/subscribe/historyread/alarms/redundancy. UI-001..UI-008 cover connection panel, tree browser, each tab, connection-state reflection, cross-platform build. Reference design content (IOpcUaClientService shape, models, view-model map, mock layout) preserved.

- docs/reqs/StatusDashboardReqs.md — retired cleanly. Replaced with a pointer to docs/v2/admin-ui.md + HLR-015 / HLR-016 / HLR-017 / ADM-*. Mapping table shows each retired DASH-001..DASH-009 requirement's replacement (live cluster-node view via SignalR, Prometheus metrics, driver-instance detail views, etc.). Note that a formal AdminUiReqs.md can be written later if needed for cert compliance.

HighLevelReqs.md was already at the target shape (HLR-001..HLR-018 with Revision header noting retired HLR-009) as of commit f217636; verified identical and no additional edit required.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 01:31:58 -04:00

12 KiB

OPC UA Client Requirements

Revision — Refreshed 2026-04-19 for the OtOpcUa v2 multi-driver platform (task #205). The Client surface (shared library + CLI + UI) shipped for v2 is preserved; this refresh restructures the document into numbered, directly-verifiable requirements (CLI-* and UI-* prefixes) layered on top of the existing detailed design content. Requirement coverage added for the redundancy command, alarm subscribe/ack round-trip, history-read, and UI tree-browser drag-to-subscribe behaviors. Original design-spec material for ConnectionSettings, IOpcUaClientService, models, and view-models is retained as reference-level details below the numbered requirements.

Parent: HLR-001, HLR-009, HLR-013

See also: docs/Client.CLI.md, docs/Client.UI.md.

Projects

Project Type Purpose
ZB.MOM.WW.OtOpcUa.Client.Shared Class library Core OPC UA client, models, interfaces
ZB.MOM.WW.OtOpcUa.Client.CLI Console app Command-line interface using CliFx
ZB.MOM.WW.OtOpcUa.Client.UI Avalonia app Desktop UI
ZB.MOM.WW.OtOpcUa.Client.Shared.Tests Test project Shared-library unit tests
ZB.MOM.WW.OtOpcUa.Client.CLI.Tests Test project CLI command tests
ZB.MOM.WW.OtOpcUa.Client.UI.Tests Test project ViewModel unit tests

Shared Requirements (Client.Shared)

SHR-001: Single Service Interface

The Client.Shared library shall expose a single service interface IOpcUaClientService covering connect, disconnect, read, write, browse, subscribe, alarm-subscribe, alarm-ack, history-read-raw, history-read-aggregate, and get-redundancy-info operations.

SHR-002: ConnectionSettings Model

The library shall expose a ConnectionSettings record with the fields: EndpointUrl (required), FailoverUrls[], Username, Password, SecurityMode (None/Sign/SignAndEncrypt; default None), SessionTimeoutSeconds (default 60), AutoAcceptCertificates (default true), CertificateStorePath.

SHR-003: Automatic Failover

The library shall monitor session keep-alive and automatically fail over across FailoverUrls when the primary endpoint is unreachable, emitting a ConnectionStateChanged event on each transition (Disconnected / Connecting / Connected / Reconnecting).

SHR-004: Cross-Platform Certificate Store

The library shall auto-generate a client certificate on first use and store it in a cross-platform path (default {AppData}/OtOpcUaClient/pki/). Server certificates are auto-accepted when AutoAcceptCertificates = true.

SHR-005: Type-Coercing Write

The library's WriteValueAsync(NodeId, object) shall read the node's current value to determine target type and coerce the input value before sending.

SHR-006: UI-Thread Dispatch Neutrality

The library shall not assume any specific synchronization context. Events (DataChanged, AlarmEvent, ConnectionStateChanged) are raised on the OPC UA stack thread; the consuming CLI / UI is responsible for dispatching to its UI thread.


CLI Requirements (Client.CLI)

CLI-001: Command Surface

The CLI shall expose the following commands: connect, read, write, browse, subscribe, historyread, alarms, redundancy.

CLI-002: Common Options

All CLI commands shall accept the options -u, --url (required), -U, --username, -P, --password, -S, --security none|sign|encrypt, -F, --failover-urls (comma-separated), --verbose.

CLI-003: Connect Command

The connect command shall attempt to establish a session using the supplied options and print Connected plus the resolved endpoint's ServerUriArray and ApplicationUri on success, or a diagnostic error message on failure.

CLI-004: Read Command

The read -n <NodeId> command shall print NodeId, Value, StatusCode, SourceTimestamp, ServerTimestamp one per line.

CLI-005: Write Command

The write -n <NodeId> -v <value> command shall coerce the value to the node's current type (per SHR-005) and print the resulting StatusCode. A Bad_UserAccessDenied result is printed verbatim so operators see the authorization outcome.

CLI-006: Browse Command

The browse [-n <parent>] [-r] [-d <depth>] command shall list child nodes under parent (or the Objects folder if omitted). -r enables recursion up to -d depth (default 1).

CLI-007: Subscribe Command

The subscribe -n <NodeId> -i <intervalMs> command shall create a monitored item at intervalMs publishing interval, print each DataChanged event as <timestamp> <nodeId> <value> <status> until Ctrl-C, then cleanly unsubscribe.

CLI-008: Historyread Command

The historyread -n <NodeId> --start <utc> --end <utc> [--max <n>] [--aggregate <type> --interval <ms>] command shall print raw values or aggregate buckets. Supported aggregate types: Average, Minimum, Maximum, Count, Start, End.

CLI-009: Alarms Command

The alarms [-n <source>] [-i <intervalMs>] command shall subscribe to alarm events, print each event as <time> <source> <condition> <severity> <state> <acked> <message>, accept ack <conditionId> commands interactively, and support refresh to trigger RequestConditionRefreshAsync.

CLI-010: Redundancy Command

The redundancy command shall call GetRedundancyInfoAsync and print Mode, ServiceLevel, ApplicationUri, and ServerUris (one per line). Suitable for redundancy-failover smoke tests.

CLI-011: Logging

The CLI shall use Serilog console sink at Warning minimum by default; --verbose raises to Debug.


UI Requirements (Client.UI)

UI-001: Connection Panel

The UI shall present a top-bar connection panel with fields for Endpoint URL, Username, Password, Security mode, and a Connect / Disconnect button. The resolved RedundancyInfo is displayed next to the bar on successful connect.

UI-002: Tree Browser

The UI shall present a left-pane tree browser backed by IOpcUaClientService.BrowseAsync, lazy-loading children on node expansion (one level per BrowseAsync call).

UI-003: Read/Write Tab

The UI shall provide a Read/Write tab that auto-reads the selected tree node's current value, displays Value + StatusCode + SourceTimestamp, and accepts a write value with a Send button.

UI-004: Subscriptions Tab

The UI shall provide a Subscriptions tab that lists active monitored items (columns: NodeId, Value, Status, Timestamp), supports Add and Remove, and dispatches DataChanged events to the Avalonia UI thread via Dispatcher.UIThread.Post.

UI-005: Alarms Tab

The UI shall provide an Alarms tab that supports SubscribeAlarms / UnsubscribeAlarms / RefreshConditions commands, displays live alarm events, and supports Acknowledge on selected events. Acknowledgment failure (including Bad_UserAccessDenied) is surfaced to the user.

UI-006: History Tab

The UI shall provide a History tab with inputs for StartTime, EndTime, MaxValues, AggregateType, Interval, a Read command, and a results table with columns (Timestamp, Value, Status).

UI-007: Connection State Reflects in UI

All tabs shall reflect the connection state — when disconnected, all action commands are disabled; the status bar shows Disconnected / Connecting / Connected / Reconnecting tied to the ConnectionStateChanged event.

UI-008: Cross-Platform

The UI shall build and run on Windows (win-x64) and macOS (osx-arm64 / osx-x64). No platform-specific OPC UA stack APIs are used.


Technology Stack

  • .NET 10, C#
  • OPC UA: OPCFoundation.NetStandard.Opc.Ua.Client
  • Logging: Serilog
  • CLI: CliFx
  • UI: Avalonia 11.x with CommunityToolkit.Mvvm
  • Tests: xUnit 3, Shouldly, Microsoft.Testing.Platform runner

Client.Shared — Design Detail

IOpcUaClientService Interface (reference)

Lifecycle: ConnectAsync(ConnectionSettings), DisconnectAsync(), IsConnected.

Read/Write: ReadValueAsync(NodeId), WriteValueAsync(NodeId, object).

Browse: BrowseAsync(NodeId? parent)BrowseResult[] (NodeId, DisplayName, NodeClass, HasChildren); lazy-load compatible.

Subscribe: SubscribeAsync(NodeId, int intervalMs), UnsubscribeAsync(NodeId), event DataChanged(NodeId, DataValue).

Alarms: SubscribeAlarmsAsync(NodeId? source, int intervalMs), UnsubscribeAlarmsAsync(), AcknowledgeAsync(conditionId, comment), RequestConditionRefreshAsync(), event AlarmEvent(AlarmEventArgs).

History: HistoryReadRawAsync(NodeId, start, end, maxValues), HistoryReadAggregateAsync(NodeId, start, end, AggregateType, intervalMs).

Redundancy: GetRedundancyInfoAsync()RedundancyInfo (Mode, ServiceLevel, ServerUris, ApplicationUri).

Models

  • BrowseResult — NodeId, DisplayName, NodeClass, HasChildren
  • AlarmEventArgs — SourceName, ConditionName, Severity, Message, Retain, ActiveState, AckedState, Time
  • RedundancyInfo — Mode, ServiceLevel, ServerUris, ApplicationUri
  • ConnectionState — enum (Disconnected, Connecting, Connected, Reconnecting)
  • AggregateType — enum (Average, Minimum, Maximum, Count, Start, End)

Client.UI — View Layout (reference)

Single-window Avalonia application:

┌─────────────────────────────────────────────────────────┐
│ [Endpoint URL] [User] [Pass] [Security▼] [Connect]     │
│ Redundancy: Mode=Warm  ServiceLevel=200  AppUri=...     │
├──────────────┬──────────────────────────────────────────┤
│              │ ┌Read/Write┬Subscriptions┬Alarms┬History┐│
│  Address     │ │ Node: ns=3;s=Tag.Attr               ││
│  Space       │ │ Value: 42.5 Status: Good            ││
│  Tree        │ │ [Write: ____] [Send]                ││
│  Browser     │ └───────────────────────────────────────┘│
├──────────────┴──────────────────────────────────────────┤
│ Status: Connected | Session: abc123 | 3 subscriptions   │
└─────────────────────────────────────────────────────────┘

ViewModels (CommunityToolkit.Mvvm)

  • MainWindowViewModel — connection fields, connect/disconnect commands, ConnectionState, RedundancyInfo, SelectedTreeNode, StatusMessage.
  • BrowseTreeViewModel — root collection (ObservableCollection<TreeNodeViewModel>), lazy-load on expand.
  • ReadWriteViewModel — auto-read on selection, WriteValue + WriteCommand.
  • SubscriptionsViewModelActiveSubscriptions, AddSubscription, RemoveSubscription, live DataChanged dispatch to UI thread.
  • AlarmsViewModelAlarmEvents, Subscribe / Unsubscribe / Refresh / Acknowledge commands.
  • HistoryViewModelStartTime, EndTime, MaxValues, AggregateType, Interval, ReadCommand, Results.

Test Projects

Client.Shared.Tests

  • ConnectionSettings validation
  • Type conversion
  • BrowseResult / AlarmEventArgs / RedundancyInfo model construction
  • FailoverUrl parsing

Client.CLI.Tests

  • Command option parsing (via CliFx test infrastructure)
  • Output formatting for each command

Client.UI.Tests

  • ViewModel property-change notifications
  • Command CanExecute logic
  • Tree lazy-load behavior (with mocked IOpcUaClientService)

Test Framework

  • xUnit 3 with Microsoft.Testing.Platform runner
  • Shouldly
  • No live OPC UA server required — mock IOpcUaClientService for unit tests