diff --git a/docker/site-a-node-a/appsettings.Site.json b/docker/site-a-node-a/appsettings.Site.json index 7c841b41..53be3432 100644 --- a/docker/site-a-node-a/appsettings.Site.json +++ b/docker/site-a-node-a/appsettings.Site.json @@ -64,6 +64,23 @@ // outside the volume and were lost on every recreate. // Replication is opt-in and configured separately; absent = local-only. "LocalDb": { - "Path": "/app/data/site-localdb.db" + "Path": "/app/data/site-localdb.db", + // Site-a is the rig's REPLICATED pair; site-b and site-c deliberately stay + // unreplicated so the default-OFF posture is proven side-by-side on one rig. + // + // This node is the initiator: it dials the peer. Replication is still + // bidirectional - the passive node's writes flow back over the same stream - + // so only one side needs PeerAddress. Port 8083 is the existing site gRPC + // listener (h2c); the sync endpoint shares it, no new port. + // + // The ApiKey must be IDENTICAL on both nodes: the host's + // LocalDbSyncAuthInterceptor is fail-closed, so a mismatch (or a missing key) + // rejects every sync stream. A plain dev key here matches the rig's existing + // posture; PRODUCTION uses a "${secret:...}" reference resolved by the + // pre-host secret expander. + "Replication": { + "PeerAddress": "http://scadabridge-site-a-b:8083", + "ApiKey": "dev-site-a-localdb-sync-key" + } } } diff --git a/docker/site-a-node-b/appsettings.Site.json b/docker/site-a-node-b/appsettings.Site.json index 299055cc..8e7bd55c 100644 --- a/docker/site-a-node-b/appsettings.Site.json +++ b/docker/site-a-node-b/appsettings.Site.json @@ -64,6 +64,16 @@ // outside the volume and were lost on every recreate. // Replication is opt-in and configured separately; absent = local-only. "LocalDb": { - "Path": "/app/data/site-localdb.db" + "Path": "/app/data/site-localdb.db", + // The PASSIVE half of site-a's replicated pair: no PeerAddress, so this node's + // sync initiator starts and idles while node-a dials in. Its own writes still + // reach node-a - the stream is bidirectional. + // + // The key MUST match node-a's exactly. LocalDbSyncAuthInterceptor is + // fail-closed, so a typo here does not degrade to unauthenticated replication; + // it rejects every stream and the pair silently stops converging. + "Replication": { + "ApiKey": "dev-site-a-localdb-sync-key" + } } }