docs: render architecture & flow diagrams as draw.io charts
Replace ASCII-art diagrams across the README and docs/ with editable .drawio sources plus exported PNGs, so the diagrams render clearly in rendered markdown and can be maintained/regenerated instead of being hand-edited as fragile text art. Non-diagram blocks (code, folder trees, UI wireframes) were left as text.
@@ -39,28 +39,8 @@ Both endpoints use the same `Protocol`. EF Core migration renames `Configuration
|
||||
|
||||
The `DataConnectionActor` Reconnecting state is extended:
|
||||
|
||||
```
|
||||
Connected
|
||||
│ disconnect detected
|
||||
▼
|
||||
Push bad quality to all subscribers
|
||||
│
|
||||
▼
|
||||
Retry active endpoint (5s interval)
|
||||
│ failure
|
||||
▼
|
||||
_consecutiveFailures++
|
||||
│
|
||||
├─ < FailoverRetryCount → retry same endpoint
|
||||
│
|
||||
├─ ≥ FailoverRetryCount AND backup exists
|
||||
│ → dispose adapter, switch _activeEndpoint, reset counter
|
||||
│ → create fresh adapter with other config
|
||||
│ → attempt connect
|
||||
│
|
||||
└─ ≥ FailoverRetryCount AND no backup
|
||||
→ keep retrying indefinitely (current behavior)
|
||||
```
|
||||

|
||||
<!-- source: diagrams/primary-backup-failover-state-machine.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
**On successful reconnect (either endpoint):**
|
||||
1. Reset `_consecutiveFailures = 0`
|
||||
|
||||
@@ -32,34 +32,8 @@ We want a strongly-typed model for OPC UA endpoint configuration, a validator th
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────┐
|
||||
│ ZB.MOM.WW.ScadaBridge.Commons │
|
||||
│ Types/DataConnections/ │
|
||||
│ OpcUaEndpointConfig.cs (POCO) │
|
||||
│ OpcUaHeartbeatConfig.cs (POCO) │
|
||||
│ OpcUaSecurityMode.cs (enum) │
|
||||
│ Validators/ │
|
||||
│ OpcUaEndpointConfigValidator.cs │
|
||||
│ Serialization/ │
|
||||
│ OpcUaEndpointConfigSerializer.cs │
|
||||
└──────────────────────────────────────┘
|
||||
▲
|
||||
│ (referenced by both)
|
||||
┌───────┴────────────────────────┐
|
||||
▼ ▼
|
||||
┌──────────────────────────┐ ┌────────────────────────────┐
|
||||
│ ZB.MOM.WW.ScadaBridge.CentralUI │ │ ZB.MOM.WW.ScadaBridge.SiteRuntime │
|
||||
│ Components/Forms/ │ │ Actors/ │
|
||||
│ OpcUaEndpointEditor │ │ DeploymentManagerActor │
|
||||
│ .razor (shared) │ │ (passes raw JSON to │
|
||||
│ │ │ DataConnectionFactory)│
|
||||
│ Pages/Admin/ │ │ │
|
||||
│ DataConnectionForm │ │ DataConnections.OpcUa/ │
|
||||
│ .razor │ │ OpcUaDataConnection.cs │
|
||||
└──────────────────────────┘ │ (consumes typed model) │
|
||||
└────────────────────────────┘
|
||||
```
|
||||

