refactor: rename ScadaLink → ZB.MOM.WW.ScadaBridge (code + projects + namespaces)

Solution + 23 src projects + 26 test projects renamed; folders, csproj,
namespaces, and ScadaLinkDbContext/ScadaBridgeDbContext class updated.
ActorSystem "scadalink" → "scadabridge", Akka seed-node URLs migrated.
SQL roles/logins, LDAP domains, CLI command name, and CLI config dir
(~/.scadalink → ~/.scadabridge) also renamed.

Build green; 5 Host.Tests fail awaiting SQL login rename in next commit.
Pre-existing StaleTagMonitor timing flakes unchanged.

Rename script committed at tools/rename-to-scadabridge.sh.
This commit is contained in:
Joseph Doherty
2026-05-28 09:37:45 -04:00
parent 6d87ee3c3b
commit 7b0b9c7365
1531 changed files with 11180 additions and 11054 deletions
+32 -32
View File
@@ -1,4 +1,4 @@
# ScadaLink Installation Guide
# ScadaBridge Installation Guide
## Prerequisites
@@ -11,32 +11,32 @@
## Single Binary Deployment
ScadaLink ships as a single executable (`ScadaLink.Host.exe`) that runs in either Central or Site role based on configuration.
ScadaBridge ships as a single executable (`ZB.MOM.WW.ScadaBridge.Host.exe`) that runs in either Central or Site role based on configuration.
### Windows Service Installation
```powershell
# Central Node
sc.exe create "ScadaLink-Central" binPath="C:\ScadaLink\ScadaLink.Host.exe" start=auto
sc.exe description "ScadaLink-Central" "ScadaLink SCADA Central Hub"
sc.exe create "ScadaBridge-Central" binPath="C:\ScadaBridge\ZB.MOM.WW.ScadaBridge.Host.exe" start=auto
sc.exe description "ScadaBridge-Central" "ScadaBridge SCADA Central Hub"
# Site Node
sc.exe create "ScadaLink-Site" binPath="C:\ScadaLink\ScadaLink.Host.exe" start=auto
sc.exe description "ScadaLink-Site" "ScadaLink SCADA Site Agent"
sc.exe create "ScadaBridge-Site" binPath="C:\ScadaBridge\ZB.MOM.WW.ScadaBridge.Host.exe" start=auto
sc.exe description "ScadaBridge-Site" "ScadaBridge SCADA Site Agent"
```
### Directory Structure
```
C:\ScadaLink\
ScadaLink.Host.exe
C:\ScadaBridge\
ZB.MOM.WW.ScadaBridge.Host.exe
appsettings.json
appsettings.Production.json
data\ # Site: SQLite databases
site.db # Deployed configs, static overrides
store-and-forward.db # S&F message buffer
logs\ # Rolling log files
scadalink-20260316.log
scadabridge-20260316.log
```
## Configuration Templates
@@ -45,7 +45,7 @@ C:\ScadaLink\
```json
{
"ScadaLink": {
"ScadaBridge": {
"Node": {
"Role": "Central",
"NodeHostname": "central-01.example.com",
@@ -53,13 +53,13 @@ C:\ScadaLink\
},
"Cluster": {
"SeedNodes": [
"akka.tcp://scadalink@central-01.example.com:8081",
"akka.tcp://scadalink@central-02.example.com:8081"
"akka.tcp://scadabridge@central-01.example.com:8081",
"akka.tcp://scadabridge@central-02.example.com:8081"
]
},
"Database": {
"ConfigurationDb": "Server=sqlserver.example.com;Database=ScadaLink;User Id=scadalink_svc;Password=<CHANGE_ME>;Encrypt=true;TrustServerCertificate=false",
"MachineDataDb": "Server=sqlserver.example.com;Database=ScadaLink_MachineData;User Id=scadalink_svc;Password=<CHANGE_ME>;Encrypt=true;TrustServerCertificate=false"
"ConfigurationDb": "Server=sqlserver.example.com;Database=ScadaBridge;User Id=scadabridge_svc;Password=<CHANGE_ME>;Encrypt=true;TrustServerCertificate=false",
"MachineDataDb": "Server=sqlserver.example.com;Database=ScadaBridge_MachineData;User Id=scadabridge_svc;Password=<CHANGE_ME>;Encrypt=true;TrustServerCertificate=false"
},
"Security": {
"LdapServer": "ldap.example.com",
@@ -95,7 +95,7 @@ C:\ScadaLink\
```json
{
"ScadaLink": {
"ScadaBridge": {
"Node": {
"Role": "Site",
"NodeHostname": "site-01-node-a.example.com",
@@ -104,19 +104,19 @@ C:\ScadaLink\
},
"Cluster": {
"SeedNodes": [
"akka.tcp://scadalink@site-01-node-a.example.com:8081",
"akka.tcp://scadalink@site-01-node-b.example.com:8081"
"akka.tcp://scadabridge@site-01-node-a.example.com:8081",
"akka.tcp://scadabridge@site-01-node-b.example.com:8081"
]
},
"Database": {
"SiteDbPath": "C:\\ScadaLink\\data\\site.db"
"SiteDbPath": "C:\\ScadaBridge\\data\\site.db"
},
"DataConnection": {
"ReconnectInterval": "00:00:05",
"TagResolutionRetryInterval": "00:00:30"
},
"StoreAndForward": {
"SqliteDbPath": "C:\\ScadaLink\\data\\store-and-forward.db",
"SqliteDbPath": "C:\\ScadaBridge\\data\\store-and-forward.db",
"DefaultRetryInterval": "00:00:30",
"DefaultMaxRetries": 50,
"ReplicationEnabled": true
@@ -131,7 +131,7 @@ C:\ScadaLink\
"PurgeIntervalHours": 24
},
"Communication": {
"CentralSeedNode": "akka.tcp://scadalink@central-01.example.com:8081"
"CentralSeedNode": "akka.tcp://scadabridge@central-01.example.com:8081"
},
"HealthMonitoring": {
"ReportInterval": "00:00:30"
@@ -149,26 +149,26 @@ C:\ScadaLink\
1. Create the configuration database:
```sql
CREATE DATABASE ScadaLink;
CREATE LOGIN scadalink_svc WITH PASSWORD = '<STRONG_PASSWORD>';
USE ScadaLink;
CREATE USER scadalink_svc FOR LOGIN scadalink_svc;
ALTER ROLE db_owner ADD MEMBER scadalink_svc;
CREATE DATABASE ScadaBridge;
CREATE LOGIN scadabridge_svc WITH PASSWORD = '<STRONG_PASSWORD>';
USE ScadaBridge;
CREATE USER scadabridge_svc FOR LOGIN scadabridge_svc;
ALTER ROLE db_owner ADD MEMBER scadabridge_svc;
```
2. Create the machine data database:
```sql
CREATE DATABASE ScadaLink_MachineData;
USE ScadaLink_MachineData;
CREATE USER scadalink_svc FOR LOGIN scadalink_svc;
ALTER ROLE db_owner ADD MEMBER scadalink_svc;
CREATE DATABASE ScadaBridge_MachineData;
USE ScadaBridge_MachineData;
CREATE USER scadabridge_svc FOR LOGIN scadabridge_svc;
ALTER ROLE db_owner ADD MEMBER scadabridge_svc;
```
3. Apply EF Core migrations (development):
- Migrations auto-apply on startup in Development environment.
4. Apply EF Core migrations (production):
- Generate SQL script: `dotnet ef migrations script --project src/ScadaLink.ConfigurationDatabase`
- Generate SQL script: `dotnet ef migrations script --project src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase`
- Review and execute the SQL script against the production database.
## Network Requirements
@@ -189,7 +189,7 @@ Ensure bidirectional TCP connectivity between all Akka.NET cluster peers. The re
## Post-Installation Verification
1. Start the service: `sc.exe start ScadaLink-Central`
2. Check the log file: `type C:\ScadaLink\logs\scadalink-*.log`
1. Start the service: `sc.exe start ScadaBridge-Central`
2. Check the log file: `type C:\ScadaBridge\logs\scadabridge-*.log`
3. Verify the readiness endpoint: `curl http://localhost:5000/health/ready`
4. For Central: verify the UI is accessible at `https://central-01.example.com/`
+13 -13
View File
@@ -1,26 +1,26 @@
# ScadaLink Production Deployment Checklist
# ScadaBridge Production Deployment Checklist
## Pre-Deployment
### Configuration Verification
- [ ] `ScadaLink:Node:Role` is set correctly (`Central` or `Site`)
- [ ] `ScadaLink:Node:NodeHostname` matches the machine's resolvable hostname
- [ ] `ScadaLink:Cluster:SeedNodes` contains exactly 2 entries for the cluster pair
- [ ] `ScadaBridge:Node:Role` is set correctly (`Central` or `Site`)
- [ ] `ScadaBridge:Node:NodeHostname` matches the machine's resolvable hostname
- [ ] `ScadaBridge:Cluster:SeedNodes` contains exactly 2 entries for the cluster pair
- [ ] Seed node addresses use fully qualified hostnames (not `localhost`)
- [ ] Remoting port (default 8081) is open bidirectionally between cluster peers
### Central Node
- [ ] `ScadaLink:Database:ConfigurationDb` connection string is valid and tested
- [ ] `ScadaLink:Database:MachineDataDb` connection string is valid and tested
- [ ] `ScadaBridge:Database:ConfigurationDb` connection string is valid and tested
- [ ] `ScadaBridge:Database:MachineDataDb` connection string is valid and tested
- [ ] SQL Server login has `db_owner` role on both databases
- [ ] EF Core migrations have been applied (SQL script reviewed and executed)
- [ ] `ScadaLink:Security:JwtSigningKey` is at least 32 characters, randomly generated
- [ ] `ScadaBridge:Security:JwtSigningKey` is at least 32 characters, randomly generated
- [ ] **Both central nodes use the same JwtSigningKey** (required for JWT failover)
- [ ] `ScadaLink:Security:LdapServer` points to the production LDAP/AD server
- [ ] `ScadaLink:Security:LdapUseTls` is `true` (LDAPS required in production)
- [ ] `ScadaLink:Security:AllowInsecureLdap` is `false`
- [ ] `ScadaBridge:Security:LdapServer` points to the production LDAP/AD server
- [ ] `ScadaBridge:Security:LdapUseTls` is `true` (LDAPS required in production)
- [ ] `ScadaBridge:Security:AllowInsecureLdap` is `false`
- [ ] LDAP search base DN is correct for the organization
- [ ] LDAP group-to-role mappings are configured
- [ ] Load balancer is configured in front of central UI (sticky sessions not required)
@@ -29,10 +29,10 @@
### Site Node
- [ ] `ScadaLink:Node:SiteId` is set and unique across all sites
- [ ] `ScadaLink:Database:SiteDbPath` points to a writable directory
- [ ] `ScadaBridge:Node:SiteId` is set and unique across all sites
- [ ] `ScadaBridge:Database:SiteDbPath` points to a writable directory
- [ ] SQLite data directory has sufficient disk space (no max buffer size for S&F)
- [ ] `ScadaLink:Communication:CentralSeedNode` points to a reachable central node
- [ ] `ScadaBridge:Communication:CentralSeedNode` points to a reachable central node
- [ ] OPC UA server endpoints are accessible from site nodes
- [ ] OPC UA security certificates are configured if required
+11 -11
View File
@@ -1,8 +1,8 @@
# ScadaLink Cluster Topology Guide
# ScadaBridge Cluster Topology Guide
## Architecture Overview
ScadaLink uses a hub-and-spoke architecture:
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.
@@ -34,7 +34,7 @@ Both central nodes must be configured as seed nodes for each other:
**Node A** (`central-01.example.com`):
```json
{
"ScadaLink": {
"ScadaBridge": {
"Node": {
"Role": "Central",
"NodeHostname": "central-01.example.com",
@@ -42,8 +42,8 @@ Both central nodes must be configured as seed nodes for each other:
},
"Cluster": {
"SeedNodes": [
"akka.tcp://scadalink@central-01.example.com:8081",
"akka.tcp://scadalink@central-02.example.com:8081"
"akka.tcp://scadabridge@central-01.example.com:8081",
"akka.tcp://scadabridge@central-02.example.com:8081"
]
}
}
@@ -53,7 +53,7 @@ Both central nodes must be configured as seed nodes for each other:
**Node B** (`central-02.example.com`):
```json
{
"ScadaLink": {
"ScadaBridge": {
"Node": {
"Role": "Central",
"NodeHostname": "central-02.example.com",
@@ -61,8 +61,8 @@ Both central nodes must be configured as seed nodes for each other:
},
"Cluster": {
"SeedNodes": [
"akka.tcp://scadalink@central-01.example.com:8081",
"akka.tcp://scadalink@central-02.example.com:8081"
"akka.tcp://scadabridge@central-01.example.com:8081",
"akka.tcp://scadabridge@central-02.example.com:8081"
]
}
}
@@ -101,7 +101,7 @@ Each site has its own two-node cluster:
**Site Node A** (`site-01-a.example.com`):
```json
{
"ScadaLink": {
"ScadaBridge": {
"Node": {
"Role": "Site",
"NodeHostname": "site-01-a.example.com",
@@ -110,8 +110,8 @@ Each site has its own two-node cluster:
},
"Cluster": {
"SeedNodes": [
"akka.tcp://scadalink@site-01-a.example.com:8081",
"akka.tcp://scadalink@site-01-b.example.com:8081"
"akka.tcp://scadabridge@site-01-a.example.com:8081",
"akka.tcp://scadabridge@site-01-b.example.com:8081"
]
}
}