diff --git a/src/ZB.MOM.WW.ScadaBridge.AuditLog/Kpi/AuditLogKpiSampleSource.cs b/src/ZB.MOM.WW.ScadaBridge.AuditLog/Kpi/AuditLogKpiSampleSource.cs
index 5e69d58f..4e77a18d 100644
--- a/src/ZB.MOM.WW.ScadaBridge.AuditLog/Kpi/AuditLogKpiSampleSource.cs
+++ b/src/ZB.MOM.WW.ScadaBridge.AuditLog/Kpi/AuditLogKpiSampleSource.cs
@@ -36,11 +36,12 @@ public sealed class AuditLogKpiSampleSource : IKpiSampleSource
///
private static readonly TimeSpan Window = TimeSpan.FromHours(1);
- // Metric catalog — the exact strings persisted in KpiSample.Metric. Stable
- // identifiers the recorder + UI trend charts key on; do not rename.
- private const string TotalEventsLastHourMetric = "totalEventsLastHour";
- private const string ErrorEventsLastHourMetric = "errorEventsLastHour";
- private const string BacklogTotalMetric = "backlogTotal";
+ // Metric catalog — the exact strings persisted in KpiSample.Metric. All three are
+ // charted, so they share the public Commons catalog: source + UI trend page key off
+ // one symbol (#178). Stable identifiers; do not rename (values are persisted).
+ private const string TotalEventsLastHourMetric = KpiMetrics.AuditLog.TotalEventsLastHour;
+ private const string ErrorEventsLastHourMetric = KpiMetrics.AuditLog.ErrorEventsLastHour;
+ private const string BacklogTotalMetric = KpiMetrics.AuditLog.BacklogTotal;
private readonly IAuditLogRepository _repository;
diff --git a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Audit/AuditLogPage.razor.cs b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Audit/AuditLogPage.razor.cs
index 17e69792..1656a05f 100644
--- a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Audit/AuditLogPage.razor.cs
+++ b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Audit/AuditLogPage.razor.cs
@@ -293,9 +293,9 @@ public partial class AuditLogPage : IDisposable
/// The metrics rendered in the panel, in display order.
private static readonly (string Metric, string Title, string? Unit)[] TrendMetrics =
{
- ("totalEventsLastHour", "Events / hour", null),
- ("errorEventsLastHour", "Error events / hour", null),
- ("backlogTotal", "Backlog", null),
+ (KpiMetrics.AuditLog.TotalEventsLastHour, "Events / hour", null),
+ (KpiMetrics.AuditLog.ErrorEventsLastHour, "Error events / hour", null),
+ (KpiMetrics.AuditLog.BacklogTotal, "Backlog", null),
};
/// Per-metric series state, keyed by the metric name.
diff --git a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Monitoring/Health.razor b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Monitoring/Health.razor
index a2381855..b71bfda1 100644
--- a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Monitoring/Health.razor
+++ b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Monitoring/Health.razor
@@ -593,13 +593,13 @@
var siteId = _trendSiteId;
(_connectionsDownSeries, _connectionsDownAvailable, _connectionsDownError) =
- await LoadTrendSeriesAsync("connectionsDown", siteId, fromUtc, toUtc);
+ await LoadTrendSeriesAsync(KpiMetrics.SiteHealth.ConnectionsDown, siteId, fromUtc, toUtc);
(_deadLettersSeries, _deadLettersAvailable, _deadLettersError) =
- await LoadTrendSeriesAsync("deadLetters", siteId, fromUtc, toUtc);
+ await LoadTrendSeriesAsync(KpiMetrics.SiteHealth.DeadLetters, siteId, fromUtc, toUtc);
(_scriptErrorsSeries, _scriptErrorsAvailable, _scriptErrorsError) =
- await LoadTrendSeriesAsync("scriptErrors", siteId, fromUtc, toUtc);
+ await LoadTrendSeriesAsync(KpiMetrics.SiteHealth.ScriptErrors, siteId, fromUtc, toUtc);
(_sfBufferDepthSeries, _sfBufferDepthAvailable, _sfBufferDepthError) =
- await LoadTrendSeriesAsync("sfBufferDepth", siteId, fromUtc, toUtc);
+ await LoadTrendSeriesAsync(KpiMetrics.SiteHealth.SfBufferDepth, siteId, fromUtc, toUtc);
}
finally
{
diff --git a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Notifications/NotificationKpis.razor b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Notifications/NotificationKpis.razor
index e2032706..f87c7747 100644
--- a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Notifications/NotificationKpis.razor
+++ b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Notifications/NotificationKpis.razor
@@ -279,11 +279,11 @@
// one metric's failure only blanks that one chart while the others still
// render their fetched data — and a throw never breaks the KPI tiles above.
(_queueDepthSeries, _queueDepthAvailable, _queueDepthError) =
- await LoadSeries("queueDepth", fromUtc, toUtc);
+ await LoadSeries(KpiMetrics.NotificationOutbox.QueueDepth, fromUtc, toUtc);
(_parkedSeries, _parkedAvailable, _parkedError) =
- await LoadSeries("parkedCount", fromUtc, toUtc);
+ await LoadSeries(KpiMetrics.NotificationOutbox.ParkedCount, fromUtc, toUtc);
(_deliveredSeries, _deliveredAvailable, _deliveredError) =
- await LoadSeries("deliveredLastInterval", fromUtc, toUtc);
+ await LoadSeries(KpiMetrics.NotificationOutbox.DeliveredLastInterval, fromUtc, toUtc);
}
finally
{
diff --git a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/SiteCalls/SiteCallsReport.razor.cs b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/SiteCalls/SiteCallsReport.razor.cs
index 742bfde5..69c14e95 100644
--- a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/SiteCalls/SiteCallsReport.razor.cs
+++ b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/SiteCalls/SiteCallsReport.razor.cs
@@ -591,11 +591,11 @@ public partial class SiteCallsReport
var fromUtc = toUtc - TimeSpan.FromHours(_windowHours);
(_bufferedSeries, _bufferedAvailable, _bufferedError) =
- await LoadSeriesAsync("buffered", fromUtc, toUtc);
+ await LoadSeriesAsync(KpiMetrics.SiteCallAudit.Buffered, fromUtc, toUtc);
(_parkedSeries, _parkedAvailable, _parkedError) =
- await LoadSeriesAsync("parked", fromUtc, toUtc);
+ await LoadSeriesAsync(KpiMetrics.SiteCallAudit.Parked, fromUtc, toUtc);
(_failedSeries, _failedAvailable, _failedError) =
- await LoadSeriesAsync("failedLastInterval", fromUtc, toUtc);
+ await LoadSeriesAsync(KpiMetrics.SiteCallAudit.FailedLastInterval, fromUtc, toUtc);
}
finally
{
diff --git a/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Kpi/KpiMetrics.cs b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Kpi/KpiMetrics.cs
new file mode 100644
index 00000000..6ceff384
--- /dev/null
+++ b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Kpi/KpiMetrics.cs
@@ -0,0 +1,98 @@
+namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Kpi;
+
+///
+/// Canonical charted KPI metric-name identifiers (M6 "KPI History &
+/// Trends") — the value of
+/// for every metric a Central UI trend chart renders. Each owning
+/// emits
+/// these strings and each trend page keys its GetSeriesAsync lookup on the same
+/// strings; promoting them to one shared public symbol means the source and the page key
+/// off a single declaration, so a future rename becomes a compiler-enforced single edit
+/// rather than a silently-blanked chart.
+///
+///
+///
+/// Each constant's value is the metric string as persisted in the tall/EAV
+/// KpiSample table and matched at query time. These values are therefore part of
+/// the on-disk data contract: this catalog is a symbol-promotion of the existing literals,
+/// not a rename — changing any value would orphan historical samples.
+///
+///
+/// Only the metrics a trend page actually charts are catalogued here. Sources may emit
+/// additional internal metrics (e.g. the Notification Outbox stuckCount /
+/// oldestPendingAgeSeconds, the Site Call Audit deliveredLastInterval /
+/// stuck / oldestPendingAgeSeconds, and the bulk of the Site Health catalog)
+/// that no page references; those stay private to their source until a page charts them.
+/// Constants are grouped by source via nested static classes mirroring
+/// .
+///
+///
+public static class KpiMetrics
+{
+ ///
+ /// Charted Notification Outbox (#21) metrics — .
+ /// Rendered by the Central UI Notification Outbox KPIs trend panel.
+ ///
+ public static class NotificationOutbox
+ {
+ /// Pending-queue depth (rows awaiting delivery).
+ public const string QueueDepth = "queueDepth";
+
+ /// Parked-row count.
+ public const string ParkedCount = "parkedCount";
+
+ /// Rows delivered in the last KPI interval.
+ public const string DeliveredLastInterval = "deliveredLastInterval";
+ }
+
+ ///
+ /// Charted Site Call Audit (#22) metrics — .
+ /// Rendered by the Central UI Site Calls report trend panel.
+ ///
+ public static class SiteCallAudit
+ {
+ /// Buffered (non-terminal) cached-call count.
+ public const string Buffered = "buffered";
+
+ /// Parked cached-call count.
+ public const string Parked = "parked";
+
+ /// Cached calls that failed permanently in the last KPI interval.
+ public const string FailedLastInterval = "failedLastInterval";
+ }
+
+ ///
+ /// Charted Audit Log (#23) metrics — .
+ /// Rendered by the Central UI Audit Log page trend panel.
+ ///
+ public static class AuditLog
+ {
+ /// Audit events recorded in the trailing hour.
+ public const string TotalEventsLastHour = "totalEventsLastHour";
+
+ /// Error-row audit events recorded in the trailing hour.
+ public const string ErrorEventsLastHour = "errorEventsLastHour";
+
+ /// Total pending (not-yet-forwarded) audit backlog.
+ public const string BacklogTotal = "backlogTotal";
+ }
+
+ ///
+ /// Charted Site Health (#11) metrics — .
+ /// Rendered by the Central UI Health-dashboard per-site trend panel.
+ ///
+ public static class SiteHealth
+ {
+ /// Data connections not in the Connected state.
+ public const string ConnectionsDown = "connectionsDown";
+
+ /// Dead-letter count reported by the site.
+ public const string DeadLetters = "deadLetters";
+
+ /// Script-execution error count reported by the site.
+ public const string ScriptErrors = "scriptErrors";
+
+ /// Summed store-and-forward buffer depth across all buffers.
+ public const string SfBufferDepth = "sfBufferDepth";
+ }
+}
diff --git a/src/ZB.MOM.WW.ScadaBridge.HealthMonitoring/Kpi/SiteHealthKpiSampleSource.cs b/src/ZB.MOM.WW.ScadaBridge.HealthMonitoring/Kpi/SiteHealthKpiSampleSource.cs
index 0ae3ae4b..2ef5a2a4 100644
--- a/src/ZB.MOM.WW.ScadaBridge.HealthMonitoring/Kpi/SiteHealthKpiSampleSource.cs
+++ b/src/ZB.MOM.WW.ScadaBridge.HealthMonitoring/Kpi/SiteHealthKpiSampleSource.cs
@@ -34,13 +34,15 @@ namespace ZB.MOM.WW.ScadaBridge.HealthMonitoring.Kpi;
public sealed class SiteHealthKpiSampleSource : IKpiSampleSource
{
// ── Metric catalog (the M6-agreed metric-name strings for this source) ──
- // Declaration order matches the emission order in AddSiteSnapshot.
+ // Declaration order matches the emission order in AddSiteSnapshot. Charted metrics
+ // share the public Commons catalog so source + UI trend page key off one symbol
+ // (#178); the uncharted internal metrics stay private here.
private const string MetricConnectionsUp = "connectionsUp";
- private const string MetricConnectionsDown = "connectionsDown";
- private const string MetricScriptErrors = "scriptErrors";
+ private const string MetricConnectionsDown = KpiMetrics.SiteHealth.ConnectionsDown;
+ private const string MetricScriptErrors = KpiMetrics.SiteHealth.ScriptErrors;
private const string MetricAlarmEvalErrors = "alarmEvalErrors";
- private const string MetricSfBufferDepth = "sfBufferDepth";
- private const string MetricDeadLetters = "deadLetters";
+ private const string MetricSfBufferDepth = KpiMetrics.SiteHealth.SfBufferDepth;
+ private const string MetricDeadLetters = KpiMetrics.SiteHealth.DeadLetters;
private const string MetricParkedMessages = "parkedMessages";
private const string MetricDeployedInstances = "deployedInstances";
private const string MetricEnabledInstances = "enabledInstances";
diff --git a/src/ZB.MOM.WW.ScadaBridge.NotificationOutbox/Kpi/NotificationOutboxKpiSampleSource.cs b/src/ZB.MOM.WW.ScadaBridge.NotificationOutbox/Kpi/NotificationOutboxKpiSampleSource.cs
index e0b0174b..07dc6246 100644
--- a/src/ZB.MOM.WW.ScadaBridge.NotificationOutbox/Kpi/NotificationOutboxKpiSampleSource.cs
+++ b/src/ZB.MOM.WW.ScadaBridge.NotificationOutbox/Kpi/NotificationOutboxKpiSampleSource.cs
@@ -34,10 +34,12 @@ namespace ZB.MOM.WW.ScadaBridge.NotificationOutbox.Kpi;
///
public sealed class NotificationOutboxKpiSampleSource : IKpiSampleSource
{
- private const string MetricQueueDepth = "queueDepth";
+ // Charted metrics share the public Commons catalog so source + UI trend page key
+ // off one symbol (#178). The uncharted internal metrics stay private here.
+ private const string MetricQueueDepth = KpiMetrics.NotificationOutbox.QueueDepth;
private const string MetricStuckCount = "stuckCount";
- private const string MetricParkedCount = "parkedCount";
- private const string MetricDeliveredLastInterval = "deliveredLastInterval";
+ private const string MetricParkedCount = KpiMetrics.NotificationOutbox.ParkedCount;
+ private const string MetricDeliveredLastInterval = KpiMetrics.NotificationOutbox.DeliveredLastInterval;
private const string MetricOldestPendingAgeSeconds = "oldestPendingAgeSeconds";
private readonly INotificationOutboxRepository _repository;
diff --git a/src/ZB.MOM.WW.ScadaBridge.SiteCallAudit/Kpi/SiteCallAuditKpiSampleSource.cs b/src/ZB.MOM.WW.ScadaBridge.SiteCallAudit/Kpi/SiteCallAuditKpiSampleSource.cs
index 3accce76..93b59a4a 100644
--- a/src/ZB.MOM.WW.ScadaBridge.SiteCallAudit/Kpi/SiteCallAuditKpiSampleSource.cs
+++ b/src/ZB.MOM.WW.ScadaBridge.SiteCallAudit/Kpi/SiteCallAuditKpiSampleSource.cs
@@ -36,10 +36,12 @@ namespace ZB.MOM.WW.ScadaBridge.SiteCallAudit.Kpi;
public sealed class SiteCallAuditKpiSampleSource : IKpiSampleSource
{
// ── Metric catalog (the M6-agreed metric-name strings for this source) ──
- // Declaration order matches the emission order in AddSnapshot.
- private const string MetricBuffered = "buffered";
- private const string MetricParked = "parked";
- private const string MetricFailedLastInterval = "failedLastInterval";
+ // Declaration order matches the emission order in AddSnapshot. Charted metrics
+ // share the public Commons catalog so source + UI trend page key off one symbol
+ // (#178); the uncharted internal metrics stay private here.
+ private const string MetricBuffered = KpiMetrics.SiteCallAudit.Buffered;
+ private const string MetricParked = KpiMetrics.SiteCallAudit.Parked;
+ private const string MetricFailedLastInterval = KpiMetrics.SiteCallAudit.FailedLastInterval;
private const string MetricDeliveredLastInterval = "deliveredLastInterval";
private const string MetricStuck = "stuck";
private const string MetricOldestPendingAgeSeconds = "oldestPendingAgeSeconds";