diff --git a/docs/requirements/Component-ManagementService.md b/docs/requirements/Component-ManagementService.md
index 1dbcef5c..a9a04ff0 100644
--- a/docs/requirements/Component-ManagementService.md
+++ b/docs/requirements/Component-ManagementService.md
@@ -131,7 +131,7 @@ The whole folder surface is reachable from the CLI as `template folder list|crea
### Sites
- **ListSites** / **GetSite**: Query site definitions.
-- **CreateSite** / **UpdateSite** / **DeleteSite**: Manage site definitions.
+- **CreateSite** / **UpdateSite** / **DeleteSite**: Manage site definitions. Create/Update validate `GrpcNodeAAddress` / `GrpcNodeBAddress` at the write boundary with `GrpcEndpointRules.TryValidate` (both optional; a non-empty value must be an absolute `http://` or `https://` URL with a host, e.g. `http://host:8083`) and reject a malformed value with a readable `COMMAND_FAILED` error naming the field — a scheme-less address used to be persisted and then throw inside central's channel build on the next site-address refresh (review 2026-10-21 03/R-1).
- **ListAreas** / **CreateArea** / **UpdateArea** / **DeleteArea**: Manage area hierarchies per site.
- **MoveArea** (`AreaId`, `NewParentAreaId?`): Re-parent an area within its own site; a null `NewParentAreaId` moves it to the site root. Delegates every rule to `AreaService.MoveAreaAsync` — rejects self-parent, descendant-parent (cycle), cross-site parent, and sibling name collision at the target level; the service writes the `"Move"` audit row. Same any-of `[Designer, Deployer]` gate as the other area mutations. CLI: `site area move`.
diff --git a/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs b/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs
index 9e9002f7..0cde809d 100644
--- a/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs
+++ b/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs
@@ -29,6 +29,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types.Deployment;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
using ZB.MOM.WW.ScadaBridge.Commons.Types.InboundApi;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Transport;
+using ZB.MOM.WW.ScadaBridge.Commons.Validation;
using ZB.MOM.WW.ScadaBridge.DeploymentManager;
using ZB.MOM.WW.ScadaBridge.HealthMonitoring;
using ZB.MOM.WW.ScadaBridge.Communication;
@@ -1885,8 +1886,23 @@ public class ManagementActor : ReceiveActor
return site;
}
+ ///
+ /// Rejects a malformed site gRPC address at the write boundary (review 2026-10-21
+ /// 03/R-1). Both addresses are optional, but a non-empty value must be an absolute
+ /// http(s) URL — anything else makes the central channel build throw inside
+ /// SitePairChannelProvider.UpdateSite on the next address refresh.
+ ///
+ private static void ValidateSiteGrpcAddresses(string? grpcNodeAAddress, string? grpcNodeBAddress)
+ {
+ if (!GrpcEndpointRules.TryValidate(grpcNodeAAddress, allowEmpty: true, out var errorA))
+ throw new ManagementCommandException($"GrpcNodeAAddress: {errorA}");
+ if (!GrpcEndpointRules.TryValidate(grpcNodeBAddress, allowEmpty: true, out var errorB))
+ throw new ManagementCommandException($"GrpcNodeBAddress: {errorB}");
+ }
+
private static async Task