From 5d3a5a40d78f9eea4c7e23c033c43a80cc0bca20 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 26 May 2026 04:27:18 -0400 Subject: [PATCH] feat(commons): add deploy/admin/audit/redundancy/fleet message contracts --- .../Messages/Admin/StartDeployment.cs | 11 +++++++++ .../Messages/Admin/StartDeploymentResult.cs | 23 +++++++++++++++++++ .../Messages/Audit/AuditEvent.cs | 17 ++++++++++++++ .../Messages/Deploy/ApplyAck.cs | 15 ++++++++++++ .../Messages/Deploy/DeploymentFailed.cs | 14 +++++++++++ .../Messages/Deploy/DeploymentSealed.cs | 13 +++++++++++ .../Messages/Deploy/DispatchDeployment.cs | 13 +++++++++++ .../Messages/Fleet/FleetStatusChanged.cs | 21 +++++++++++++++++ .../Redundancy/NodeRedundancyState.cs | 16 +++++++++++++ .../Redundancy/RedundancyStateChanged.cs | 11 +++++++++ 10 files changed, 154 insertions(+) create mode 100644 src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Admin/StartDeployment.cs create mode 100644 src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Admin/StartDeploymentResult.cs create mode 100644 src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Audit/AuditEvent.cs create mode 100644 src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Deploy/ApplyAck.cs create mode 100644 src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Deploy/DeploymentFailed.cs create mode 100644 src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Deploy/DeploymentSealed.cs create mode 100644 src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Deploy/DispatchDeployment.cs create mode 100644 src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Fleet/FleetStatusChanged.cs create mode 100644 src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Redundancy/NodeRedundancyState.cs create mode 100644 src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Redundancy/RedundancyStateChanged.cs diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Admin/StartDeployment.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Admin/StartDeployment.cs new file mode 100644 index 0000000..797097c --- /dev/null +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Admin/StartDeployment.cs @@ -0,0 +1,11 @@ +using ZB.MOM.WW.OtOpcUa.Commons.Types; + +namespace ZB.MOM.WW.OtOpcUa.Commons.Messages.Admin; + +/// +/// Request from the admin UI to the AdminOperationsActor singleton asking it to snapshot +/// the current live-edit state and start a deployment. +/// +public sealed record StartDeployment( + string CreatedBy, + CorrelationId CorrelationId); diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Admin/StartDeploymentResult.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Admin/StartDeploymentResult.cs new file mode 100644 index 0000000..8e72a5d --- /dev/null +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Admin/StartDeploymentResult.cs @@ -0,0 +1,23 @@ +using ZB.MOM.WW.OtOpcUa.Commons.Types; + +namespace ZB.MOM.WW.OtOpcUa.Commons.Messages.Admin; + +public enum StartDeploymentOutcome +{ + Accepted, + NoChanges, + AnotherDeploymentInFlight, + Rejected, +} + +/// +/// Reply from the AdminOperationsActor singleton. Accepted means the snapshot +/// was sealed and a Deployment row was created; the in-flight deployment can be +/// tracked through fleet-status broadcasts. +/// +public sealed record StartDeploymentResult( + StartDeploymentOutcome Outcome, + DeploymentId? DeploymentId, + RevisionHash? RevisionHash, + string? Message, + CorrelationId CorrelationId); diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Audit/AuditEvent.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Audit/AuditEvent.cs new file mode 100644 index 0000000..ed12a26 --- /dev/null +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Audit/AuditEvent.cs @@ -0,0 +1,17 @@ +using ZB.MOM.WW.OtOpcUa.Commons.Types; + +namespace ZB.MOM.WW.OtOpcUa.Commons.Messages.Audit; + +/// +/// Cluster-broadcast audit event consumed by the AuditWriterActor singleton, which +/// batches and idempotently inserts into ConfigAuditLog. +/// +public sealed record AuditEvent( + Guid EventId, + string Category, + string Action, + string Actor, + DateTime OccurredAtUtc, + string? DetailsJson, + NodeId SourceNode, + CorrelationId CorrelationId); diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Deploy/ApplyAck.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Deploy/ApplyAck.cs new file mode 100644 index 0000000..10ff6f7 --- /dev/null +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Deploy/ApplyAck.cs @@ -0,0 +1,15 @@ +using ZB.MOM.WW.OtOpcUa.Commons.Types; + +namespace ZB.MOM.WW.OtOpcUa.Commons.Messages.Deploy; + +public enum ApplyAckOutcome { Applied, Failed } + +/// +/// Per-node acknowledgment returned by DriverHostActor to the dispatching coordinator. +/// +public sealed record ApplyAck( + DeploymentId DeploymentId, + NodeId NodeId, + ApplyAckOutcome Outcome, + string? FailureReason, + CorrelationId CorrelationId); diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Deploy/DeploymentFailed.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Deploy/DeploymentFailed.cs new file mode 100644 index 0000000..93878f9 --- /dev/null +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Deploy/DeploymentFailed.cs @@ -0,0 +1,14 @@ +using ZB.MOM.WW.OtOpcUa.Commons.Types; + +namespace ZB.MOM.WW.OtOpcUa.Commons.Messages.Deploy; + +/// +/// Coordinator-published event indicating that the deployment failed and was rolled back. +/// Includes the set of nodes that NACKed or timed out so the admin UI can surface which +/// node(s) are sticky on the prior good revision. +/// +public sealed record DeploymentFailed( + DeploymentId DeploymentId, + string FailureReason, + IReadOnlyList FailedNodes, + CorrelationId CorrelationId); diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Deploy/DeploymentSealed.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Deploy/DeploymentSealed.cs new file mode 100644 index 0000000..7f98333 --- /dev/null +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Deploy/DeploymentSealed.cs @@ -0,0 +1,13 @@ +using ZB.MOM.WW.OtOpcUa.Commons.Types; + +namespace ZB.MOM.WW.OtOpcUa.Commons.Messages.Deploy; + +/// +/// Coordinator-published event indicating that every active driver node successfully applied +/// the deployment and the row in Deployment has been transitioned to Sealed. +/// +public sealed record DeploymentSealed( + DeploymentId DeploymentId, + RevisionHash RevisionHash, + DateTime SealedAtUtc, + CorrelationId CorrelationId); diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Deploy/DispatchDeployment.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Deploy/DispatchDeployment.cs new file mode 100644 index 0000000..616398f --- /dev/null +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Deploy/DispatchDeployment.cs @@ -0,0 +1,13 @@ +using ZB.MOM.WW.OtOpcUa.Commons.Types; + +namespace ZB.MOM.WW.OtOpcUa.Commons.Messages.Deploy; + +/// +/// Sent from the admin-role ConfigPublishCoordinator singleton to each driver node's +/// DriverHostActor. Tells the node to fetch the deployment artifact identified by +/// + and apply it. +/// +public sealed record DispatchDeployment( + DeploymentId DeploymentId, + RevisionHash RevisionHash, + CorrelationId CorrelationId); diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Fleet/FleetStatusChanged.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Fleet/FleetStatusChanged.cs new file mode 100644 index 0000000..e5095e9 --- /dev/null +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Fleet/FleetStatusChanged.cs @@ -0,0 +1,21 @@ +using ZB.MOM.WW.OtOpcUa.Commons.Types; + +namespace ZB.MOM.WW.OtOpcUa.Commons.Messages.Fleet; + +public enum FleetNodeHealth { Healthy, Degraded, Unreachable } + +public sealed record FleetNodeStatus( + NodeId NodeId, + FleetNodeHealth Health, + RevisionHash? CurrentRevision, + DateTime LastSeenUtc); + +/// +/// Periodic fleet-wide status broadcast pushed by FleetStatusBroadcaster to admin UI +/// subscribers via SignalR. +/// +public sealed record FleetStatusChanged( + IReadOnlyList Nodes, + DeploymentId? CurrentDeployment, + DateTime AsOfUtc, + CorrelationId CorrelationId); diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Redundancy/NodeRedundancyState.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Redundancy/NodeRedundancyState.cs new file mode 100644 index 0000000..c1e6cca --- /dev/null +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Redundancy/NodeRedundancyState.cs @@ -0,0 +1,16 @@ +using ZB.MOM.WW.OtOpcUa.Commons.Types; + +namespace ZB.MOM.WW.OtOpcUa.Commons.Messages.Redundancy; + +public enum RedundancyRole { Primary, Secondary, Detached } + +/// +/// Snapshot of a single node's redundancy state. Aggregated by RedundancyStateActor +/// to compute fleet-wide ServiceLevel. +/// +public sealed record NodeRedundancyState( + NodeId NodeId, + RedundancyRole Role, + bool IsClusterLeader, + bool IsRoleLeaderForDriver, + DateTime AsOfUtc); diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Redundancy/RedundancyStateChanged.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Redundancy/RedundancyStateChanged.cs new file mode 100644 index 0000000..6b21638 --- /dev/null +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Messages/Redundancy/RedundancyStateChanged.cs @@ -0,0 +1,11 @@ +using ZB.MOM.WW.OtOpcUa.Commons.Types; + +namespace ZB.MOM.WW.OtOpcUa.Commons.Messages.Redundancy; + +/// +/// Broadcast whenever the cluster's redundancy topology changes (node up/down, role-leader +/// change, partition heal). Subscribers compute their local OPC UA ServiceLevel from this. +/// +public sealed record RedundancyStateChanged( + IReadOnlyList Nodes, + CorrelationId CorrelationId);