Audit (three parallel agent passes) found 43 markdown files carrying stale references to the deleted Galaxy.Host/Proxy/Shared projects after the v2-mxgw merge. This commit lands the prioritized fixes. Track 1 — high-traffic in-place rewrites (3 files, ~454 lines deleted) - README.md (202 → 91 lines): drops .NET 4.8 / x86 / TopShelf install text; leads with the multi-driver .NET 10 server identity and points at scripts/install/Install-Services.ps1 and the parity rig. - docs/v2/driver-specs.md §1 Galaxy (~289 → ~66 lines): replaces the Tier-C out-of-process spec with a Tier-A in-process description matching the current GalaxyDriver code, with the four-section GalaxyDriverOptions JSON shape pulled verbatim from Config/GalaxyDriverOptions.cs. - docs/drivers/Galaxy.md (211 → 92 lines): full rewrite around the current Browse/Runtime/Health/Config sub-folders. Track 2 — historical banners (5 files) - lmx_mxgw.md, lmx_mxgw_impl.md, lmx_backend.md, docs/v2/Galaxy.ParityMatrix.md, docs/v2/implementation/phase-2-galaxy-out-of-process.md each get a "✅ Completed 2026-04-30 — historical record" banner block. lmx_mxgw.md also fixes two dead links (`docs/Galaxy.Driver.md` and `docs/v2/Galaxy.Driver.md`) → `docs/drivers/Galaxy.md`. Track 3 — v1 archive sweep (10 git mv + 1 new index + 2 in-place scrubs) - Moved 10 v1 docs under docs/v1/ preserving subpath structure: AlarmTracking, Configuration, DataTypeMapping, HistoricalDataAccess, Subscriptions (top-level); drivers/Galaxy-Repository, drivers/Galaxy-Test-Fixture; reqs/GalaxyRepositoryReqs, reqs/MxAccessClientReqs, reqs/ServiceHostReqs. - New docs/v1/README.md is the shared archive banner + per-file table. - docs/README.md repointed to the v1 paths and updated to reflect the v2 two-process deploy shape (Server + Admin + optional OtOpcUaWonderwareHistorian). - docs/v2/Galaxy.ParityRig.md got a historical banner + four inline scrubs marking the OtOpcUaGalaxyHost service / Driver.Galaxy.Host EXE / Driver.Galaxy.ParityTests project as deleted-in-PR-7.2. The repo's live-reading surface (README + CLAUDE.md + docs/v2/) now describes only the post-PR-7.2 architecture. v1 docs are preserved as a labelled archive under docs/v1/. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9.5 KiB
Configuration
Two-layer model
OtOpcUa configuration is split into two layers:
| Layer | Where | Scope | Edited by |
|---|---|---|---|
| Bootstrap | appsettings.json per process |
Enough to start the process and reach the Config DB | Local file edit + process restart |
| Authoritative config | Config DB (SQL Server) via OtOpcUaConfigDbContext |
Clusters, namespaces, UNS hierarchy, equipment, tags, driver instances, ACLs, role grants, poll groups | Admin UI draft/publish workflow |
The rule: if the setting describes how the process connects to the rest of the world (Config DB connection string, LDAP bind, transport security profile, node identity, logging), it lives in appsettings.json. If it describes what the fleet does (clusters, drivers, tags, UNS, ACLs), it lives in the Config DB and is edited through the Admin UI.
Bootstrap configuration (appsettings.json)
Each of the three processes (Server, Admin, Galaxy.Host) reads its own appsettings.json plus environment overrides.
OtOpcUa Server — src/ZB.MOM.WW.OtOpcUa.Server/appsettings.json
Bootstrap-only. Program.cs reads four top-level sections:
| Section | Keys | Purpose |
|---|---|---|
Node |
NodeId, ClusterId, ConfigDbConnectionString, LocalCachePath |
Identity + path to the Config DB + LiteDB offline cache path. |
OpcUaServer |
EndpointUrl, ApplicationName, ApplicationUri, PkiStoreRoot, AutoAcceptUntrustedClientCertificates, SecurityProfile |
OPC UA endpoint + transport security. See security.md. |
OpcUaServer:Ldap |
Enabled, Server, Port, UseTls, AllowInsecureLdap, SearchBase, ServiceAccountDn, ServiceAccountPassword, GroupToRole, UserNameAttribute, GroupAttribute |
LDAP auth for OPC UA UserName tokens. See security.md. |
Serilog |
Standard Serilog keys + WriteJson bool |
Logging verbosity + optional JSON file sink for SIEM ingest. |
Authorization |
StrictMode (bool) |
Flip true to fail-closed on sessions lacking LDAP group metadata. Default false during ACL rollouts. |
Metrics:Prometheus:Enabled |
bool | Toggles the /metrics endpoint. |
Minimal example:
{
"Serilog": { "MinimumLevel": "Information" },
"Node": {
"NodeId": "node-dev-a",
"ClusterId": "cluster-dev",
"ConfigDbConnectionString": "Server=localhost,14330;Database=OtOpcUaConfig;Integrated Security=True;TrustServerCertificate=True;Encrypt=False;",
"LocalCachePath": "config_cache.db"
},
"OpcUaServer": {
"EndpointUrl": "opc.tcp://0.0.0.0:4840/OtOpcUa",
"ApplicationUri": "urn:node-dev-a:OtOpcUa",
"SecurityProfile": "None",
"AutoAcceptUntrustedClientCertificates": true,
"Ldap": { "Enabled": false }
}
}
OtOpcUa Admin — src/ZB.MOM.WW.OtOpcUa.Admin/appsettings.json
| Section | Purpose |
|---|---|
ConnectionStrings:ConfigDb |
SQL connection string — must point at the same Config DB every Server reaches. |
Authentication:Ldap |
LDAP bind for the Admin login form (same options shape as the Server's OpcUaServer:Ldap). |
CertTrust |
CertTrustOptions — file-system path under the Server's PkiStoreRoot so the Admin Certificates page can promote rejected client certs. |
Metrics:Prometheus:Enabled |
Toggles the /metrics scrape endpoint (default true). |
Serilog |
Logging. |
Galaxy.Host
Environment-variable driven (OTOPCUA_GALAXY_PIPE, OTOPCUA_ALLOWED_SID, OTOPCUA_GALAXY_SECRET, OTOPCUA_GALAXY_BACKEND, OTOPCUA_GALAXY_ZB_CONN, OTOPCUA_HISTORIAN_*). No appsettings.json — the supervisor owns the launch environment. See ServiceHosting.md.
Environment overrides
Standard .NET config layering applies: appsettings.{Environment}.json, then environment variables with Section__Property naming. DOTNET_ENVIRONMENT (or ASPNETCORE_ENVIRONMENT for Admin) selects the overlay.
Authoritative configuration (Config DB)
The Config DB is the single source of truth for every setting that a v1 deployment used to carry in appsettings.json as driver-specific state. OtOpcUaConfigDbContext (src/ZB.MOM.WW.OtOpcUa.Configuration/OtOpcUaConfigDbContext.cs) is the EF Core context used by both the Admin writer and every Server reader.
Top-level sections operators touch
| Concept | Entity | Admin UI surface | Purpose |
|---|---|---|---|
| Cluster | ServerCluster |
Clusters pages | Fleet unit; owns nodes, generations, UNS, ACLs. |
| Cluster node | ClusterNode + ClusterNodeCredential |
RedundancyTab, Hosts page | Per-node identity, RedundancyRole, ServiceLevelBase, ApplicationUri, service-account credentials. |
| Generation | ConfigGeneration + ClusterNodeGenerationState |
Generations / DiffViewer | Append-only; draft → publish workflow (sp_PublishGeneration). |
| Namespace | Namespace |
Namespaces tab | Per-cluster OPC UA namespace; Kind = Equipment / SystemPlatform / Simulated. |
| Driver instance | DriverInstance |
Drivers tab | Configured driver (Modbus, S7, OpcUaClient, Galaxy, …) + DriverConfig JSON + resilience profile. |
| Device | Device |
Under each driver instance | Per-host settings inside a driver instance (IP, port, unit-id…). |
| UNS hierarchy | UnsArea + UnsLine |
UnsTab (drag/drop) | L3 / L4 of the unified namespace. |
| Equipment | Equipment |
Equipment pages, CSV import | L5; carries MachineCode, ZTag, SAPID, EquipmentUuid, reservation-backed external ids. |
| Tag | Tag |
Under each equipment | Driver-specific tag address + SecurityClassification + poll-group assignment. |
| Poll group | PollGroup |
Driver-scoped | Poll cadence buckets; PollGroupEngine in Core.Abstractions uses this at runtime. |
| ACL | NodeAcl |
AclsTab + Probe dialog | Per-level permission grants, additive only. See security.md. |
| Role grant | LdapGroupRoleMapping |
RoleGrants page | Maps LDAP groups → Admin roles (ConfigViewer / ConfigEditor / FleetAdmin). |
| External id reservation | ExternalIdReservation |
Reservations page | Reservation-backed ZTag and SAPID uniqueness. |
| Equipment import batch | EquipmentImportBatch |
CSV import flow | Staged bulk-add with validation preview. |
| Audit log | ConfigAuditLog |
Audit page | Append-only record of every publish, rollback, credential rotation, role-grant change. |
Draft → publish generation model
All edits go into a draft generation scoped to one cluster. DraftValidationService checks invariants (same-cluster FKs, reservation collisions, UNS path consistency, ACL scope validity). When the operator clicks Publish, sp_PublishGeneration atomically promotes the draft, records the audit event, and causes every RedundancyCoordinator.RefreshAsync in the affected cluster to pick up the new topology + ACL set. The Admin UI DiffViewer shows exactly what's changing before publish.
Old generations are retained; rollback is "publish older generation as new". ConfigAuditLog makes every change auditable by principal + timestamp.
Offline cache
Each Server process caches the last-seen published generation in Node:LocalCachePath via LiteDB (LiteDbConfigCache in src/ZB.MOM.WW.OtOpcUa.Configuration/LocalCache/). The cache lets a node start without the central DB reachable; once the DB comes back, NodeBootstrap syncs to the current generation.
Full schema reference
For table columns, indexes, stored procedures, the publish-transaction semantics, and the SQL authorization model (per-node SQL principals + SESSION_CONTEXT cluster binding), see docs/v2/config-db-schema.md.
Admin UI flow
For the draft editor, DiffViewer, CSV import, IdentificationFields, RedundancyTab, AclsTab + Probe-this-permission, RoleGrants, and the SignalR real-time surface, see docs/v2/admin-ui.md.
Where did v1 appsettings sections go?
Quick index for operators coming from v1 LmxOpcUa:
| v1 appsettings section | v2 home |
|---|---|
OpcUa.Port / BindAddress / EndpointPath / ServerName |
Bootstrap OpcUaServer:EndpointUrl + ApplicationName. |
OpcUa.ApplicationUri |
Config DB ClusterNode.ApplicationUri. |
OpcUa.MaxSessions / SessionTimeoutMinutes |
Bootstrap OpcUaServer:* (if exposed) or stack defaults. |
OpcUa.AlarmTrackingEnabled / AlarmFilter |
Per driver instance in Config DB (alarm surface is capability-driven per IAlarmSource). |
MxAccess.* |
Galaxy driver instance DriverConfig JSON + Galaxy.Host env vars (see ServiceHosting.md). |
GalaxyRepository.* |
Galaxy driver instance DriverConfig JSON + OTOPCUA_GALAXY_ZB_CONN env var. |
Dashboard.* |
Retired — Admin UI replaces the dashboard. See StatusDashboard.md. |
Historian.* |
Galaxy driver instance DriverConfig JSON + OTOPCUA_HISTORIAN_* env vars. |
Authentication.Ldap.* |
Bootstrap OpcUaServer:Ldap (same shape) + Admin Authentication:Ldap for the UI login. |
Security.* |
Bootstrap OpcUaServer:SecurityProfile + PkiStoreRoot + AutoAcceptUntrustedClientCertificates. |
Redundancy.* |
Config DB ClusterNode.RedundancyRole + ServiceLevelBase. |
Validation
- Bootstrap: the process fails fast on missing required keys in
Program.cs(e.g.Node:NodeId,Node:ClusterId,Node:ConfigDbConnectionStringall throwInvalidOperationExceptionif unset). - Authoritative:
DraftValidationServiceruns on every save;sp_ValidateDraftruns as part ofsp_PublishGenerationso an invalid draft cannot reach any node.