|
||||
<!-- source: diagrams/opcua-config-model-architecture.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
Both sides deserialize from `DataConnection.PrimaryConfiguration` / `BackupConfiguration` strings into the same `OpcUaEndpointConfig` instance. The DB column type does not change.
|
||||
|
||||
|
||||
@@ -17,29 +17,8 @@ A sibling `docker-env2/` directory with `deploy.sh` / `teardown.sh` / `seed-site
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
(host machine)
|
||||
|
||||
Primary stack (already existing — unchanged) Env2 stack (new)
|
||||
┌────────────────────────────────────┐ ┌──────────────────────────────┐
|
||||
│ Traefik :9000 ◄── 9001/9002 UI │ │ Traefik :9100 ◄── 9101/9102 UI│
|
||||
│ Central A/B (9011/9012 Akka) │ │ Central A/B (9111/9112 Akka) │
|
||||
│ Site-A/B/C (9021..9044) │ │ Site-X (9121/9122 Akka, │
|
||||
└─────────────┬──────────────────────┘ │ 9123/9124 gRPC) │
|
||||
│ └──────────┬───────────────────┘
|
||||
│ │
|
||||
▼ scadabridge-net (shared bridge network) ◄──────┘
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ scadabridge-mssql ScadaBridgeConfig (primary DB) │
|
||||
│ ScadaBridgeMachineData (primary DB) │
|
||||
│ ScadaBridgeConfig2 (env2 DB) ← new │
|
||||
│ ScadaBridgeMachineData2(env2 DB) ← new │
|
||||
│ scadabridge-ldap (shared — same test users) │
|
||||
│ scadabridge-smtp (shared Mailpit) │
|
||||
│ scadabridge-opcua (shared) │
|
||||
│ scadabridge-restapi (shared) │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||

|
||||
<!-- source: diagrams/env2-architecture-overview.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
Both stacks attach to the same `scadabridge-net` Docker bridge so env2's app containers can reach the infra services by container hostname (`scadabridge-mssql`, `scadabridge-ldap`, etc.). Akka clusters are independent — each side's `SeedNodes` lists only its own central nodes, so they never gossip-merge despite sharing the network.
|
||||
|
||||
|
||||
@@ -14,19 +14,8 @@
|
||||
|
||||
## Task Dependency Graph
|
||||
|
||||
```
|
||||
T0 ─┐ ┐
|
||||
T1 ─┤ (all independent, all │
|
||||
T2 ─┤ parallelizable, all ├─► T10 (manual smoke test)
|
||||
T3 ─┤ ready from the start) │
|
||||
T4 ─┤ │
|
||||
T6 ─┤ │
|
||||
T7 ─┤ │
|
||||
T8 ─┤ │
|
||||
T9 ─┘ │
|
||||
│
|
||||
T0,T4 ──► T5 (lifecycle scripts) ─────────┘
|
||||
```
|
||||

|
||||
<!-- source: diagrams/env2-task-dependency-graph.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
T10 is the only task that requires all of T0–T9 done. Everything else can run in parallel.
|
||||
|
||||
|
||||
@@ -18,27 +18,8 @@
|
||||
|
||||
## Section 1 — Architecture
|
||||
|
||||
```
|
||||
[Blazor Server browser]
|
||||
│ SignalR
|
||||
▼
|
||||
[CentralUI: InstanceConfigure.razor]
|
||||
│ opens
|
||||
▼
|
||||
[CentralUI: <OpcUaBrowserDialog/>]
|
||||
│ uses
|
||||
▼
|
||||
[CentralUI: IOpcUaBrowseService] ── implementation calls
|
||||
│
|
||||
▼
|
||||
[CommunicationService.SendCommandToSiteAsync<BrowseOpcUaNodeResult>(siteId, BrowseOpcUaNodeCommand)]
|
||||
│ ClusterClient Ask, ManagementEnvelope { User, Command, CorrelationId }
|
||||
▼
|
||||
[Site: CentralCommunicationActor → DataConnectionManagerActor]
|
||||
│ dispatches to IBrowsableDataConnection (RealOpcUaClient)
|
||||
▼
|
||||
[OPC UA server] ◄── OPC Foundation .NET SDK Browse service
|
||||
```
|
||||

|
||||
<!-- source: diagrams/opcua-tag-browser-architecture.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
Three slices, top-to-bottom:
|
||||
1. **Data model.** Add a per-instance OPC UA address override (new column on `InstanceConnectionBinding`).
|
||||
@@ -164,25 +145,8 @@ Returning failure inside `BrowseOpcUaNodeResult` (rather than exceptions across
|
||||
|
||||
**Wire flow.**
|
||||
|
||||
```
|
||||
CentralUI.OpcUaBrowseService.BrowseChildrenAsync(siteId, connId, parent)
|
||||
→ CommunicationService.SendCommandToSiteAsync<BrowseOpcUaNodeResult>(
|
||||
siteId,
|
||||
new BrowseOpcUaNodeCommand(connId, parent))
|
||||
→ ManagementEnvelope { User, Command, CorrelationId } over ClusterClient
|
||||
→ Site: CentralCommunicationActor unwraps envelope
|
||||
→ Site: DataConnectionManagerActor receives BrowseOpcUaNodeCommand
|
||||
- Look up IDataConnection by Id
|
||||
- if not found → ConnectionNotFound
|
||||
- if !(conn is IBrowsableDataConnection) → NotBrowsable
|
||||
- else await conn.BrowseChildrenAsync(ParentNodeId, ct)
|
||||
- Catch ConnectionNotConnectedException → ConnectionNotConnected
|
||||
- Catch OperationCanceledException → Timeout
|
||||
- Catch ServiceResultException → ServerError + verbatim msg
|
||||
- Else success: BrowseOpcUaNodeResult(children, truncated, null)
|
||||
→ Reply travels back via CentralCommunicationActor → CommunicationService
|
||||
→ returned to CentralUI page
|
||||
```
|
||||

|
||||
<!-- source: diagrams/opcua-tag-browser-command-flow.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
Handler lives in the **DCL coordinator actor** (the same actor that owns the per-connection `IDataConnection` instances) — keeps lifecycle and browse co-located so we don't race against reconnect.
|
||||
|
||||
|
||||
@@ -16,23 +16,8 @@
|
||||
|
||||
## Task dependency overview
|
||||
|
||||
```
|
||||
T1 ─┬─ T2 ─┬─ T17 (computed AlarmActor enrich)
|
||||
│ ├─ T18 (proto) ── T19 (grpc mapping) ── T23 (DebugView)
|
||||
T3 ─┼─ T10 (DCL actor)
|
||||
├─ T11 (OPC UA adapter)
|
||||
└─ T12 (MxGateway adapter)
|
||||
T4 ─┬─ T5 ── T6 ── T21 (mgmt handlers)
|
||||
├─ T7 (migration)
|
||||
├─ T8 ── T9 (validation)
|
||||
└─ T20 ─┬─ T21 ── T26 (seed)
|
||||
├─ T22 (CLI)
|
||||
├─ T24 (template UI)
|
||||
└─ T25 (instance UI)
|
||||
T13, T14 ──┐
|
||||
T1,T2,T3,T4(Resolved),T13,T14 ── T15 (NativeAlarmActor) ── T16 (InstanceActor wiring)
|
||||
(everything) ── T27 (docs) , T28 (integration/manual verify)
|
||||
```
|
||||

|
||||
<!-- source: diagrams/native-alarms-task-dependency.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="env2arch" name="Env2 Architecture">
|
||||
<mxGraphModel dx="1400" dy="900" grid="1" gridSize="10" guides="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="900" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- Host machine container -->
|
||||
<mxCell id="host" value="host machine" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;strokeColor=#666666;verticalAlign=top;fontStyle=2;fontColor=#666666;dashed=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="40" width="1020" height="800" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Primary stack -->
|
||||
<mxCell id="primary" value="Primary stack (already existing — unchanged)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;fontStyle=1;align=center;spacingTop=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="100" width="420" height="220" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="p-traefik" value="Traefik :9000 ◄── 9001/9002 UI" style="whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#6c8ebf;align=left;spacingLeft=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="100" y="160" width="380" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="p-central" value="Central A/B (9011/9012 Akka)" style="whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#6c8ebf;align=left;spacingLeft=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="100" y="210" width="380" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="p-site" value="Site-A/B/C (9021..9044)" style="whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#6c8ebf;align=left;spacingLeft=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="100" y="260" width="380" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Env2 stack -->
|
||||
<mxCell id="env2" value="Env2 stack (new)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;verticalAlign=top;fontStyle=1;align=center;spacingTop=6;" vertex="1" parent="1">
|
||||
<mxGeometry x="600" y="100" width="420" height="220" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e-traefik" value="Traefik :9100 ◄── 9101/9102 UI" style="whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#82b366;align=left;spacingLeft=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="620" y="160" width="380" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e-central" value="Central A/B (9111/9112 Akka)" style="whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#82b366;align=left;spacingLeft=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="620" y="210" width="380" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e-site" value="Site-X (9121/9122 Akka, 9123/9124 gRPC)" style="whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#82b366;align=left;spacingLeft=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="620" y="260" width="380" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Shared network bar -->
|
||||
<mxCell id="net" value="scadabridge-net (shared bridge network)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="400" width="940" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Infra container -->
|
||||
<mxCell id="infra" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="500" width="860" height="300" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- MSSQL block -->
|
||||
<mxCell id="mssql" value="scadabridge-mssql" style="shape=cylinder3;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;verticalAlign=top;fontStyle=1;spacingTop=4;" vertex="1" parent="1">
|
||||
<mxGeometry x="150" y="530" width="160" height="240" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="db1" value="ScadaBridgeConfig (primary DB)" style="whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;align=left;spacingLeft=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="340" y="540" width="300" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="db2" value="ScadaBridgeMachineData (primary DB)" style="whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;align=left;spacingLeft=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="340" y="590" width="300" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="db3" value="ScadaBridgeConfig2 (env2 DB) ← new" style="whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;align=left;spacingLeft=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="340" y="640" width="300" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="db4" value="ScadaBridgeMachineData2 (env2 DB) ← new" style="whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;align=left;spacingLeft=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="340" y="690" width="300" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Shared commodity infra services -->
|
||||
<mxCell id="ldap" value="scadabridge-ldap (shared — same test users)" style="whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;align=left;spacingLeft=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="530" width="280" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="smtp" value="scadabridge-smtp (shared Mailpit)" style="whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;align=left;spacingLeft=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="580" width="280" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="opcua" value="scadabridge-opcua (shared)" style="whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;align=left;spacingLeft=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="630" width="280" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="restapi" value="scadabridge-restapi (shared)" style="whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;align=left;spacingLeft=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="680" width="280" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Edges: primary -> net, env2 -> net -->
|
||||
<mxCell id="ep" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;" edge="1" parent="1" source="primary" target="net">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ee" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#82b366;" edge="1" parent="1" source="env2" target="net">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<!-- net -> infra -->
|
||||
<mxCell id="eni" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#d6b656;" edge="1" parent="1" source="net" target="infra">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 317 KiB |
@@ -0,0 +1,98 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="env2dag" name="Env2 Task Dependency Graph">
|
||||
<mxGraphModel dx="1200" dy="900" grid="1" gridSize="10" guides="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1000" pageHeight="800" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- Independent / parallelizable group label -->
|
||||
<mxCell id="grpLabel" value="all independent, all parallelizable, all ready from the start" style="text;html=1;align=center;verticalAlign=middle;fontStyle=2;fontColor=#666666;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="30" width="300" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Independent task nodes (T0..T9 minus T5) -->
|
||||
<mxCell id="t0" value="T0" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="80" width="80" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t1" value="T1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="130" width="80" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t2" value="T2" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="180" width="80" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t3" value="T3" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="230" width="80" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t4" value="T4" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="280" width="80" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t6" value="T6" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="330" width="80" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t7" value="T7" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="380" width="80" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t8" value="T8" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="430" width="80" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t9" value="T9" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="480" width="80" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- T5: lifecycle scripts (fed by T0 and T4) -->
|
||||
<mxCell id="t5" value="T5 lifecycle scripts" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="440" y="430" width="160" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- T10: manual smoke test -->
|
||||
<mxCell id="t10" value="T10 manual smoke test" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="780" y="255" width="160" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Edges: each independent task -> T10 -->
|
||||
<mxCell id="e0" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="t0" target="t10">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="t1" target="t10">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="t2" target="t10">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="t3" target="t10">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="t6" target="t10">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="t7" target="t10">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="t8" target="t10">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="t9" target="t10">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- T0,T4 -> T5 -->
|
||||
<mxCell id="e05" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#d79b00;" edge="1" parent="1" source="t0" target="t5">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e45" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#d79b00;" edge="1" parent="1" source="t4" target="t5">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- T5 -> T10 -->
|
||||
<mxCell id="e510" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#d79b00;" edge="1" parent="1" source="t5" target="t10">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Note -->
|
||||
<mxCell id="note" value="T10 is the only task that requires all of T0–T9 done. Everything else runs in parallel." style="text;html=1;align=left;verticalAlign=middle;fontStyle=2;fontColor=#666666;" vertex="1" parent="1">
|
||||
<mxGeometry x="640" y="360" width="320" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 102 KiB |
@@ -0,0 +1,41 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="perwp" name="Per-Work-Package Execution">
|
||||
<mxGraphModel dx="900" dy="1100" grid="1" gridSize="10" guides="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="700" pageHeight="1200" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<mxCell id="s1" value="1. READ the WP description and acceptance criteria" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;align=left;spacingLeft=12;verticalAlign=middle;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="180" y="40" width="380" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="s2" value="2. READ all traced requirements (HLR bullets, KDD, CD constraints) to understand intent" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;align=left;spacingLeft=12;verticalAlign=middle;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="180" y="130" width="380" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="s3" value="3. IMPLEMENT the WP • Write code • Write unit tests for acceptance criteria • Write negative tests for prohibition criteria" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;align=left;spacingLeft=12;verticalAlign=middle;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="180" y="230" width="380" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="s4" value="4. VERIFY acceptance criteria • Run tests: all must pass • Walk each acceptance criterion line by line • If a criterion cannot be verified yet (depends on a later WP), note it as "deferred to WP-N"" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;align=left;spacingLeft=12;verticalAlign=middle;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="180" y="370" width="380" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="s5" value="5. UPDATE the phase execution checklist • Mark WP as complete with date • Note any deferred criteria • Note any questions logged" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;align=left;spacingLeft=12;verticalAlign=middle;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="180" y="530" width="380" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="s6" value="6. COMMIT with message: "Phase N WP-M: <summary>"" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;align=left;spacingLeft=12;verticalAlign=middle;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="180" y="670" width="380" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Edges -->
|
||||
<mxCell id="e12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="s1" target="s2"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e23" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="s2" target="s3"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e34" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="s3" target="s4"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e45" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="s4" target="s5"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e56" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="s5" target="s6"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 257 KiB |
@@ -0,0 +1,41 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="channelbridge" name="Channel Bridging">
|
||||
<mxGraphModel dx="1000" dy="700" grid="1" gridSize="10" guides="1" arrows="1"
|
||||
fold="1" page="1" pageScale="1" pageWidth="900" pageHeight="640" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- Producer side: Akka Actor Thread(s) -->
|
||||
<mxCell id="akka" value="Akka Actor Thread(s)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=13;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="60" width="240" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Consumer side: gRPC Response Stream -->
|
||||
<mxCell id="grpc" value="gRPC Response Stream" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=13;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="560" y="60" width="240" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Channel box -->
|
||||
<mxCell id="channel" value="Channel<SiteStreamEvent> BoundedChannelOptions(1000) FullMode = DropOldest" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=13;fontStyle=1;verticalAlign=middle;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="280" width="400" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Producer writes into channel -->
|
||||
<mxCell id="write" value="channel.Writer.TryWrite(evt)" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;fontSize=12;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.25;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="akka" target="channel">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Channel read out to gRPC stream -->
|
||||
<mxCell id="read" value="await responseStream.WriteAsync(evt)" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;fontSize=12;exitX=0.75;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="channel" target="grpc">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Notes -->
|
||||
<mxCell id="note" value="• Bounded capacity (1000): prevents unbounded memory growth if the gRPC client is slow • DropOldest: matches the existing SiteStreamManager overflow strategy • ReadAllAsync: yields items as they arrive, naturally async" style="text;html=1;align=left;verticalAlign=middle;fontSize=11;fontColor=#666666;spacingLeft=4;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="450" width="720" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 133 KiB |
@@ -0,0 +1,83 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="statemachine" name="Reconnection State Machine">
|
||||
<mxGraphModel dx="1000" dy="800" grid="1" gridSize="10" guides="1" arrows="1"
|
||||
fold="1" page="1" pageScale="1" pageWidth="900" pageHeight="820" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- Streaming state -->
|
||||
<mxCell id="streaming" value="Streaming" style="rounded=1;arcSize=30;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=14;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="60" width="180" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="streamingNote" value="Normal state: gRPC stream active" style="text;html=1;align=left;verticalAlign=middle;fontSize=11;fontStyle=2;fontColor=#666666;" vertex="1" parent="1">
|
||||
<mxGeometry x="560" y="70" width="170" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Reconnecting state -->
|
||||
<mxCell id="reconnecting" value="Reconnecting" style="rounded=1;arcSize=30;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="240" width="180" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="reconnectingNote" value="try other node endpoint" style="text;html=1;align=left;verticalAlign=middle;fontSize=11;fontStyle=2;fontColor=#666666;" vertex="1" parent="1">
|
||||
<mxGeometry x="560" y="250" width="170" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Decision diamond -->
|
||||
<mxCell id="decide" value="reconnect result?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="380" y="400" width="140" height="90" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Schedule retry box -->
|
||||
<mxCell id="retry" value="schedule retry (5s backoff)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="100" y="410" width="170" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Terminated state -->
|
||||
<mxCell id="terminated" value="Terminated" style="rounded=1;arcSize=30;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=14;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="620" width="180" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="terminatedNote" value="notify consumer, stop actor" style="text;html=1;align=left;verticalAlign=middle;fontSize=11;fontStyle=2;fontColor=#666666;" vertex="1" parent="1">
|
||||
<mxGeometry x="560" y="630" width="170" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Transitions -->
|
||||
<mxCell id="t_stream_recon" value="gRPC stream error / keepalive timeout" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;fontSize=11;" edge="1" parent="1" source="streaming" target="reconnecting">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="t_recon_decide" value="" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;" edge="1" parent="1" source="reconnecting" target="decide">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- success -> Streaming -->
|
||||
<mxCell id="t_success" value="success" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;fontSize=11;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="decide" target="streaming">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="700" y="445" />
|
||||
<mxPoint x="700" y="90" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- failure (retry < max) -> schedule retry -->
|
||||
<mxCell id="t_retry" value="failure (retry < max)" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;fontSize=11;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="decide" target="retry">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- schedule retry -> Reconnecting (loop back) -->
|
||||
<mxCell id="t_loop" value="" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="retry" target="reconnecting">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="185" y="270" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- failure (retry >= max) -> Terminated -->
|
||||
<mxCell id="t_term" value="failure (retry >= max)" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;fontSize=11;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="decide" target="terminated">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 134 KiB |
@@ -0,0 +1,102 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="grpcarch" name="gRPC Streams Architecture">
|
||||
<mxGraphModel dx="1200" dy="900" grid="1" gridSize="10" guides="1" arrows="1"
|
||||
fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="1000" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- Column headers -->
|
||||
<mxCell id="hdrCentral" value="Central Cluster" style="text;html=1;align=center;verticalAlign=middle;fontSize=16;fontStyle=1;fontColor=#333333;" vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="30" width="280" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="hdrSite" value="Site Cluster" style="text;html=1;align=center;verticalAlign=middle;fontSize=16;fontStyle=1;fontColor=#333333;" vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="30" width="280" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ruleC" value="" style="line;strokeWidth=2;html=1;strokeColor=#6c8ebf;" vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="60" width="280" height="10" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ruleS" value="" style="line;strokeWidth=2;html=1;strokeColor=#d79b00;" vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="60" width="280" height="10" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- CENTRAL column -->
|
||||
<mxCell id="bridgeTop" value="DebugStreamBridgeActor" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=13;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="110" width="280" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- SITE column -->
|
||||
<mxCell id="instance" value="InstanceActor" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=13;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="110" width="280" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- ClusterClient command/control between bridge and instance -->
|
||||
<mxCell id="ccSub" value="SubscribeDebugView ►" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;dashed=1;fontSize=11;exitX=1;exitY=0.3;exitDx=0;exitDy=0;entryX=0;entryY=0.3;entryDx=0;entryDy=0;verticalAlign=bottom;labelBackgroundColor=#ffffff;" edge="1" parent="1" source="bridgeTop" target="instance">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="0" y="-8" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ccSnap" value="◄ DebugViewSnapshot" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;dashed=1;fontSize=11;exitX=0;exitY=0.7;exitDx=0;exitDy=0;entryX=1;entryY=0.7;entryDx=0;entryDy=0;verticalAlign=top;labelBackgroundColor=#ffffff;" edge="1" parent="1" source="instance" target="bridgeTop">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="0" y="8" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ccLabel" value="ClusterClient: command / control" style="text;html=1;align=center;verticalAlign=middle;fontSize=10;fontStyle=2;fontColor=#666666;" vertex="1" parent="1">
|
||||
<mxGeometry x="455" y="178" width="170" height="34" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Instance publishes -->
|
||||
<mxCell id="publishes" value="publishes AttributeValueChanged AlarmStateChanged" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="220" width="280" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="instPub" value="" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;" edge="1" parent="1" source="instance" target="publishes">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- gRPC server (site) -->
|
||||
<mxCell id="grpcServer" value="SiteStreamGrpcServer (Kestrel, on site)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=13;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="340" width="280" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="pub2srv" value="" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;" edge="1" parent="1" source="publishes" target="grpcServer">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="srvNote1" value="receives from SiteStreamManager" style="text;html=1;align=left;verticalAlign=middle;fontSize=10;fontStyle=2;fontColor=#666666;" vertex="1" parent="1">
|
||||
<mxGeometry x="970" y="345" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="srvNote2" value="filters by instance name" style="text;html=1;align=left;verticalAlign=middle;fontSize=10;fontStyle=2;fontColor=#666666;" vertex="1" parent="1">
|
||||
<mxGeometry x="970" y="375" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- gRPC client (central) -->
|
||||
<mxCell id="grpcClient" value="SiteStreamGrpcClient (per-site, on central)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=13;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="340" width="280" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- gRPC stream: server -> client -->
|
||||
<mxCell id="grpcStream" value="gRPC stream (HTTP/2)" style="edgeStyle=none;html=1;endArrow=block;rounded=0;strokeWidth=2;strokeColor=#82b366;fontSize=12;fontStyle=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="grpcServer" target="grpcClient">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="cliNote" value="reads from gRPC stream routes by correlationId" style="text;html=1;align=center;verticalAlign=middle;fontSize=10;fontStyle=2;fontColor=#666666;" vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="410" width="280" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- bridge (central, lower) -->
|
||||
<mxCell id="bridgeBottom" value="DebugStreamBridgeActor" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=13;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="460" width="280" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cli2bridge" value="" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;" edge="1" parent="1" source="grpcClient" target="bridgeBottom">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- SignalR / Blazor -->
|
||||
<mxCell id="signalr" value="SignalR Hub / Blazor UI" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=13;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="560" width="280" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bridge2signalr" value="" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;" edge="1" parent="1" source="bridgeBottom" target="signalr">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 216 KiB |
@@ -0,0 +1,158 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="nadag" name="Native Alarms Task Dependency">
|
||||
<mxGraphModel dx="1600" dy="1100" grid="1" gridSize="10" guides="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1500" pageHeight="1200" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- ============ Block 1: T1/T3 sources ============ -->
|
||||
<mxCell id="t1" value="T1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="60" width="90" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t3" value="T3" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="200" width="90" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- T2 and the DCL/adapter fan-out from T1+T3 -->
|
||||
<mxCell id="t2" value="T2" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="60" width="90" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t10" value="T10 DCL actor" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="180" width="140" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t11" value="T11 OPC UA adapter" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="240" width="140" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t12" value="T12 MxGateway adapter" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="300" width="140" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- T2 fan-out: T17, T18->T19->T23 -->
|
||||
<mxCell id="t17" value="T17 computed AlarmActor enrich" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1">
|
||||
<mxGeometry x="460" y="20" width="180" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t18" value="T18 proto" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1">
|
||||
<mxGeometry x="460" y="100" width="140" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t19" value="T19 grpc mapping" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="100" width="140" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t23" value="T23 DebugView" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1">
|
||||
<mxGeometry x="900" y="100" width="140" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- ============ Block 2: T4 source ============ -->
|
||||
<mxCell id="t4" value="T4" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="500" width="90" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- T4 fan-out -->
|
||||
<mxCell id="t5" value="T5" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="420" width="90" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t6" value="T6" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="400" y="420" width="90" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t7" value="T7 migration" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="480" width="120" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t8" value="T8" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="540" width="90" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t9" value="T9 validation" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
|
||||
<mxGeometry x="400" y="540" width="120" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t20" value="T20" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="640" width="90" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- T21: fed by both T6 and T20 -->
|
||||
<mxCell id="t21" value="T21 mgmt handlers" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
|
||||
<mxGeometry x="600" y="480" width="140" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t26" value="T26 seed" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
|
||||
<mxGeometry x="820" y="480" width="120" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- T20 fan-out (others) -->
|
||||
<mxCell id="t22" value="T22 CLI" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
|
||||
<mxGeometry x="460" y="620" width="120" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t24" value="T24 template UI" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
|
||||
<mxGeometry x="460" y="680" width="120" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t25" value="T25 instance UI" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
|
||||
<mxGeometry x="460" y="740" width="120" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- ============ Block 3: T13/T14 -> T15 -> T16 ============ -->
|
||||
<mxCell id="t13" value="T13" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="860" width="90" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t14" value="T14" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="920" width="90" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t15" value="T15 NativeAlarmActor" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="600" y="880" width="160" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t16" value="T16 InstanceActor wiring" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1">
|
||||
<mxGeometry x="820" y="880" width="160" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t15in" value="inputs to T15: T1, T2, T3, T4 (Resolved), T13, T14" style="text;html=1;align=left;verticalAlign=middle;fontStyle=2;fontColor=#666666;" vertex="1" parent="1">
|
||||
<mxGeometry x="180" y="880" width="380" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- ============ Block 4: everything -> T27, T28 ============ -->
|
||||
<mxCell id="t27" value="T27 docs" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1">
|
||||
<mxGeometry x="1060" y="980" width="140" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="t28" value="T28 integration / manual verify" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1">
|
||||
<mxGeometry x="1060" y="1040" width="200" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="evt" value="(everything) ──►" style="text;html=1;align=right;verticalAlign=middle;fontStyle=2;fontColor=#666666;" vertex="1" parent="1">
|
||||
<mxGeometry x="880" y="990" width="170" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- ============ Edges ============ -->
|
||||
<!-- T1 + T3 -> T2, T10, T11, T12 -->
|
||||
<mxCell id="b1t2a" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;" edge="1" parent="1" source="t1" target="t2"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="b1t10a" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;" edge="1" parent="1" source="t1" target="t10"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="b1t11a" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;" edge="1" parent="1" source="t1" target="t11"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="b1t12a" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;" edge="1" parent="1" source="t1" target="t12"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="b1t2b" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;" edge="1" parent="1" source="t3" target="t2"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="b1t10b" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;" edge="1" parent="1" source="t3" target="t10"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="b1t11b" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;" edge="1" parent="1" source="t3" target="t11"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="b1t12b" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#6c8ebf;" edge="1" parent="1" source="t3" target="t12"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
|
||||
<!-- T2 -> T17, T18; T18 -> T19 -> T23 -->
|
||||
<mxCell id="e_t2_17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#9673a6;" edge="1" parent="1" source="t2" target="t17"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e_t2_18" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#9673a6;" edge="1" parent="1" source="t2" target="t18"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e_18_19" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#9673a6;" edge="1" parent="1" source="t18" target="t19"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e_19_23" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#9673a6;" edge="1" parent="1" source="t19" target="t23"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
|
||||
<!-- T4 -> T5, T7, T8, T20 -->
|
||||
<mxCell id="e_4_5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#82b366;" edge="1" parent="1" source="t4" target="t5"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e_4_7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#82b366;" edge="1" parent="1" source="t4" target="t7"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e_4_8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#82b366;" edge="1" parent="1" source="t4" target="t8"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e_4_20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#82b366;" edge="1" parent="1" source="t4" target="t20"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
|
||||
<!-- T5 -> T6 -> T21; T8 -> T9 -->
|
||||
<mxCell id="e_5_6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#82b366;" edge="1" parent="1" source="t5" target="t6"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e_6_21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#82b366;" edge="1" parent="1" source="t6" target="t21"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e_8_9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#82b366;" edge="1" parent="1" source="t8" target="t9"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
|
||||
<!-- T20 -> T21, T22, T24, T25; T21 -> T26 -->
|
||||
<mxCell id="e_20_21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#82b366;" edge="1" parent="1" source="t20" target="t21"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e_20_22" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#82b366;" edge="1" parent="1" source="t20" target="t22"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e_20_24" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#82b366;" edge="1" parent="1" source="t20" target="t24"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e_20_25" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#82b366;" edge="1" parent="1" source="t20" target="t25"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e_21_26" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#82b366;" edge="1" parent="1" source="t21" target="t26"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
|
||||
<!-- T13, T14 -> T15 -> T16 -->
|
||||
<mxCell id="e_13_15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#d79b00;" edge="1" parent="1" source="t13" target="t15"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e_14_15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#d79b00;" edge="1" parent="1" source="t14" target="t15"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
<mxCell id="e_15_16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;strokeColor=#d79b00;" edge="1" parent="1" source="t15" target="t16"><mxGeometry relative="1" as="geometry" /></mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 238 KiB |
@@ -0,0 +1,105 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="arch" name="Config Model Architecture">
|
||||
<mxGraphModel dx="1200" dy="900" grid="1" gridSize="10" guides="1" arrows="1"
|
||||
fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="900" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- Commons container -->
|
||||
<mxCell id="commons" value="ZB.MOM.WW.ScadaBridge.Commons"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;fontStyle=1;verticalAlign=top;spacingTop=8;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="40" width="380" height="270" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Types/DataConnections group -->
|
||||
<mxCell id="types" value="Types/DataConnections/ OpcUaEndpointConfig.cs (POCO) OpcUaHeartbeatConfig.cs (POCO) OpcUaSecurityMode.cs (enum)"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=12;align=left;spacingLeft=10;verticalAlign=middle;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="380" y="80" width="340" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Validators group -->
|
||||
<mxCell id="validators" value="Validators/ OpcUaEndpointConfigValidator.cs"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=12;align=left;spacingLeft=10;verticalAlign=middle;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="380" y="190" width="340" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Serialization group -->
|
||||
<mxCell id="serialization" value="Serialization/ OpcUaEndpointConfigSerializer.cs"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=12;align=left;spacingLeft=10;verticalAlign=middle;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="380" y="250" width="340" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- CentralUI container -->
|
||||
<mxCell id="centralui" value="ZB.MOM.WW.ScadaBridge.CentralUI"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;fontStyle=1;verticalAlign=top;spacingTop=8;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="480" width="320" height="220" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="cui_forms" value="Components/Forms/ OpcUaEndpointEditor.razor (shared)"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=12;align=left;spacingLeft=10;verticalAlign=middle;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="140" y="520" width="280" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="cui_pages" value="Pages/Admin/ DataConnectionForm.razor"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=12;align=left;spacingLeft=10;verticalAlign=middle;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="140" y="600" width="280" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- SiteRuntime container -->
|
||||
<mxCell id="siteruntime" value="ZB.MOM.WW.ScadaBridge.SiteRuntime"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=14;fontStyle=1;verticalAlign=top;spacingTop=8;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="660" y="480" width="340" height="220" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="sr_actors" value="Actors/ DeploymentManagerActor (passes raw JSON to DataConnectionFactory)"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;align=left;spacingLeft=10;verticalAlign=middle;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="520" width="300" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="sr_dc" value="DataConnections.OpcUa/ OpcUaDataConnection.cs (consumes typed model)"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;align=left;spacingLeft=10;verticalAlign=middle;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="600" width="300" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- referenced-by edges: both sides reference Commons -->
|
||||
<mxCell id="ref_cui" value="referenced by"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;startArrow=none;fontSize=12;dashed=0;"
|
||||
edge="1" parent="1" source="commons" target="centralui">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="280" y="400" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ref_sr" value="referenced by"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;startArrow=none;fontSize=12;dashed=0;"
|
||||
edge="1" parent="1" source="commons" target="siteruntime">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="830" y="400" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- caption note -->
|
||||
<mxCell id="note" value="Both sides deserialize DataConnection.PrimaryConfiguration / BackupConfiguration into the same OpcUaEndpointConfig instance. The DB column type does not change."
|
||||
style="text;html=1;align=center;verticalAlign=middle;fontSize=12;fontStyle=2;fontColor=#555555;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="200" y="730" width="720" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 331 KiB |
@@ -0,0 +1,93 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="browserarch" name="Tag Browser Architecture">
|
||||
<mxGraphModel dx="1000" dy="1200" grid="1" gridSize="10" guides="1" arrows="1"
|
||||
fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1300" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- 1. Blazor Server browser -->
|
||||
<mxCell id="n1" value="Blazor Server browser"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=13;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="40" width="320" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- 2. CentralUI: InstanceConfigure.razor -->
|
||||
<mxCell id="n2" value="CentralUI: InstanceConfigure.razor"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=13;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="150" width="320" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- 3. CentralUI: <OpcUaBrowserDialog/> -->
|
||||
<mxCell id="n3" value="CentralUI: &lt;OpcUaBrowserDialog/&gt;"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=13;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="260" width="320" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- 4. CentralUI: IOpcUaBrowseService -->
|
||||
<mxCell id="n4" value="CentralUI: IOpcUaBrowseService"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=13;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="370" width="320" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- 5. CommunicationService.SendCommandToSiteAsync -->
|
||||
<mxCell id="n5" value="CommunicationService.SendCommandToSiteAsync<BrowseOpcUaNodeResult>(siteId, BrowseOpcUaNodeCommand)"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontSize=12;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="180" y="480" width="440" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- 6. Site: CentralCommunicationActor -> DataConnectionManagerActor -->
|
||||
<mxCell id="n6" value="Site: CentralCommunicationActor → DataConnectionManagerActor"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=13;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="200" y="600" width="400" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- 7. OPC UA server -->
|
||||
<mxCell id="n7" value="OPC UA server"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=13;fontStyle=1;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="710" width="240" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Edges with labels -->
|
||||
<mxCell id="e1" value="SignalR"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;"
|
||||
edge="1" parent="1" source="n1" target="n2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e2" value="opens"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;"
|
||||
edge="1" parent="1" source="n2" target="n3">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e3" value="uses"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;"
|
||||
edge="1" parent="1" source="n3" target="n4">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e4" value="implementation calls"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;"
|
||||
edge="1" parent="1" source="n4" target="n5">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e5" value="ClusterClient Ask ManagementEnvelope { User, Command, CorrelationId }"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;"
|
||||
edge="1" parent="1" source="n5" target="n6">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e6" value="dispatches to IBrowsableDataConnection (RealOpcUaClient) OPC Foundation .NET SDK Browse service"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;"
|
||||
edge="1" parent="1" source="n6" target="n7">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 205 KiB |
@@ -0,0 +1,155 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="cmdflow" name="Browse Command Flow">
|
||||
<mxGraphModel dx="1200" dy="1400" grid="1" gridSize="10" guides="1" arrows="1"
|
||||
fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="1500" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- Step 1: CentralUI.OpcUaBrowseService -->
|
||||
<mxCell id="s1" value="CentralUI.OpcUaBrowseService.BrowseChildrenAsync(siteId, connId, parent)"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=12;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="40" width="440" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Step 2: CommunicationService.SendCommandToSiteAsync -->
|
||||
<mxCell id="s2" value="CommunicationService.SendCommandToSiteAsync<BrowseOpcUaNodeResult>( siteId, new BrowseOpcUaNodeCommand(connId, parent))"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontSize=12;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="150" width="440" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Step 3: ManagementEnvelope over ClusterClient -->
|
||||
<mxCell id="s3" value="ManagementEnvelope { User, Command, CorrelationId } over ClusterClient"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontSize=12;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="160" y="270" width="360" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Step 4: Site: CentralCommunicationActor unwraps envelope -->
|
||||
<mxCell id="s4" value="Site: CentralCommunicationActor unwraps envelope"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="160" y="390" width="360" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Step 5: Site: DataConnectionManagerActor receives command -->
|
||||
<mxCell id="s5" value="Site: DataConnectionManagerActor receives BrowseOpcUaNodeCommand (DCL coordinator actor — owns the per-connection IDataConnection instances)"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="490" width="440" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Handler logic box (the bulleted sub-steps) -->
|
||||
<mxCell id="handler" value="Handler logic"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;fontStyle=1;verticalAlign=top;spacingTop=6;align=center;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="660" y="470" width="380" height="380" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="h_lookup" value="Look up IDataConnection by Id"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#d6b656;fontSize=11;align=left;spacingLeft=8;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="500" width="340" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="h_notfound" value="if not found → ConnectionNotFound"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=11;align=left;spacingLeft=8;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="540" width="340" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="h_notbrowsable" value="if !(conn is IBrowsableDataConnection) → NotBrowsable"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=11;align=left;spacingLeft=8;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="580" width="340" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="h_await" value="else await conn.BrowseChildrenAsync(ParentNodeId, ct)"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#d6b656;fontSize=11;align=left;spacingLeft=8;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="620" width="340" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="h_notconn" value="Catch ConnectionNotConnectedException → ConnectionNotConnected"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=11;align=left;spacingLeft=8;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="660" width="340" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="h_cancel" value="Catch OperationCanceledException → Timeout"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=11;align=left;spacingLeft=8;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="700" width="340" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="h_svc" value="Catch ServiceResultException → ServerError + verbatim msg"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=11;align=left;spacingLeft=8;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="740" width="340" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="h_success" value="Else success: BrowseOpcUaNodeResult(children, truncated, null)"
|
||||
style="rounded=0;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=11;align=left;spacingLeft=8;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="790" width="340" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- auth note -->
|
||||
<mxCell id="authnote" value="Auth: site-side handler validates ManagementEnvelope.User has the Design role; otherwise reply ServerError ("Not authorized to browse data connections")."
|
||||
style="text;html=1;align=left;verticalAlign=middle;fontSize=11;fontStyle=2;fontColor=#555555;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="570" width="430" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Reply path -->
|
||||
<mxCell id="r1" value="Reply travels back via CentralCommunicationActor → CommunicationService"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=12;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="900" width="440" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="r2" value="returned to CentralUI page"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=12;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="200" y="1010" width="280" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Main chain edges -->
|
||||
<mxCell id="e1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;"
|
||||
edge="1" parent="1" source="s1" target="s2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;"
|
||||
edge="1" parent="1" source="s2" target="s3">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;"
|
||||
edge="1" parent="1" source="s3" target="s4">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;"
|
||||
edge="1" parent="1" source="s4" target="s5">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- s5 -> handler logic -->
|
||||
<mxCell id="e5" value="processes"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;"
|
||||
edge="1" parent="1" source="s5" target="handler">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- handler -> reply -->
|
||||
<mxCell id="e6" value="result / failure"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;"
|
||||
edge="1" parent="1" source="handler" target="r1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="850" y="930" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="e7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;"
|
||||
edge="1" parent="1" source="r1" target="r2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 436 KiB |
@@ -0,0 +1,166 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="failover" name="Failover State Machine">
|
||||
<mxGraphModel dx="1200" dy="900" grid="1" gridSize="10" guides="1" arrows="1"
|
||||
fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="1300" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- Connected (start state) -->
|
||||
<mxCell id="connected" value="Connected"
|
||||
style="rounded=1;arcSize=40;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=14;fontStyle=1;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="420" y="40" width="200" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Push bad quality -->
|
||||
<mxCell id="badquality" value="Push bad quality to all subscribers"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=13;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="420" y="150" width="200" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Retry active endpoint -->
|
||||
<mxCell id="retry" value="Retry active endpoint (5s interval)"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=13;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="420" y="260" width="200" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- _consecutiveFailures++ -->
|
||||
<mxCell id="incr" value="_consecutiveFailures++"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=13;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="420" y="370" width="200" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Branch decision diamond -->
|
||||
<mxCell id="branch" value="Evaluate _consecutiveFailures"
|
||||
style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="450" y="470" width="140" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Branch 1: retry same endpoint -->
|
||||
<mxCell id="same" value="Retry same endpoint"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=13;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="495" width="200" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Branch 2: failover to backup -->
|
||||
<mxCell id="failover" value="Failover • dispose adapter, switch _activeEndpoint, reset counter • create fresh adapter with other config • attempt connect"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=12;align=left;spacingLeft=8;verticalAlign=middle;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="380" y="640" width="280" height="110" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Branch 3: no backup -->
|
||||
<mxCell id="nobackup" value="Keep retrying indefinitely (current behavior)"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=13;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="760" y="495" width="220" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Successful reconnect outcome -->
|
||||
<mxCell id="reconnect" value="On successful reconnect (either endpoint) 1. Reset _consecutiveFailures = 0 2. ReSubscribeAll() — re-create subscriptions on new adapter 3. Transition to Connected 4. Log failover event if endpoint changed 5. Report active endpoint in health metrics"
|
||||
style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;align=left;spacingLeft=10;verticalAlign=middle;"
|
||||
vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="830" width="320" height="140" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Edges -->
|
||||
<mxCell id="e1" value="disconnect detected"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;"
|
||||
edge="1" parent="1" source="connected" target="badquality">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;"
|
||||
edge="1" parent="1" source="badquality" target="retry">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e3" value="failure"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;"
|
||||
edge="1" parent="1" source="retry" target="incr">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;"
|
||||
edge="1" parent="1" source="incr" target="branch">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Branch 1 edge -->
|
||||
<mxCell id="b1" value="< FailoverRetryCount"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;"
|
||||
edge="1" parent="1" source="branch" target="same">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<!-- Branch 1 loops back to retry -->
|
||||
<mxCell id="b1loop" value="retry"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;dashed=1;"
|
||||
edge="1" parent="1" source="same" target="retry">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="180" y="285" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Branch 2 edge -->
|
||||
<mxCell id="b2" value="≥ FailoverRetryCount AND backup exists"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;"
|
||||
edge="1" parent="1" source="branch" target="failover">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Branch 3 edge -->
|
||||
<mxCell id="b3" value="≥ FailoverRetryCount AND no backup"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;"
|
||||
edge="1" parent="1" source="branch" target="nobackup">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<!-- no backup loops back to retry -->
|
||||
<mxCell id="b3loop" value="retry (round-robin n/a)"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;dashed=1;"
|
||||
edge="1" parent="1" source="nobackup" target="retry">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="870" y="285" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- failover -> attempt connect -> success -> reconnect -->
|
||||
<mxCell id="b2ok" value="connect succeeds"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;"
|
||||
edge="1" parent="1" source="failover" target="reconnect">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<!-- failover -> attempt connect -> failure -> back to retry loop -->
|
||||
<mxCell id="b2fail" value="connect fails (round-robin: primary → backup → primary...)"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;dashed=1;"
|
||||
edge="1" parent="1" source="failover" target="retry">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="700" y="695" />
|
||||
<mxPoint x="700" y="285" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- reconnect -> Connected -->
|
||||
<mxCell id="bdone" value="Transition to Connected"
|
||||
style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;"
|
||||
edge="1" parent="1" source="reconnect" target="connected">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="320" y="900" />
|
||||
<mxPoint x="320" y="65" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 366 KiB |
@@ -547,27 +547,8 @@ This section governs how implementation plans are executed. The goal is autonomo
|
||||
|
||||
For each work package, follow this sequence:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ 1. READ the WP description and acceptance criteria │
|
||||
│ 2. READ all traced requirements (HLR bullets, KDD, │
|
||||
│ CD constraints) to understand intent │
|
||||
│ 3. IMPLEMENT the WP │
|
||||
│ - Write code │
|
||||
│ - Write unit tests for acceptance criteria │
|
||||
│ - Write negative tests for prohibition criteria │
|
||||
│ 4. VERIFY acceptance criteria │
|
||||
│ - Run tests: all must pass │
|
||||
│ - Walk each acceptance criterion line by line │
|
||||
│ - If a criterion cannot be verified yet (depends │
|
||||
│ on a later WP), note it as "deferred to WP-N" │
|
||||
│ 5. UPDATE the phase execution checklist │
|
||||
│ - Mark WP as complete with date │
|
||||
│ - Note any deferred criteria │
|
||||
│ - Note any questions logged │
|
||||
│ 6. COMMIT with message: "Phase N WP-M: <summary>" │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||

|
||||
<!-- source: diagrams/generate-plans-per-work-package.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
### Mid-Phase Compliance Check
|
||||
|
||||
|
||||
@@ -23,29 +23,8 @@ gRPC server-streaming is an established pattern for real-time tag value updates;
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Central Cluster Site Cluster
|
||||
───────────── ────────────
|
||||
|
||||
DebugStreamBridgeActor InstanceActor
|
||||
│ │
|
||||
│── SubscribeDebugView ──► │ (ClusterClient: command/control)
|
||||
│◄── DebugViewSnapshot ── │
|
||||
│ │
|
||||
│ │ publishes AttributeValueChanged
|
||||
│ │ publishes AlarmStateChanged
|
||||
│ ▼
|
||||
SiteStreamGrpcClient ◄──── gRPC stream ───── SiteStreamGrpcServer
|
||||
(per-site, on central) (HTTP/2) (Kestrel, on site)
|
||||
│ │
|
||||
│ reads from gRPC stream │ receives from SiteStreamManager
|
||||
│ routes by correlationId │ filters by instance name
|
||||
▼ │
|
||||
DebugStreamBridgeActor │
|
||||
│ │
|
||||
▼ │
|
||||
SignalR Hub / Blazor UI │
|
||||
```
|
||||

