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.
@@ -0,0 +1,90 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="topology" name="Topology">
|
||||
<mxGraphModel dx="1200" dy="800" grid="1" gridSize="10" guides="1" arrows="1"
|
||||
fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="800" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- Users -->
|
||||
<mxCell id="users" value="Users (HTTPS / LB)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=13;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="100" width="140" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Central Cluster container -->
|
||||
<mxCell id="central" value="Central Cluster" style="swimlane;whiteSpace=wrap;html=1;startSize=30;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;fontStyle=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="320" y="60" width="380" height="150" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="nodeA" value="Node A Active" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=13;fontStyle=1;" vertex="1" parent="central">
|
||||
<mxGeometry x="40" y="60" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="nodeB" value="Node B Standby" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=13;fontStyle=1;" vertex="1" parent="central">
|
||||
<mxGeometry x="220" y="60" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ab" value="" style="edgeStyle=none;html=1;startArrow=block;endArrow=block;rounded=0;" edge="1" parent="central" source="nodeA" target="nodeB">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Users -> Central -->
|
||||
<mxCell id="u2c" value="" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="users" target="nodeA">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Sites -->
|
||||
<mxCell id="site01" value="Site 01" style="swimlane;whiteSpace=wrap;html=1;startSize=26;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=13;fontStyle=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="60" y="420" width="220" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="s01a" value="A" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=13;fontStyle=1;" vertex="1" parent="site01">
|
||||
<mxGeometry x="30" y="50" width="70" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="s01b" value="B" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=13;fontStyle=1;" vertex="1" parent="site01">
|
||||
<mxGeometry x="120" y="50" width="70" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="site02" value="Site 02" style="swimlane;whiteSpace=wrap;html=1;startSize=26;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=13;fontStyle=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="320" y="420" width="220" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="s02a" value="A" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=13;fontStyle=1;" vertex="1" parent="site02">
|
||||
<mxGeometry x="30" y="50" width="70" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="s02b" value="B" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=13;fontStyle=1;" vertex="1" parent="site02">
|
||||
<mxGeometry x="120" y="50" width="70" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="site03" value="Site 03" style="swimlane;whiteSpace=wrap;html=1;startSize=26;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=13;fontStyle=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="580" y="420" width="220" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="s03a" value="A" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=13;fontStyle=1;" vertex="1" parent="site03">
|
||||
<mxGeometry x="30" y="50" width="70" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="s03b" value="B" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=13;fontStyle=1;" vertex="1" parent="site03">
|
||||
<mxGeometry x="120" y="50" width="70" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="siteN" value="Site N" style="swimlane;whiteSpace=wrap;html=1;startSize=26;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=13;fontStyle=1;verticalAlign=top;dashed=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="840" y="420" width="220" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="sNa" value="A" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=13;fontStyle=1;" vertex="1" parent="siteN">
|
||||
<mxGeometry x="30" y="50" width="70" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="sNb" value="B" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=13;fontStyle=1;" vertex="1" parent="siteN">
|
||||
<mxGeometry x="120" y="50" width="70" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Central -> Sites (fan-out from cluster bottom) -->
|
||||
<mxCell id="c2s01" value="" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="central" target="site01">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="c2s02" value="" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="central" target="site02">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="c2s03" value="" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="central" target="site03">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="c2sN" value="" style="edgeStyle=orthogonalEdgeStyle;html=1;endArrow=block;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="central" target="siteN">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 74 KiB |
@@ -6,24 +6,8 @@ ScadaBridge uses a hub-and-spoke architecture:
|
||||
- **Central Cluster**: Two-node active/standby Akka.NET cluster for management, UI, and coordination.
|
||||
- **Site Clusters**: Two-node active/standby Akka.NET clusters at each remote site for data collection and local processing.
|
||||
|
||||
```
|
||||
┌──────────────────────────┐
|
||||
│ Central Cluster │
|
||||
│ ┌──────┐ ┌──────┐ │
|
||||
Users ──────────► │ │Node A│◄──►│Node B│ │
|
||||
(HTTPS/LB) │ │Active│ │Stby │ │
|
||||
│ └──┬───┘ └──┬───┘ │
|
||||
└─────┼───────────┼────────┘
|
||||
│ │
|
||||
┌───────────┼───────────┼───────────┐
|
||||
│ │ │ │
|
||||
┌─────▼─────┐ ┌──▼──────┐ ┌──▼──────┐ ┌──▼──────┐
|
||||
│ Site 01 │ │ Site 02 │ │ Site 03 │ │ Site N │
|
||||
│ ┌──┐ ┌──┐ │ │ ┌──┐┌──┐│ │ ┌──┐┌──┐│ │ ┌──┐┌──┐│
|
||||
│ │A │ │B │ │ │ │A ││B ││ │ │A ││B ││ │ │A ││B ││
|
||||
│ └──┘ └──┘ │ │ └──┘└──┘│ │ └──┘└──┘│ │ └──┘└──┘│
|
||||
└───────────┘ └─────────┘ └─────────┘ └─────────┘
|
||||
```
|
||||

