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>
This commit is contained in:
@@ -1,106 +1,113 @@
|
||||
# Galaxy Repository — Component Requirements
|
||||
# Galaxy Driver — Galaxy Repository Requirements
|
||||
|
||||
Parent: [HLR-002](HighLevelReqs.md#hlr-002-galaxy-hierarchy-as-opc-ua-address-space), [HLR-005](HighLevelReqs.md#hlr-005-dynamic-address-space-rebuild)
|
||||
> **Revision** — Refreshed 2026-04-19 for the OtOpcUa v2 multi-driver platform (task #205). Scope clarified: this document is **Galaxy-driver-specific**. Galaxy is one of seven drivers in the OtOpcUa platform; the requirements below describe the SQL-side of the Galaxy driver (hierarchy/attribute/change-detection queries against the ZB database) that backs the Galaxy driver's `ITagDiscovery.DiscoverAsync` and `IRediscoverable` implementations. All Galaxy-specific SQL runs inside `OtOpcUa.Galaxy.Host` (.NET 4.8 x86 Windows service); the in-server `Driver.Galaxy.Proxy` calls it over a named pipe. For platform-wide tag discovery requirements see `OpcUaServerReqs.md` OPC-002. For deeper spec see `docs/GalaxyRepository.md` and `docs/v2/driver-specs.md`.
|
||||
|
||||
Parent: [HLR-002](HighLevelReqs.md#hlr-002-multi-driver-plug-in-model), [HLR-003](HighLevelReqs.md#hlr-003-address-space-composition-per-namespace), [HLR-006](HighLevelReqs.md#hlr-006-change-detection-and-rediscovery)
|
||||
|
||||
Driver scope: Galaxy only. Namespace kind: `SystemPlatform`.
|
||||
|
||||
## GR-001: Hierarchy Extraction
|
||||
|
||||
The system shall query the Galaxy Repository database to extract all deployed objects with their parent-child containment relationships, contained names, and tag names.
|
||||
The Galaxy driver's `ITagDiscovery.DiscoverAsync` implementation shall query the ZB Galaxy Repository database to extract all deployed objects with their parent-child containment relationships, contained names, and tag names.
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
- Executes `queries/hierarchy.sql` against the ZB database.
|
||||
- Executes `queries/hierarchy.sql` against the ZB database from within `OtOpcUa.Galaxy.Host`.
|
||||
- Returns a list of objects with: `gobject_id`, `tag_name`, `contained_name`, `browse_name`, `parent_gobject_id`, `is_area`.
|
||||
- Objects with `parent_gobject_id = 0` are children of the root ZB node.
|
||||
- Objects with `parent_gobject_id = 0` become children of the root ZB node inside the `SystemPlatform` namespace.
|
||||
- Only deployed, non-template objects matching the category filter (areas, engines, user-defined objects, etc.) are returned.
|
||||
- Query completes within 10 seconds on a typical Galaxy (hundreds of objects). Log a Warning if it takes longer.
|
||||
- Query completes within 10 seconds on a typical Galaxy (hundreds of objects). Log Warning if it takes longer.
|
||||
|
||||
### Details
|
||||
|
||||
- Results are ordered by `parent_gobject_id, tag_name` for deterministic tree building.
|
||||
- If the query returns zero rows, log a Warning (Galaxy may have no deployed objects, or the DB connection may be misconfigured).
|
||||
- Orphan detection: if a row references a `parent_gobject_id` that does not exist in the result set and is not 0, log a Warning and skip that node.
|
||||
- Empty result → Warning logged (Galaxy may have no deployed objects, or the DB connection may be misconfigured).
|
||||
- Orphan detection: a row referencing a non-existent `parent_gobject_id` (and not 0) is skipped with a Warning.
|
||||
- Streamed to the core via `IAddressSpaceBuilder.AddFolder` / `AddObject` calls over the Galaxy named pipe; no in-memory full-tree buffering on the Host side.
|
||||
|
||||
---
|
||||
|
||||
## GR-002: Attribute Extraction
|
||||
|
||||
The system shall query user-defined (dynamic) attributes for deployed objects, including data type, array flag, and array dimensions.
|
||||
The Galaxy driver shall query user-defined (dynamic) attributes for deployed objects, including data type, array flag, and array dimensions.
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
- Executes `queries/attributes.sql` using the template chain CTE to resolve inherited attributes.
|
||||
- Returns: `gobject_id`, `tag_name`, `attribute_name`, `full_tag_reference`, `mx_data_type`, `is_array`, `array_dimension`, `security_classification`.
|
||||
- Attributes starting with `_` are filtered out by the query.
|
||||
- `array_dimension` is correctly extracted from the `mx_value` hex bytes (positions 13-16, little-endian uint16).
|
||||
- `array_dimension` is extracted from the `mx_value` hex bytes (positions 13-16, little-endian uint16).
|
||||
|
||||
### Details
|
||||
|
||||
- CTE recursion depth is limited to 10 levels (per the query). This is sufficient for Galaxy template hierarchies.
|
||||
- If `mx_data_type` is null or not in the known set (1-8, 13-16), default to String.
|
||||
- If `gobject_id` from an attribute row does not match any hierarchy object, skip that attribute (object may not be deployed).
|
||||
- CTE recursion depth is limited to 10 levels.
|
||||
- `mx_data_type` not in the known set (1-8, 13-16) defaults to String.
|
||||
- `gobject_id` that doesn't match a hierarchy object is skipped (object may not be deployed).
|
||||
- Each emitted attribute is reported via `DriverAttributeInfo` to the core through `IAddressSpaceBuilder.AddVariable`.
|
||||
|
||||
---
|
||||
|
||||
## GR-003: Change Detection
|
||||
## GR-003: Change Detection and IRediscoverable
|
||||
|
||||
The system shall poll `galaxy.time_of_last_deploy` at a configurable interval to detect when a new deployment has occurred.
|
||||
The Galaxy driver shall implement `IRediscoverable` by polling `galaxy.time_of_last_deploy` on a configurable interval to detect when a new deployment has occurred.
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
- Polls `SELECT time_of_last_deploy FROM galaxy` at a configurable interval (`GalaxyRepository:ChangeDetectionIntervalSeconds`, default 30 seconds).
|
||||
- Polls `SELECT time_of_last_deploy FROM galaxy` at a configurable interval (`Galaxy:ChangeDetectionIntervalSeconds`, default 30 seconds).
|
||||
- Compares the returned timestamp to the last known value stored in memory.
|
||||
- If different, triggers a rebuild (re-run hierarchy + attributes queries, notify OPC UA server).
|
||||
- First poll after startup always triggers an initial build.
|
||||
- If the query fails (SQL timeout, connection error), log Warning and retry at next interval. Do not trigger a rebuild on failure.
|
||||
- If different, raises the `IRediscoverable.RediscoveryNeeded` signal so the core re-runs `ITagDiscovery.DiscoverAsync` and surgically rebuilds the Galaxy namespace subtree (per OPC-017).
|
||||
- First poll after startup always triggers an initial discovery.
|
||||
- Query failure → Warning logged; no rediscovery triggered; retry at next interval.
|
||||
|
||||
### Details
|
||||
|
||||
- Polling runs on a background timer thread, not blocking the STA thread.
|
||||
- `time_of_last_deploy` is a datetime column. Compare using exact equality (not range).
|
||||
- Polling runs on a background `Task` inside `OtOpcUa.Galaxy.Host`, not on the STA message-pump thread.
|
||||
- `time_of_last_deploy` is a `datetime` column; compared using exact equality (not a range).
|
||||
- Signal delivery to the Proxy happens via a server-push message on the Galaxy named pipe.
|
||||
|
||||
---
|
||||
|
||||
## GR-004: Rebuild on Change
|
||||
## GR-004: Rediscovery Data Flow
|
||||
|
||||
When a deployment change is detected, the system shall re-query hierarchy and attributes and provide the updated structure to the OPC UA server for address space rebuild.
|
||||
On a deployment change, the Galaxy driver shall re-query hierarchy + attributes and stream the updated structure to the core for surgical namespace rebuild.
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
- On change detection, re-query both hierarchy and attributes.
|
||||
- Provide the new data set to the OPC UA server component for address space replacement.
|
||||
- Log at Information level: "Galaxy deployment change detected. Rebuilding address space. ({ObjectCount} objects, {AttributeCount} attributes)".
|
||||
- Log total rebuild time at Information level.
|
||||
- If the re-query fails, log Error and keep the existing address space (do not clear it).
|
||||
- On change signal, re-run `GR-001` (hierarchy) and `GR-002` (attributes) queries.
|
||||
- Stream the new tree to the core via `IAddressSpaceBuilder` over the named pipe.
|
||||
- Log at Information level: `"Galaxy deployment change detected. Rebuilding. ({ObjectCount} objects, {AttributeCount} attributes)"`.
|
||||
- Log total rediscovery duration at Information level.
|
||||
- On re-query failure: Error logged; existing Galaxy subtree is retained.
|
||||
|
||||
### Details
|
||||
|
||||
- Rebuild is not atomic from the DB perspective — hierarchy and attributes are two separate queries. This is acceptable; deployment is an infrequent operation.
|
||||
- Raise an event/callback that the OPC UA server subscribes to: `OnGalaxyChanged(hierarchyData, attributeData)`.
|
||||
- Rediscovery is not atomic from the DB perspective — hierarchy and attributes are two separate queries. Acceptable; Galaxy deployment is an infrequent operation.
|
||||
- The core owns the diff/surgical apply per OPC-017; the Galaxy driver only streams the new authoritative tree.
|
||||
|
||||
---
|
||||
|
||||
## GR-005: Connection Configuration
|
||||
|
||||
Database connection parameters shall be configurable via appsettings.json (connection string using Windows Authentication by default).
|
||||
Galaxy DB connection parameters shall be configurable via environment variables passed from the `OtOpcUa.Galaxy.Host` supervisor at spawn time.
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
- Connection string in `appsettings.json` under `GalaxyRepository:ConnectionString`.
|
||||
- Default: `Server=localhost;Database=ZB;Integrated Security=true` (Windows Auth).
|
||||
- ADO.NET `SqlConnection` used for queries (.NET Framework 4.8 built-in).
|
||||
- Connection string via `OTOPCUA_GALAXY_ZB_CONN` environment variable.
|
||||
- Default: `Server=localhost;Database=ZB;Integrated Security=True;TrustServerCertificate=True;Encrypt=False;` (Windows Auth).
|
||||
- ADO.NET `SqlConnection` used for queries (.NET Framework 4.8).
|
||||
- Connection is opened per-query (not kept open). Connection pooling handles efficiency.
|
||||
- If the initial connection test at startup fails, log Error with the connection string and continue attempting (change detection polls will keep retrying).
|
||||
- If the initial connection test at startup fails, log Error with the connection string sanitized and continue attempting (change-detection polls keep retrying).
|
||||
|
||||
### Details
|
||||
|
||||
- Command timeout: configurable via `GalaxyRepository:CommandTimeoutSeconds`, default 30 seconds.
|
||||
- No ORM. Raw ADO.NET with `SqlCommand` and `SqlDataReader`. SQL text is embedded as constants (not dynamically constructed).
|
||||
- Command timeout: `Galaxy:CommandTimeoutSeconds` in Config DB driver JSON (default 30 seconds).
|
||||
- No ORM. Raw ADO.NET with `SqlCommand` and `SqlDataReader`. SQL text embedded as constants.
|
||||
|
||||
---
|
||||
|
||||
## GR-006: Query Safety
|
||||
|
||||
All SQL queries shall be static read-only SELECT statements. No writes to the Galaxy Repository database.
|
||||
All Galaxy SQL queries shall be static read-only SELECT statements. No writes to the Galaxy Repository database.
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
@@ -112,10 +119,23 @@ All SQL queries shall be static read-only SELECT statements. No writes to the Ga
|
||||
|
||||
## GR-007: Startup Validation
|
||||
|
||||
On startup, the Galaxy Repository component shall validate database connectivity.
|
||||
On startup, the Galaxy driver's DB component inside `OtOpcUa.Galaxy.Host` shall validate database connectivity.
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
- Execute a simple test query (`SELECT 1`) against the configured database.
|
||||
- If the database is unreachable, log an Error but do not prevent service startup.
|
||||
- The service runs in degraded mode (empty address space) until the database becomes available and the next change detection poll succeeds.
|
||||
- Execute a simple test query (`SELECT 1`) against the configured Galaxy DB.
|
||||
- If the database is unreachable, log Error but do not prevent Host startup.
|
||||
- The Galaxy driver runs in degraded mode (empty SystemPlatform namespace) until the database becomes available and the next change-detection poll succeeds.
|
||||
- In degraded mode the Galaxy driver instance reports `DriverHealth.Unavailable`, causing its Polly circuit state to be open until the first successful discovery.
|
||||
|
||||
---
|
||||
|
||||
## GR-008: Capability Wrapping
|
||||
|
||||
All calls into the Galaxy DB component from the Proxy side shall route through `CapabilityInvoker.InvokeAsync(DriverCapability.Discover, …)`.
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
- `Driver.Galaxy.Proxy.DiscoverAsync` is a thin capability-invoker call that sends a MessagePack request over the named pipe to the Host's DB component.
|
||||
- Roslyn analyzer **OTOPCUA0001** validates there are no direct discovery calls bypassing the invoker.
|
||||
- Polly pipeline for `DriverCapability.Discover` on the Galaxy driver instance carries Timeout + Retry + CircuitBreaker.
|
||||
|
||||
Reference in New Issue
Block a user