diff --git a/outputs/diagrams/otopcua-dataflow.mmd b/outputs/diagrams/otopcua-dataflow.mmd new file mode 100644 index 0000000..97395f2 --- /dev/null +++ b/outputs/diagrams/otopcua-dataflow.mmd @@ -0,0 +1,50 @@ +flowchart LR + subgraph Equipment["Equipment (Layer 1)"] + PLC1["Modbus TCP/RTU
devices"] + PLC2["Siemens S7
PLCs"] + PLC3["OPC UA-native
equipment"] + PLC4["AB CIP/Legacy
PLCs"] + PLC5["Beckhoff TwinCAT
controllers"] + CNC["FANUC CNC
(FOCAS)"] + end + + subgraph OtOpcUa["OtOpcUa Cluster — per site (Layer 2)"] + direction TB + subgraph Drivers["Core Drivers (8)"] + D1["Modbus
Tier A"] + D2["S7
Tier B"] + D3["OPC UA Client
Tier A"] + D4["AB CIP + Legacy
Tier B"] + D5["TwinCAT
Tier B"] + D6["FOCAS
Tier C ⚡"] + end + subgraph Namespaces["Two Namespaces"] + EN["Equipment NS
(raw data)"] + SPN["System Platform NS
(processed data)"] + end + ACL["ACL Enforcer
6-level scope"] + end + + subgraph Consumers["Downstream Consumers"] + SB["ScadaBridge
(Tier 1 cutover)"] + IG["Ignition SCADA
(Tier 2 cutover)"] + SP["System Platform IO
(Tier 3 cutover)"] + end + + PLC1 --> D1 + PLC2 --> D2 + PLC3 --> D3 + PLC4 --> D4 + PLC5 --> D5 + CNC -.->|"out-of-process
named pipe"| D6 + D1 --> EN + D2 --> EN + D3 --> EN + D4 --> EN + D5 --> EN + D6 --> EN + EN --> ACL + SPN --> ACL + ACL --> SB + ACL --> IG + ACL --> SP diff --git a/outputs/diagrams/otopcua-dataflow.png b/outputs/diagrams/otopcua-dataflow.png new file mode 100644 index 0000000..ef75688 Binary files /dev/null and b/outputs/diagrams/otopcua-dataflow.png differ diff --git a/outputs/diagrams/redpanda-eventhub.mmd b/outputs/diagrams/redpanda-eventhub.mmd new file mode 100644 index 0000000..c8cd7f2 --- /dev/null +++ b/outputs/diagrams/redpanda-eventhub.mmd @@ -0,0 +1,47 @@ +flowchart LR + subgraph Sites["Site ScadaBridge Clusters"] + SB1["ScadaBridge
Warsaw West"] + SB2["ScadaBridge
Shannon"] + SB3["ScadaBridge
Ponce"] + SBN["ScadaBridge
... other sites"] + end + + subgraph SAF["Store & Forward
(per site, per call)"] + Q1["Local Queue"] + Q2["Local Queue"] + Q3["Local Queue"] + QN["Local Queue"] + end + + subgraph Redpanda["Redpanda Central Cluster (South Bend)"] + direction TB + subgraph Topics["Topics: {domain}.{entity}.{event-type}"] + T1["equipment.tag.value-changed
⏱ analytics 30d"] + T2["equipment.state.transitioned
⏱ analytics 30d"] + T3["mes.workorder.started
⏱ analytics 30d"] + T4["scada.alarm.raised
⏱ operational 7d"] + T5["quality.inspection.completed
⏱ compliance 90d"] + end + SR["Schema Registry
Protobuf + BACKWARD_TRANSITIVE"] + AUTH["SASL/OAUTHBEARER
+ prefix ACLs"] + end + + subgraph Consumers["Enterprise Consumers"] + SNB["SnowBridge
→ Snowflake"] + KPI["KPI Processors"] + CAM["Camstar
Integration"] + REPLAY["Historical Replay
(simulation-lite)"] + end + + SB1 --> Q1 --> T1 + SB2 --> Q2 --> T2 + SB3 --> Q3 --> T3 + SBN --> QN --> T4 + SR -.->|"validates"| Topics + AUTH -.->|"enforces"| Topics + T1 --> SNB + T2 --> SNB + T2 --> KPI + T3 --> CAM + T1 --> REPLAY + T5 --> SNB diff --git a/outputs/diagrams/redpanda-eventhub.png b/outputs/diagrams/redpanda-eventhub.png new file mode 100644 index 0000000..da46f35 Binary files /dev/null and b/outputs/diagrams/redpanda-eventhub.png differ diff --git a/outputs/diagrams/scadabridge-dataflow.mmd b/outputs/diagrams/scadabridge-dataflow.mmd new file mode 100644 index 0000000..07e12fb --- /dev/null +++ b/outputs/diagrams/scadabridge-dataflow.mmd @@ -0,0 +1,36 @@ +flowchart LR + subgraph Inputs["Data Inputs"] + OT["OtOpcUa
Equipment NS"] + SP["OtOpcUa
System Platform NS"] + end + + subgraph ScadaBridge["ScadaBridge Cluster (per site)"] + direction TB + TPL["Templates
(central DB → site push)"] + SCR["Scripts
(C# Roslyn)"] + SAF["Store & Forward
(per-call, optional)"] + subgraph Internals["Akka.NET Runtime"] + SUP["Supervision
(self-healing)"] + CLST["2-node cluster
(~25s failover)"] + end + end + + subgraph Outputs["Integration Targets"] + RED["Redpanda EventHub
(committed, Year 1)"] + API["External Web APIs
(pre-configured, generic)"] + DB["SQL Server
(batch tracking)"] + NOT["Email Notifications
(contact-list driven)"] + EQ["Equipment Writes
(OPC UA via OtOpcUa)"] + CAM["Camstar MES
(direct Web API)"] + end + + OT --> SCR + SP --> SCR + TPL --> SCR + SCR --> SAF + SAF --> RED + SAF --> API + SAF --> DB + SAF --> NOT + SCR --> EQ + SCR --> CAM diff --git a/outputs/diagrams/scadabridge-dataflow.png b/outputs/diagrams/scadabridge-dataflow.png new file mode 100644 index 0000000..8b13455 Binary files /dev/null and b/outputs/diagrams/scadabridge-dataflow.png differ diff --git a/outputs/diagrams/snowbridge-dataflow.mmd b/outputs/diagrams/snowbridge-dataflow.mmd new file mode 100644 index 0000000..3be6803 --- /dev/null +++ b/outputs/diagrams/snowbridge-dataflow.mmd @@ -0,0 +1,30 @@ +flowchart LR + subgraph Sources["Data Sources"] + HIS["Aveva Historian
(SQL interface)
Year 1 adapter"] + RED["Redpanda Topics
(ScadaBridge events)
Year 2 adapter"] + FUT["Future Sources
(Ignition, Data Hub, etc.)"] + end + + subgraph SnowBridge["SnowBridge (.NET service)"] + direction TB + SA["Source Adapters
(pluggable per source)"] + SEL["Selection Engine
(which tags/topics → Snowflake)"] + GOV["Governance Layer"] + subgraph Approval["Approval Workflow"] + SELF["Self-service
(single tag, non-compliance)"] + FOUR["Four-eyes review
(new topic, compliance tier,
high-cost impact)"] + end + UI["Operator Web UI + API
(RBAC, audit trail,
exportable state)"] + end + + subgraph Snowflake["Snowflake"] + LAND["Landing Tables
(Snowpipe Streaming
or COPY)"] + end + + HIS --> SA + RED --> SA + FUT -.-> SA + SA --> SEL + UI --> GOV --> SEL + GOV --> Approval + SEL --> LAND diff --git a/outputs/diagrams/snowbridge-dataflow.png b/outputs/diagrams/snowbridge-dataflow.png new file mode 100644 index 0000000..14e769a Binary files /dev/null and b/outputs/diagrams/snowbridge-dataflow.png differ diff --git a/outputs/diagrams/snowflake-dbt-dataflow.mmd b/outputs/diagrams/snowflake-dbt-dataflow.mmd new file mode 100644 index 0000000..bdb86eb --- /dev/null +++ b/outputs/diagrams/snowflake-dbt-dataflow.mmd @@ -0,0 +1,39 @@ +flowchart TB + subgraph Input["Data Ingestion"] + SNB["SnowBridge
(Historian SQL + Redpanda)"] + end + + subgraph Snowflake["Snowflake + dbt"] + direction TB + LAND["Landing Tables
(raw, as-received)"] + STG["Staging Models
(cleaned, typed)"] + subgraph Curated["Curated Layer (canonical model)"] + DIM["dim_equipment
(UUID + 5 identifiers
+ UNS path + class)"] + STATE["fact_state_transitions
(Running/Idle/Faulted/
Starved/Blocked)"] + TAGS["fact_tag_values
(time-series, filtered)"] + OEE["mart_oee
(cross-site OEE
from canonical state)"] + EVENTS["fact_events
(canonical event stream)"] + end + TESTS["dbt tests
(enum divergence checks,
source freshness ≤15min)"] + end + + subgraph Consumers["Analytics Consumers"] + PBI["Power BI
(reporting)"] + AIML["AI/ML Models
(predictive)"] + ADHOC["Ad-hoc SQL
(analysts)"] + end + + SNB --> LAND + LAND --> STG + STG --> DIM + STG --> STATE + STG --> TAGS + STATE --> OEE + TAGS --> OEE + DIM --> PBI + OEE --> PBI + EVENTS --> AIML + STATE --> AIML + DIM --> ADHOC + TAGS --> ADHOC + TESTS -.->|"validates"| Curated diff --git a/outputs/diagrams/snowflake-dbt-dataflow.png b/outputs/diagrams/snowflake-dbt-dataflow.png new file mode 100644 index 0000000..057a969 Binary files /dev/null and b/outputs/diagrams/snowflake-dbt-dataflow.png differ