|
||||
<!-- source: diagrams/topology-architecture-overview.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
## Central Cluster Setup
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -167,20 +167,8 @@ Keepalive settings are configurable via `CommunicationOptions`:
|
||||
|
||||
## Topology
|
||||
|
||||
```
|
||||
Central Cluster
|
||||
├── ClusterClient → Site A Cluster (SiteCommunicationActor via Receptionist) [command/control]
|
||||
├── ClusterClient → Site B Cluster (SiteCommunicationActor via Receptionist) [command/control]
|
||||
└── ClusterClient → Site N Cluster (SiteCommunicationActor via Receptionist) [command/control]
|
||||
│
|
||||
├── SiteStreamGrpcClient ◄── gRPC stream ── Site A (SiteStreamGrpcServer) [real-time data]
|
||||
├── SiteStreamGrpcClient ◄── gRPC stream ── Site B (SiteStreamGrpcServer) [real-time data]
|
||||
└── SiteStreamGrpcClient ◄── gRPC stream ── Site N (SiteStreamGrpcServer) [real-time data]
|
||||
|
||||
Site Clusters
|
||||
└── ClusterClient → Central Cluster (CentralCommunicationActor via Receptionist) [command/control]
|
||||
└── SiteStreamGrpcServer (Kestrel HTTP/2, port 8083) → serves gRPC streams [real-time data]
|
||||
```
|
||||

|
||||
<!-- source: diagrams/communication-topology.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
- Sites do **not** communicate with each other.
|
||||
- All inter-cluster communication flows through central.
|
||||
|
||||
@@ -143,15 +143,8 @@ EF Core's DbContext naturally provides unit-of-work semantics:
|
||||
|
||||
### Example Transactional Flow
|
||||
|
||||
```
|
||||
Template Engine: Create Template
|
||||
│
|
||||
├── repository.AddTemplate(template) // template is a Commons POCO
|
||||
├── repository.AddAttributes(attributes) // attributes are Commons POCOs
|
||||
├── repository.AddAlarms(alarms) // alarms are Commons POCOs
|
||||
├── repository.AddScripts(scripts) // scripts are Commons POCOs
|
||||
└── repository.SaveChangesAsync() // single transaction commits all
|
||||
```
|
||||

|
||||
<!-- source: diagrams/configdb-transactional-flow.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
---
|
||||
|
||||
@@ -184,14 +177,8 @@ Audit entries are written **synchronously** within the same database transaction
|
||||
|
||||
### Integration Example
|
||||
|
||||
```
|
||||
Template Engine: Update Template
|
||||
│
|
||||
├── repository.UpdateTemplate(template)
|
||||
├── auditService.LogAsync(user, "Update", "Template", template.Id,
|
||||
│ template.Name, template)
|
||||
└── repository.SaveChangesAsync() ← both the change and audit entry commit together
|
||||
```
|
||||

|
||||
<!-- source: diagrams/configdb-integration-example.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
### Audit Entry Schema
|
||||
|
||||
|
||||
@@ -80,12 +80,8 @@ Data connections support an optional backup endpoint for automatic failover when
|
||||
|
||||
**Failover state machine:**
|
||||
|
||||
```
|
||||
Connected → disconnect → push bad quality → retry active endpoint (5s)
|
||||
→ N failures (≥ FailoverRetryCount) → switch to other endpoint
|
||||
→ dispose adapter, create fresh adapter with other config
|
||||
→ reconnect → ReSubscribeAll → Connected
|
||||
```
|
||||

