feat(db): PendingSecuredWrite entity + migration + repository (T14b)

This commit is contained in:
Joseph Doherty
2026-06-18 02:09:31 -04:00
parent a0ce8b6c44
commit c799f41d53
10 changed files with 2477 additions and 0 deletions
@@ -0,0 +1,99 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.SecuredWrites;
namespace ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Configurations;
/// <summary>
/// Maps the <see cref="PendingSecuredWrite"/> entity to the central
/// <c>PendingSecuredWrites</c> table (M7 OPC UA / MxGateway UX, Task T14b).
/// Operational (mutable) state — NOT audit — so the table is non-partitioned,
/// standard <c>[PRIMARY]</c> filegroup, no DB-role restriction. Two named indexes
/// back the Central UI's "pending in this status, newest first" and "writes for
/// this site" queries. Mirrors <c>SiteCallEntityTypeConfiguration</c>.
/// </summary>
public class PendingSecuredWriteEntityTypeConfiguration : IEntityTypeConfiguration<PendingSecuredWrite>
{
/// <summary>
/// Configures the EF Core entity type mapping for <see cref="PendingSecuredWrite"/>.
/// </summary>
/// <param name="builder">The entity type builder to configure.</param>
public void Configure(EntityTypeBuilder<PendingSecuredWrite> builder)
{
builder.ToTable("PendingSecuredWrites");
// Surrogate identity key (bigint IDENTITY) — generated on insert.
builder.HasKey(p => p.Id);
builder.Property(p => p.Id)
.ValueGeneratedOnAdd();
// Bounded ASCII identifier columns.
builder.Property(p => p.SiteId)
.HasMaxLength(128)
.IsUnicode(false)
.IsRequired();
builder.Property(p => p.ConnectionName)
.HasMaxLength(128)
.IsUnicode(false)
.IsRequired();
builder.Property(p => p.TagPath)
.HasMaxLength(512)
.IsUnicode(false)
.IsRequired();
builder.Property(p => p.ValueType)
.HasMaxLength(128)
.IsUnicode(false)
.IsRequired();
// Enum-as-string lifecycle column (Pending|Approved|Rejected|Executed|Failed|Expired).
builder.Property(p => p.Status)
.HasMaxLength(32)
.IsUnicode(false)
.IsRequired();
builder.Property(p => p.OperatorUser)
.HasMaxLength(256)
.IsUnicode(false)
.IsRequired();
builder.Property(p => p.VerifierUser)
.HasMaxLength(256)
.IsUnicode(false);
// Larger ASCII payload column — JSON-serialised value to write.
builder.Property(p => p.ValueJson)
.HasMaxLength(4000)
.IsUnicode(false)
.IsRequired();
// Operator-facing free-text comments; ASCII, bounded.
builder.Property(p => p.OperatorComment)
.HasMaxLength(1024)
.IsUnicode(false);
builder.Property(p => p.VerifierComment)
.HasMaxLength(1024)
.IsUnicode(false);
// Execution error detail; ASCII, bounded a bit larger to capture target faults.
builder.Property(p => p.ExecutionError)
.HasMaxLength(2048)
.IsUnicode(false);
// Timestamps are UTC datetime2 throughout (EF default for DateTime on SQL Server).
builder.Property(p => p.SubmittedAtUtc)
.IsRequired();
// Indexes — names locked for migration/operational discoverability.
// Status_Submitted backs "pending writes in this status, newest first".
builder.HasIndex(p => new { p.Status, p.SubmittedAtUtc })
.HasDatabaseName("IX_PendingSecuredWrites_Status_Submitted");
// Site backs "secured writes for this site".
builder.HasIndex(p => p.SiteId)
.HasDatabaseName("IX_PendingSecuredWrites_Site");
}
}