|
||||
<!-- source: diagrams/grpc-streams-architecture.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
**Key separation**: ClusterClient handles subscribe/unsubscribe/snapshot (request-response). gRPC handles the ongoing value stream (server-streaming).
|
||||
|
||||
@@ -271,17 +250,8 @@ public override async Task SubscribeInstance(
|
||||
|
||||
`IServerStreamWriter<T>` is **not thread-safe**. Multiple Akka actors may publish events concurrently. The `Channel<SiteStreamEvent>` bridges these worlds:
|
||||
|
||||
```
|
||||
Akka Actor Thread(s) gRPC Response Stream
|
||||
│ ▲
|
||||
│ channel.Writer.TryWrite(evt) │ await responseStream.WriteAsync(evt)
|
||||
▼ │
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Channel<SiteStreamEvent> │
|
||||
│ BoundedChannelOptions(1000) │
|
||||
│ FullMode = DropOldest │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||

|
||||
<!-- source: diagrams/grpc-channel-bridging.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
- **Bounded capacity** (1000): prevents unbounded memory growth if the gRPC client is slow
|
||||
- **DropOldest**: matches the existing `SiteStreamManager` overflow strategy
|
||||
@@ -431,32 +401,8 @@ private void HandleGrpcStreamError(Exception ex)
|
||||
|
||||
### Reconnection State Machine (DebugStreamBridgeActor)
|
||||
|
||||
```
|
||||
┌──────────────────┐
|
||||
│ Streaming │ ◄── Normal state: gRPC stream active
|
||||
└────────┬─────────┘
|
||||
│ gRPC stream error / keepalive timeout
|
||||
▼
|
||||
┌──────────────────┐
|
||||
┌──► │ Reconnecting │ ── try other node endpoint
|
||||
│ └────────┬─────────┘
|
||||
│ │
|
||||
│ ┌────────┴─────────┐
|
||||
│ │ │
|
||||
│ success failure (retry < max)
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ Streaming schedule retry (5s backoff)
|
||||
│ │
|
||||
└───────────────────────┘
|
||||
│
|
||||
failure (retry >= max)
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ Terminated │ ── notify consumer, stop actor
|
||||
└──────────────────┘
|
||||
```
|
||||

|
||||
<!-- source: diagrams/grpc-reconnection-state-machine.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
### Summary
|
||||
|
||||
|
||||