Adds the four tables Streams B/C/F consume — Script (generation-scoped source code), VirtualTag (generation-scoped calculated-tag config), ScriptedAlarm (generation-scoped alarm config), and ScriptedAlarmState (logical-id-keyed persistent runtime state). ## New entities (net10, EF Core) - Script — stable logical ScriptId carries across generations; SourceHash is the compile-cache key (matches Core.Scripting's CompiledScriptCache). - VirtualTag — mandatory EquipmentId FK (plan decision #2, unified Equipment tree); ChangeTriggered/TimerIntervalMs + Historize flags; check constraints enforce "at least one trigger" + "timer >= 50ms". - ScriptedAlarm — required AlarmType ('AlarmCondition'/'LimitAlarm'/'OffNormalAlarm'/ 'DiscreteAlarm'); Severity 1..1000 range check; HistorizeToAveva default true per plan decision #15. - ScriptedAlarmState — keyed ONLY on ScriptedAlarmId (NOT generation-scoped) per plan decision #14 — ack state + audit trail must follow alarm identity across Modified generations. CommentsJson has ISJSON check for GxP audit. ## Migration EF-generated 20260420231641_AddPhase7ScriptingTables covers all 4 tables + indexes + check constraints + FKs to ConfigGeneration. sp_PublishGeneration required no changes — it only flips Draft->Published status; the new entities already carry GenerationId so they publish atomically with the rest of the config. ## Tests — 12/12 (design-time model introspection) Phase7ScriptingEntitiesTests covers: table registration, column maxlength + column types, unique indexes (Generation+LogicalId, Generation+EquipmentPath for VirtualTag and ScriptedAlarm), secondary indexes (SourceHash for cache lookup), check constraints (trigger-required, timer-min, severity-range, alarm-type-enum, CommentsJson-IsJson), ScriptedAlarmState PK is alarm-id not generation-scoped, ScriptedAlarm defaults (HistorizeToAveva=true, Retain=true, Severity=500, Enabled=true), DbSets wired, and the generated migration type exists for rollforward.
63 lines
2.8 KiB
C#
63 lines
2.8 KiB
C#
namespace ZB.MOM.WW.OtOpcUa.Configuration.Entities;
|
|
|
|
/// <summary>
|
|
/// Per Phase 7 plan decision #14 — persistent runtime state for each scripted alarm.
|
|
/// Survives process restart so operators don't re-ack and ack history survives for
|
|
/// GxP / 21 CFR Part 11 compliance. Keyed on <c>ScriptedAlarmId</c> logically (not
|
|
/// per-generation) because ack state follows the alarm's stable identity across
|
|
/// generations — a Modified alarm keeps its ack history.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// <c>ActiveState</c> is deliberately NOT persisted — it rederives from the current
|
|
/// predicate evaluation on startup. Only operator-supplied state (<see cref="AckedState"/>,
|
|
/// <see cref="ConfirmedState"/>, <see cref="ShelvingState"/>) + audit trail persist.
|
|
/// </para>
|
|
/// <para>
|
|
/// <see cref="CommentsJson"/> is an append-only JSON array of <c>{user, utc, text}</c>
|
|
/// tuples — one per operator comment. Core.ScriptedAlarms' <c>AlarmConditionState.Comments</c>
|
|
/// serializes directly into this column.
|
|
/// </para>
|
|
/// </remarks>
|
|
public sealed class ScriptedAlarmState
|
|
{
|
|
/// <summary>Logical FK — matches <see cref="ScriptedAlarm.ScriptedAlarmId"/>. One row per alarm identity.</summary>
|
|
public required string ScriptedAlarmId { get; set; }
|
|
|
|
/// <summary>Enabled/Disabled. Persists across restart per plan decision #14.</summary>
|
|
public required string EnabledState { get; set; } = "Enabled";
|
|
|
|
/// <summary>Unacknowledged / Acknowledged.</summary>
|
|
public required string AckedState { get; set; } = "Unacknowledged";
|
|
|
|
/// <summary>Unconfirmed / Confirmed.</summary>
|
|
public required string ConfirmedState { get; set; } = "Unconfirmed";
|
|
|
|
/// <summary>Unshelved / OneShotShelved / TimedShelved.</summary>
|
|
public required string ShelvingState { get; set; } = "Unshelved";
|
|
|
|
/// <summary>When a TimedShelve expires — null if not shelved or OneShotShelved.</summary>
|
|
public DateTime? ShelvingExpiresUtc { get; set; }
|
|
|
|
/// <summary>User who last acknowledged. Null if never acked.</summary>
|
|
public string? LastAckUser { get; set; }
|
|
|
|
/// <summary>Operator-supplied ack comment. Null if no comment or never acked.</summary>
|
|
public string? LastAckComment { get; set; }
|
|
|
|
public DateTime? LastAckUtc { get; set; }
|
|
|
|
/// <summary>User who last confirmed.</summary>
|
|
public string? LastConfirmUser { get; set; }
|
|
|
|
public string? LastConfirmComment { get; set; }
|
|
|
|
public DateTime? LastConfirmUtc { get; set; }
|
|
|
|
/// <summary>JSON array of operator comments, append-only (GxP audit).</summary>
|
|
public string CommentsJson { get; set; } = "[]";
|
|
|
|
/// <summary>Row write timestamp — tracks last state change.</summary>
|
|
public DateTime UpdatedAtUtc { get; set; }
|
|
}
|