|
||||
<!-- source: diagrams/dcl-endpoint-redundancy.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
- **Round-robin**: primary → backup → primary → backup. No preferred endpoint after first failover — the connection stays on whichever endpoint is working.
|
||||
- **No auto-failback**: The connection remains on the active endpoint until it fails.
|
||||
|
||||
@@ -22,24 +22,8 @@ Central cluster only. The site-side deployment responsibilities (receiving confi
|
||||
|
||||
## Deployment Flow
|
||||
|
||||
```
|
||||
Engineer (UI) → Deployment Manager (Central)
|
||||
│
|
||||
├── 1. Request validated + flattened config from Template Engine
|
||||
│ (validation includes flattening, script compilation,
|
||||
│ trigger references, connection binding completeness)
|
||||
├── 2. If validation fails → return errors to UI, stop
|
||||
├── 3. Send config to site via Communication Layer
|
||||
│ │
|
||||
│ ▼
|
||||
│ Site Runtime (Deployment Manager Singleton)
|
||||
│ ├── 4. Store new flattened config locally (SQLite)
|
||||
│ ├── 5. Compile scripts at site
|
||||
│ ├── 6. Create/update Instance Actor (with child Script + Alarm Actors)
|
||||
│ └── 7. Report success/failure back to central
|
||||
│
|
||||
└── 8. Update deployment status in config DB
|
||||
```
|
||||

|
||||
<!-- source: diagrams/deployment-flow.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
## Deployment Identity & Idempotency
|
||||
|
||||
|
||||
@@ -123,20 +123,8 @@ API method scripts are compiled at central startup — all method definitions ar
|
||||
|
||||
## Request Flow
|
||||
|
||||
```
|
||||
External System
|
||||
│
|
||||
▼
|
||||
Inbound API (Central)
|
||||
├── 1. Extract API key from request
|
||||
├── 2. Validate key exists and is enabled
|
||||
├── 3. Resolve method by name
|
||||
├── 4. Check API key is in method's approved list
|
||||
├── 5. Validate and deserialize parameters
|
||||
├── 6. Execute implementation script (subject to method timeout)
|
||||
├── 7. Serialize return value
|
||||
└── 8. Return response
|
||||
```
|
||||

|
||||
<!-- source: diagrams/inboundapi-request-flow.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
## Implementation Script Capabilities
|
||||
|
||||
|
||||
@@ -24,24 +24,8 @@ SMTP and HTTP delivery is blocking I/O. Delivery work runs on a **dedicated bloc
|
||||
|
||||
## End-to-End Flow
|
||||
|
||||
```
|
||||
Site script: Notify.To("list").Send(subject, body)
|
||||
│ generate NotificationId (GUID) locally; return it to the script immediately
|
||||
▼
|
||||
Site Store-and-Forward Engine (notification category, target = central)
|
||||
│ durably forwards to central via Central–Site Communication (ClusterClient);
|
||||
│ buffers/retries if central is unreachable
|
||||
▼
|
||||
Central ingest: insert-if-not-exists on NotificationId → Notifications table (Pending)
|
||||
│ ack the site → site S&F clears the message
|
||||
▼
|
||||
Central Notification Outbox actor (singleton, active central node)
|
||||
│ polls due rows; resolves the list; delivers via the matching adapter
|
||||
├── success → Delivered
|
||||
├── transient failure → Retrying (schedule NextAttemptAt)
|
||||
└── permanent failure
|
||||
/ retries exhausted → Parked
|
||||
```
|
||||

|
||||
<!-- source: diagrams/notificationoutbox-flow.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
The site forwards only `(listName, subject, body)` plus provenance — recipient resolution happens at central, at delivery time. This keeps notification-list definitions in one place and removes the deploy-to-sites artifact entirely.
|
||||
|
||||
|
||||
@@ -27,21 +27,8 @@ Site clusters only.
|
||||
|
||||
## Actor Hierarchy
|
||||
|
||||
```
|
||||
Deployment Manager Singleton (Cluster Singleton)
|
||||
├── Instance Actor ("MachineA-001")
|
||||
│ ├── Script Actor ("MonitorSpeed") — coordinator
|
||||
│ │ └── Script Execution Actor — short-lived, per invocation
|
||||
│ ├── Script Actor ("CalculateOEE") — coordinator
|
||||
│ │ └── Script Execution Actor — short-lived, per invocation
|
||||
│ ├── Alarm Actor ("OverTemp") — coordinator (computed)
|
||||
│ │ └── Alarm Execution Actor — short-lived, per on-trigger invocation
|
||||
│ ├── Alarm Actor ("LowPressure") — coordinator (computed)
|
||||
│ └── Native Alarm Actor ("OpcUaServer1") — read-only mirror, peer to Alarm Actor
|
||||
├── Instance Actor ("MachineA-002")
|
||||
│ └── ...
|
||||
└── ...
|
||||
```
|
||||

|
||||
<!-- source: diagrams/siteruntime-actor-hierarchy.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -25,23 +25,8 @@ Site clusters only. The central cluster does not buffer messages.
|
||||
|
||||
## Message Lifecycle
|
||||
|
||||
```
|
||||
Script submits message
|
||||
│
|
||||
▼
|
||||
Attempt immediate delivery
|
||||
│
|
||||
├── Success → Remove from buffer
|
||||
│
|
||||
└── Failure → Buffer message
|
||||
│
|
||||
▼
|
||||
Retry loop (per retry policy)
|
||||
│
|
||||
├── Success → Remove from buffer + notify standby
|
||||
│
|
||||
└── Max retries exhausted → Park message
|
||||
```
|
||||

|
||||
<!-- source: diagrams/storeforward-message-lifecycle.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
For notifications, "delivery" means forwarding the message to the central cluster via Central–Site Communication; "success" is central's ack, on which the message is cleared. Notifications are retried at the fixed forward interval until central acks, but — like every other category — they are bounded by the engine's `DefaultMaxRetries` cap: a sustained central outage that exceeds `DefaultMaxRetries × forward-interval` will park the buffered notification, after which an operator can Retry/Discard it via the parked-message UI. Operationally, the cap is sized so the normal central-recovery window stays well inside it; "do not park" is the design's operational intent on the happy path, not an absolute invariant. Callers that genuinely require unbounded retry pass `maxRetries: 0` on `EnqueueAsync` (the documented "no limit" escape hatch — see `StoreAndForward-015`).
|
||||
|
||||
|
||||
@@ -92,20 +92,8 @@ The manifest is plaintext so the import wizard can preview bundle contents and s
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
ZB.MOM.WW.ScadaBridge.Transport
|
||||
├── IBundleExporter
|
||||
│ ExportAsync(ExportSelection, Passphrase?, ct) → Stream
|
||||
├── IBundleImporter
|
||||
│ LoadAsync(stream, Passphrase?, ct) → BundleSession
|
||||
│ PreviewAsync(sessionId, ct) → ImportPreview
|
||||
│ ApplyAsync(sessionId, resolutions, ct) → ImportResult
|
||||
├── DependencyResolver
|
||||
├── BundleSerializer (manifest + content JSON; ZIP packer)
|
||||
├── BundleSecretEncryptor (AES-256-GCM + PBKDF2)
|
||||
├── BundleSessionStore (in-memory, TTL'd)
|
||||
└── ManifestValidator (schema/version gating, hash check)
|
||||
```
|
||||

|
||||
<!-- source: diagrams/transport-architecture.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
The component is central-only. It is registered in `ZB.MOM.WW.ScadaBridge.Host` for central roles only, never for site roles. All persistence flows through existing audited repository interfaces in `ZB.MOM.WW.ScadaBridge.ConfigurationDatabase` — the component does not call `DbContext.SaveChangesAsync` directly. `BundleSessionStore` is in-process on the active central node (matching Blazor Server circuit affinity): 30-minute TTL, eviction on expiry, 3-strike passphrase lockout per session.
|
||||
|
||||
@@ -132,22 +120,8 @@ The user can toggle "include all dependencies" off (with a warning that the bund
|
||||
|
||||
### Backend
|
||||
|
||||
```
|
||||
User (Design role) ─► Central UI Export wizard
|
||||
│
|
||||
▼
|
||||
IBundleExporter
|
||||
│
|
||||
├─► DependencyResolver ─► repositories (read)
|
||||
├─► EntitySerializer ─► content.json
|
||||
├─► BundleSecretEncryptor ► content.enc (if passphrase)
|
||||
├─► ManifestBuilder ─► manifest.json
|
||||
▼
|
||||
ZIP packer → temp file → browser download
|
||||
│
|
||||
▼
|
||||
IAuditService.LogAsync(BundleExported …)
|
||||
```
|
||||

|
||||
<!-- source: diagrams/transport-export-flow.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
Audit event: `BundleExported` — caller, artifact count, content hash, encrypted yes/no, bundle filename.
|
||||
|
||||
@@ -179,35 +153,8 @@ Bundle references that cannot be satisfied in either the bundle or the target DB
|
||||
|
||||
### Backend
|
||||
|
||||
```
|
||||
User (Admin role) ─► uploads bundle
|
||||
│
|
||||
▼
|
||||
IBundleImporter.LoadAsync
|
||||
· verify SHA-256 (manifest vs content)
|
||||
· check bundleFormatVersion supported
|
||||
· decrypt content.enc with passphrase (if encrypted)
|
||||
· deserialize entities
|
||||
· open BundleSession (30-min TTL)
|
||||
│
|
||||
▼
|
||||
PreviewAsync → diff vs target DB → ImportPreview
|
||||
│
|
||||
▼ (user reviews + resolves conflicts)
|
||||
│
|
||||
ApplyAsync (single EF transaction)
|
||||
· run two-tier semantic validation (minimal name scan + full SemanticValidator)
|
||||
· apply resolutions (add / overwrite / skip / rename)
|
||||
· upsert TemplateFolder hierarchy
|
||||
· IAuditService.LogAsync(BundleImported …)
|
||||
· commit
|
||||
│
|
||||
▼
|
||||
ImportResult → UI step 5
|
||||
│
|
||||
▼
|
||||
"View on Deployments →" (existing page)
|
||||
```
|
||||

|
||||
<!-- source: diagrams/transport-import-flow.drawio — edit, then re-export with export-drawio.sh -->
|
||||
|
||||
Authorization: `RequireAdmin` on both the Razor page and `IBundleImporter.*` entrypoints.
|
||||
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="topology" name="Topology">
|
||||
<mxGraphModel dx="1400" dy="900" grid="1" gridSize="10" guides="1" arrows="1"
|
||||
fold="1" page="1" pageScale="1" pageWidth="1300" pageHeight="900" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- Central Cluster container -->
|
||||
<mxCell id="central" value="Central Cluster" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;fontStyle=1;fontSize=14;" vertex="1" parent="1">
|
||||
<mxGeometry x="60" y="60" width="380" height="320" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cc-a" value="ClusterClient (command/control)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="90" y="110" width="150" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cc-b" value="ClusterClient (command/control)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="90" y="170" width="150" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cc-n" value="ClusterClient (command/control)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="90" y="230" width="150" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="grpc-client" value="SiteStreamGrpcClient (real-time data)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="90" y="300" width="150" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Site A -->
|
||||
<mxCell id="siteA" value="Site A Cluster" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;verticalAlign=top;fontStyle=1;fontSize=14;" vertex="1" parent="1">
|
||||
<mxGeometry x="720" y="60" width="380" height="250" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="siteA-comm" value="SiteCommunicationActor (via Receptionist)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="760" y="110" width="190" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="siteA-grpc" value="SiteStreamGrpcServer (Kestrel HTTP/2, port 8083)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="760" y="180" width="190" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="siteA-clusterclient" value="ClusterClient → Central (CentralCommunicationActor)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="760" y="245" width="190" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Site B -->
|
||||
<mxCell id="siteB" value="Site B Cluster" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;verticalAlign=top;fontStyle=1;fontSize=14;" vertex="1" parent="1">
|
||||
<mxGeometry x="720" y="370" width="380" height="130" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="siteB-comm" value="SiteCommunicationActor (via Receptionist)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="760" y="410" width="190" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="siteB-grpc" value="SiteStreamGrpcServer" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="760" y="455" width="190" height="35" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Site N -->
|
||||
<mxCell id="siteN" value="Site N Cluster" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;verticalAlign=top;fontStyle=1;fontSize=14;" vertex="1" parent="1">
|
||||
<mxGeometry x="720" y="560" width="380" height="130" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="siteN-comm" value="SiteCommunicationActor (via Receptionist)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="760" y="600" width="190" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="siteN-grpc" value="SiteStreamGrpcServer" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="760" y="645" width="190" height="35" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Command/control edges: Central ClusterClients -> Site comm actors -->
|
||||
<mxCell id="e-cca" value="command/control" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;" edge="1" parent="1" source="cc-a" target="siteA-comm">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e-ccb" value="command/control" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;" edge="1" parent="1" source="cc-b" target="siteB-comm">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e-ccn" value="command/control" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;" edge="1" parent="1" source="cc-n" target="siteN-comm">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- gRPC stream edges: site servers -> central grpc client (data flows site->central) -->
|
||||
<mxCell id="e-grpca" value="gRPC stream (real-time data)" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;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="siteA-grpc" target="grpc-client">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="540" y="205" />
|
||||
<mxPoint x="540" y="325" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e-grpcb" value="gRPC stream" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;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="siteB-grpc" target="grpc-client">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="600" y="472" />
|
||||
<mxPoint x="600" y="335" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e-grpcn" value="gRPC stream" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;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="siteN-grpc" target="grpc-client">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="660" y="662" />
|
||||
<mxPoint x="660" y="345" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Site A -> Central command/control (ClusterClient to central) -->
|
||||
<mxCell id="e-sa-central" value="command/control" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;dashed=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.7;entryDx=0;entryDy=0;" edge="1" parent="1" source="siteA-clusterclient" target="central">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="480" y="270" />
|
||||
<mxPoint x="480" y="284" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Note: sites do not talk to each other -->
|
||||
<mxCell id="note" value="Sites do NOT communicate with each other. All inter-cluster communication flows through Central." style="shape=note;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="60" y="560" width="380" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 341 KiB |
@@ -0,0 +1,37 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="configdb-integration-example" name="Integration Example">
|
||||
<mxGraphModel dx="800" dy="600" grid="1" gridSize="10" guides="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="start" value="Template Engine: Update Template" style="rounded=1;arcSize=40;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="220" y="40" width="360" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="upd" value="repository.UpdateTemplate(template)" style="whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;align=left;spacingLeft=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="220" y="150" width="360" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="audit" value="auditService.LogAsync(user, "Update", "Template",     template.Id, template.Name, template)" style="whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;align=left;spacingLeft=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="220" y="230" width="360" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="save" value="repository.SaveChangesAsync()" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;align=left;spacingLeft=12;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="220" y="330" width="360" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="note" value="both the change and audit entry commit together" style="shape=note;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;size=14;align=left;spacingLeft=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="630" y="330" width="180" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e0" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="start" target="upd">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="upd" target="audit">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="audit" target="save">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=none;dashed=1;" edge="1" parent="1" source="save" target="note">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 109 KiB |
@@ -0,0 +1,49 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="configdb-transactional-flow" name="Transactional Flow">
|
||||
<mxGraphModel dx="800" dy="600" grid="1" gridSize="10" guides="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="start" value="Template Engine: Create Template" style="rounded=1;arcSize=40;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="40" width="320" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="add1" value="repository.AddTemplate(template) // template is a Commons POCO" style="whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;align=left;spacingLeft=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="150" width="320" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="add2" value="repository.AddAttributes(attributes) // attributes are Commons POCOs" style="whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;align=left;spacingLeft=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="230" width="320" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="add3" value="repository.AddAlarms(alarms) // alarms are Commons POCOs" style="whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;align=left;spacingLeft=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="310" width="320" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="add4" value="repository.AddScripts(scripts) // scripts are Commons POCOs" style="whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;align=left;spacingLeft=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="390" width="320" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="save" value="repository.SaveChangesAsync() // single transaction commits all" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;align=left;spacingLeft=12;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="480" width="320" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="db" value="Configuration DB (MS SQL)" style="shape=cylinder3;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1">
|
||||
<mxGeometry x="640" y="475" width="120" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e0" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="start" target="add1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="add1" target="add2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="add2" target="add3">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="add3" target="add4">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="add4" target="save">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e5" value="single transaction" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;dashed=1;" edge="1" parent="1" source="save" target="db">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 182 KiB |
@@ -0,0 +1,71 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="dcl-endpoint-redundancy" name="Failover State Machine">
|
||||
<mxGraphModel dx="900" dy="700" grid="1" gridSize="10" guides="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="connected" value="Connected" style="rounded=1;arcSize=50;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="40" width="160" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="pushbad" value="push bad quality" style="whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="150" width="160" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="retry" value="retry active endpoint (5s)" style="whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="250" width="160" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="decide" value="N failures (≥ FailoverRetryCount)?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
|
||||
<mxGeometry x="350" y="350" width="180" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="switch" value="switch to other endpoint" style="whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="500" width="160" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="dispose" value="dispose adapter, create fresh adapter with other config" style="whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="600" width="160" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="reconnect" value="reconnect" style="whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="710" width="160" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="resub" value="ReSubscribeAll" style="whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="800" width="160" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e0" value="disconnect" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="connected" target="pushbad">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="pushbad" target="retry">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="retry" target="decide">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e2b" value="no (retry again)" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;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="retry">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="620" y="400" />
|
||||
<mxPoint x="620" y="275" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e3" value="yes" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="decide" target="switch">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="switch" target="dispose">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="dispose" target="reconnect">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="reconnect" target="resub">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e7" value="back to Connected" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="resub" target="connected">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="240" y="825" />
|
||||
<mxPoint x="240" y="65" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 128 KiB |
@@ -0,0 +1,96 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="deployflow" name="Deployment Flow">
|
||||
<mxGraphModel dx="1200" dy="1400" grid="1" gridSize="10" guides="1" arrows="1"
|
||||
fold="1" page="1" pageScale="1" pageWidth="900" pageHeight="1500" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- Start: Engineer -->
|
||||
<mxCell id="engineer" value="Engineer (UI)" style="rounded=1;arcSize=50;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=13;" vertex="1" parent="1">
|
||||
<mxGeometry x="320" y="40" width="200" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Deployment Manager (Central) container header -->
|
||||
<mxCell id="dm-central" value="Deployment Manager (Central)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;fontStyle=1;fontSize=13;" vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="130" width="640" height="430" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="step1" value="1. Request validated + flattened config from Template Engine (validation: flattening, script compilation, trigger references, connection binding completeness)" style="whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="160" y="180" width="560" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="step2" value="2. Validation fails?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="350" y="270" width="180" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="step2fail" value="Return errors to UI, stop" style="rounded=1;arcSize=50;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="600" y="280" width="140" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="step3" value="3. Send config to site via Communication Layer" style="whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="220" y="390" width="440" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="step8" value="8. Update deployment status in config DB" style="shape=cylinder3;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="480" width="320" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Site Runtime container -->
|
||||
<mxCell id="site-runtime" value="Site Runtime (Deployment Manager Singleton)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;verticalAlign=top;fontStyle=1;fontSize=13;" vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="620" width="640" height="380" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="step4" value="4. Store new flattened config locally (SQLite)" style="shape=cylinder3;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="200" y="670" width="480" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="step5" value="5. Compile scripts at site" style="whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="770" width="400" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="step6" value="6. Create/update Instance Actor (with child Script + Alarm Actors)" style="whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="850" width="400" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="step7" value="7. Report success/failure back to central" style="whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="940" width="400" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Edges -->
|
||||
<mxCell id="e0" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="engineer" target="step1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="step1" target="step2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e2yes" value="yes" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;" edge="1" parent="1" source="step2" target="step2fail">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e2no" value="no" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;" edge="1" parent="1" source="step2" target="step3">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e3" value="config" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;" edge="1" parent="1" source="step3" target="step4">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="step4" target="step5">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="step5" target="step6">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="step6" target="step7">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e7" value="report success/failure" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;dashed=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="step7" target="step8">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="780" y="965" />
|
||||
<mxPoint x="780" y="515" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 354 KiB |
@@ -0,0 +1,67 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="inboundapi-request-flow" name="Request Flow">
|
||||
<mxGraphModel dx="900" dy="900" grid="1" gridSize="10" guides="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="ext" value="External System" style="rounded=1;arcSize=50;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="320" y="40" width="200" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="api" value="Inbound API (Central)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="320" y="140" width="200" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="s1" value="1. Extract API key from request" style="whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;align=left;spacingLeft=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="240" width="280" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="s2" value="2. Validate key exists and is enabled" style="whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;align=left;spacingLeft=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="300" width="280" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="s3" value="3. Resolve method by name" style="whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;align=left;spacingLeft=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="360" width="280" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="s4" value="4. Check API key is in method's approved list" style="whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;align=left;spacingLeft=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="420" width="280" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="s5" value="5. Validate and deserialize parameters" style="whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;align=left;spacingLeft=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="480" width="280" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="s6" value="6. Execute implementation script (subject to method timeout)" style="whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;align=left;spacingLeft=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="540" width="280" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="s7" value="7. Serialize return value" style="whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;align=left;spacingLeft=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="610" width="280" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="s8" value="8. Return response" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;align=left;spacingLeft=12;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="670" width="280" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e0" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="ext" target="api">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="api" target="s1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e2" 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="e3" 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="e4" 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="e5" 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="e6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="s5" target="s6">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="s6" target="s7">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="s7" target="s8">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 146 KiB |
@@ -0,0 +1,83 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="outboxflow" name="End-to-End Flow">
|
||||
<mxGraphModel dx="1000" dy="1400" grid="1" gridSize="10" guides="1" arrows="1"
|
||||
fold="1" page="1" pageScale="1" pageWidth="950" pageHeight="1400" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- Site script -->
|
||||
<mxCell id="script" value="Site script: Notify.To("list").Send(subject, body) generate NotificationId (GUID) locally; return it to the script immediately" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="40" width="380" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Site S&F Engine -->
|
||||
<mxCell id="snf" value="Site Store-and-Forward Engine (notification category, target = central) durably forwards to central via Central–Site Communication (ClusterClient); buffers/retries if central is unreachable" style="whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="170" width="460" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Central ingest -->
|
||||
<mxCell id="ingest" value="Central ingest: insert-if-not-exists on NotificationId → Notifications table (Pending) ack the site → site S&F clears the message" style="shape=cylinder3;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="270" y="310" width="400" height="90" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Central Notification Outbox actor -->
|
||||
<mxCell id="outbox" value="Central Notification Outbox actor (singleton, active central node) polls due rows; resolves the list; delivers via the matching adapter" style="whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="460" width="380" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Delivery decision -->
|
||||
<mxCell id="d1" value="Delivery outcome" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="400" y="610" width="140" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Delivered -->
|
||||
<mxCell id="delivered" value="Delivered" style="rounded=1;arcSize=50;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="630" width="180" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Retrying -->
|
||||
<mxCell id="retrying" value="Retrying (schedule NextAttemptAt)" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="380" y="790" width="180" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Parked -->
|
||||
<mxCell id="parked" value="Parked" style="rounded=1;arcSize=50;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="650" y="630" width="180" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Edges -->
|
||||
<mxCell id="e1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="script" target="snf">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="snf" target="ingest">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="ingest" target="outbox">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="outbox" target="d1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e5" value="success" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;" edge="1" parent="1" source="d1" target="delivered">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e6" value="transient failure" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;" edge="1" parent="1" source="d1" target="retrying">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e7" value="permanent failure / retries exhausted" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;" edge="1" parent="1" source="d1" target="parked">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<!-- Retrying loops back to outbox poll -->
|
||||
<mxCell id="e8" value="retry due" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=11;dashed=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="retrying" target="outbox">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="780" y="820" />
|
||||
<mxPoint x="780" y="500" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 333 KiB |
@@ -0,0 +1,104 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="actorhierarchy" name="Actor Hierarchy">
|
||||
<mxGraphModel dx="1400" dy="1000" grid="1" gridSize="10" guides="1" arrows="1"
|
||||
fold="1" page="1" pageScale="1" pageWidth="1320" pageHeight="560" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- Root: Deployment Manager Singleton -->
|
||||
<mxCell id="dms" value="Deployment Manager Singleton (Cluster Singleton)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;fontSize=13;" vertex="1" parent="1">
|
||||
<mxGeometry x="490" y="30" width="280" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Instance Actors -->
|
||||
<mxCell id="ia1" value="Instance Actor ("MachineA-001")" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontStyle=1;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="368" y="160" width="184" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ia2" value="Instance Actor ("MachineA-002")" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontStyle=1;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="980" y="160" width="184" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="iamore" value="… more Instance Actors" style="text;html=1;align=center;verticalAlign=middle;fontSize=12;fontStyle=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="1190" y="170" width="120" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Children of MachineA-001 (top row) -->
|
||||
<mxCell id="sa1" value="Script Actor ("MonitorSpeed") — coordinator" style="whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="16" y="300" width="164" height="74" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="sa2" value="Script Actor ("CalculateOEE") — coordinator" style="whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="196" y="300" width="164" height="74" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="aa1" value="Alarm Actor ("OverTemp") — coordinator (computed)" style="whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="376" y="300" width="164" height="74" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="aa2" value="Alarm Actor ("LowPressure") — coordinator (computed)" style="whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="556" y="300" width="164" height="74" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="naa1" value="Native Alarm Actor ("OpcUaServer1") — read-only mirror, peer to Alarm Actor" style="whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="736" y="300" width="164" height="74" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Execution actors (bottom row, under their coordinators) -->
|
||||
<mxCell id="sea1" value="Script Execution Actor — short-lived, per invocation" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;dashed=1;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="16" y="430" width="164" height="64" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="sea2" value="Script Execution Actor — short-lived, per invocation" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;dashed=1;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="196" y="430" width="164" height="64" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="aea1" value="Alarm Execution Actor — short-lived, per on-trigger invocation" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;dashed=1;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="376" y="430" width="164" height="64" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Child of MachineA-002 -->
|
||||
<mxCell id="ia2child" value="… (Script / Alarm Actors)" style="text;html=1;align=center;verticalAlign=middle;fontSize=12;fontStyle=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="992" y="304" width="160" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Edges: root -> instances -->
|
||||
<mxCell id="e-dms-ia1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="dms" target="ia1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e-dms-ia2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="dms" target="ia2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e-dms-more" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;dashed=1;" edge="1" parent="1" source="dms" target="iamore">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Edges: MachineA-001 -> its children (all top-row, no box in between) -->
|
||||
<mxCell id="e-ia1-sa1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="ia1" target="sa1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e-ia1-sa2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="ia1" target="sa2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e-ia1-aa1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="ia1" target="aa1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e-ia1-aa2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="ia1" target="aa2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e-ia1-naa1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="ia1" target="naa1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Edges: coordinator -> execution actor (short vertical, own column) -->
|
||||
<mxCell id="e-sa1-sea1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="sa1" target="sea1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e-sa2-sea2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="sa2" target="sea2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e-aa1-aea1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="aa1" target="aea1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Edge: MachineA-002 -> its child -->
|
||||
<mxCell id="e-ia2-child" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;dashed=1;" edge="1" parent="1" source="ia2" target="ia2child">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 217 KiB |
@@ -0,0 +1,82 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="msglifecycle" name="Message Lifecycle">
|
||||
<mxGraphModel dx="1000" dy="1300" grid="1" gridSize="10" guides="1" arrows="1"
|
||||
fold="1" page="1" pageScale="1" pageWidth="900" pageHeight="1300" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
|
||||
<!-- Start -->
|
||||
<mxCell id="submit" value="Script submits message" style="rounded=1;arcSize=50;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=13;" vertex="1" parent="1">
|
||||
<mxGeometry x="320" y="40" width="220" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Attempt immediate delivery -->
|
||||
<mxCell id="attempt" value="Attempt immediate delivery" style="whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=13;" vertex="1" parent="1">
|
||||
<mxGeometry x="320" y="140" width="220" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Decision: success or failure -->
|
||||
<mxCell id="d1" value="Delivered?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="350" y="240" width="160" height="90" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Success -> Remove from buffer -->
|
||||
<mxCell id="remove1" value="Remove from buffer" style="rounded=1;arcSize=50;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="620" y="255" width="200" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Failure -> Buffer message -->
|
||||
<mxCell id="buffer" value="Buffer message" style="whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="330" y="390" width="200" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Retry loop -->
|
||||
<mxCell id="retry" value="Retry loop (per retry policy)" style="whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="330" y="490" width="200" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Retry decision -->
|
||||
<mxCell id="d2" value="Retry outcome" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="350" y="610" width="160" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Retry success -> Remove from buffer + notify standby -->
|
||||
<mxCell id="remove2" value="Remove from buffer + notify standby" style="rounded=1;arcSize=50;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="620" y="625" width="200" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Max retries exhausted -> Park message -->
|
||||
<mxCell id="park" value="Park message (dead-letter)" style="rounded=1;arcSize=50;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="330" y="770" width="200" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
|
||||
<!-- Edges -->
|
||||
<mxCell id="e1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="submit" target="attempt">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="attempt" target="d1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e3" value="Success" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;" edge="1" parent="1" source="d1" target="remove1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e4" value="Failure" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;" edge="1" parent="1" source="d1" target="buffer">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="buffer" target="retry">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="retry" target="d2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e7" value="Success" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;" edge="1" parent="1" source="d2" target="remove2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e8" value="Max retries exhausted" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;fontSize=12;" edge="1" parent="1" source="d2" target="park">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 154 KiB |
@@ -0,0 +1,34 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="transport-architecture" name="Architecture">
|
||||
<mxGraphModel dx="900" dy="800" grid="1" gridSize="10" guides="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="container" value="ZB.MOM.WW.ScadaBridge.Transport" style="swimlane;whiteSpace=wrap;html=1;startSize=34;fillColor=#f5f5f5;strokeColor=#666666;fontStyle=1;fontSize=14;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="40" width="560" height="610" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="exporter" value="IBundleExporter ExportAsync(ExportSelection, Passphrase?, ct) → Stream" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;align=left;spacingLeft=12;verticalAlign=top;spacingTop=8;" vertex="1" parent="container">
|
||||
<mxGeometry x="30" y="50" width="500" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="importer" value="IBundleImporter LoadAsync(stream, Passphrase?, ct) → BundleSession PreviewAsync(sessionId, ct) → ImportPreview ApplyAsync(sessionId, resolutions, ct) → ImportResult" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;align=left;spacingLeft=12;verticalAlign=top;spacingTop=8;" vertex="1" parent="container">
|
||||
<mxGeometry x="30" y="140" width="500" height="110" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="resolver" value="DependencyResolver" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;align=left;spacingLeft=12;" vertex="1" parent="container">
|
||||
<mxGeometry x="30" y="270" width="500" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="serializer" value="BundleSerializer (manifest + content JSON; ZIP packer)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;align=left;spacingLeft=12;" vertex="1" parent="container">
|
||||
<mxGeometry x="30" y="330" width="500" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="encryptor" value="BundleSecretEncryptor (AES-256-GCM + PBKDF2)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;align=left;spacingLeft=12;" vertex="1" parent="container">
|
||||
<mxGeometry x="30" y="390" width="500" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="sessionstore" value="BundleSessionStore (in-memory, TTL'd)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;align=left;spacingLeft=12;" vertex="1" parent="container">
|
||||
<mxGeometry x="30" y="450" width="500" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="manifestvalidator" value="ManifestValidator (schema/version gating, hash check)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;align=left;spacingLeft=12;" vertex="1" parent="container">
|
||||
<mxGeometry x="30" y="510" width="500" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 228 KiB |
@@ -0,0 +1,85 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="transport-export-flow" name="Export Flow (Backend)">
|
||||
<mxGraphModel dx="1000" dy="800" grid="1" gridSize="10" guides="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="900" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="user" value="User (Design role)" style="rounded=1;arcSize=50;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="40" width="160" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wizard" value="Central UI Export wizard" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="40" width="200" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="exporter" value="IBundleExporter" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="150" width="200" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="resolver" value="DependencyResolver" style="whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="250" width="200" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="repos" value="repositories (read)" style="shape=cylinder3;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1">
|
||||
<mxGeometry x="600" y="245" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="serializer" value="EntitySerializer" style="whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="310" width="200" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="contentjson" value="content.json" style="shape=note;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;size=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="610" y="310" width="110" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="encryptor" value="BundleSecretEncryptor" style="whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="370" width="200" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="contentenc" value="content.enc (if passphrase)" style="shape=note;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;size=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="610" y="368" width="110" height="44" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="manifestbuilder" value="ManifestBuilder" style="whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="430" width="200" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="manifestjson" value="manifest.json" style="shape=note;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;size=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="610" y="430" width="110" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zip" value="ZIP packer → temp file → browser download" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="520" width="280" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="audit" value="IAuditService.LogAsync(BundleExported …)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="240" y="620" width="280" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e0" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="user" target="wizard">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="wizard" target="exporter">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="exporter" target="resolver">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="resolver" target="serializer">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="serializer" target="encryptor">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="encryptor" target="manifestbuilder">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="manifestbuilder" target="zip">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="zip" target="audit">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="b1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="resolver" target="repos">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="b2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="serializer" target="contentjson">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="b3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="encryptor" target="contentenc">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="b4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="manifestbuilder" target="manifestjson">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 164 KiB |
@@ -0,0 +1,49 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram id="transport-import-flow" name="Import Flow (Backend)">
|
||||
<mxGraphModel dx="1000" dy="900" grid="1" gridSize="10" guides="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="900" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="user" value="User (Admin role) ─► uploads bundle" style="rounded=1;arcSize=30;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="260" y="40" width="320" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="load" value="IBundleImporter.LoadAsync   · verify SHA-256 (manifest vs content)   · check bundleFormatVersion supported   · decrypt content.enc with passphrase (if encrypted)   · deserialize entities   · open BundleSession (30-min TTL)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;align=left;spacingLeft=12;verticalAlign=top;spacingTop=8;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="220" y="150" width="400" height="140" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="preview" value="PreviewAsync → diff vs target DB → ImportPreview" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
|
||||
<mxGeometry x="220" y="350" width="400" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="review" value="(user reviews + resolves conflicts)" style="whiteSpace=wrap;html=1;fillColor=none;strokeColor=none;fontStyle=2;align=left;" vertex="1" parent="1">
|
||||
<mxGeometry x="630" y="425" width="240" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="apply" value="ApplyAsync (single EF transaction)   · run two-tier semantic validation     (minimal name scan + full SemanticValidator)   · apply resolutions (add / overwrite / skip / rename)   · upsert TemplateFolder hierarchy   · IAuditService.LogAsync(BundleImported …)   · commit" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;align=left;spacingLeft=12;verticalAlign=top;spacingTop=8;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="220" y="460" width="400" height="160" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="result" value="ImportResult → UI step 5" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
|
||||
<mxGeometry x="260" y="680" width="320" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="deployments" value=""View on Deployments →" (existing page)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="260" y="780" width="320" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e0" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="user" target="load">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="load" target="preview">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="preview" target="apply">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e2b" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=none;dashed=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="preview" target="review">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="apply" target="result">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="e4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;endArrow=block;" edge="1" parent="1" source="result" target="deployments">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
After Width: | Height: | Size: 282 KiB |