feat(configdb): map AuditEvent to AuditLog table with PK and five named indexes (#23)

This commit is contained in:
Joseph Doherty
2026-05-20 10:05:49 -04:00
parent 08743bc42d
commit fb423b11ab
3 changed files with 208 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using ScadaLink.Commons.Entities.Audit;
namespace ScadaLink.ConfigurationDatabase.Configurations;
/// <summary>
/// Maps the <see cref="AuditEvent"/> record to the central <c>AuditLog</c> table
/// described in alog.md §4. Column lengths/types and the five named indexes are
/// fixed by that specification — keep this in sync with the doc.
/// </summary>
public class AuditLogEntityTypeConfiguration : IEntityTypeConfiguration<AuditEvent>
{
public void Configure(EntityTypeBuilder<AuditEvent> builder)
{
builder.ToTable("AuditLog");
builder.HasKey(e => e.EventId);
// Enum-as-string columns: bounded varchar(32) ASCII.
builder.Property(e => e.Channel)
.HasConversion<string>()
.HasMaxLength(32)
.IsUnicode(false)
.IsRequired();
builder.Property(e => e.Kind)
.HasConversion<string>()
.HasMaxLength(32)
.IsUnicode(false)
.IsRequired();
builder.Property(e => e.Status)
.HasConversion<string>()
.HasMaxLength(32)
.IsUnicode(false)
.IsRequired();
builder.Property(e => e.ForwardState)
.HasConversion<string>()
.HasMaxLength(32)
.IsUnicode(false);
// Ascii identifier columns — never carry user-supplied unicode.
builder.Property(e => e.SourceSiteId)
.HasMaxLength(64)
.IsUnicode(false);
builder.Property(e => e.SourceInstanceId)
.HasMaxLength(128)
.IsUnicode(false);
builder.Property(e => e.SourceScript)
.HasMaxLength(128)
.IsUnicode(false);
builder.Property(e => e.Actor)
.HasMaxLength(128)
.IsUnicode(false);
builder.Property(e => e.Target)
.HasMaxLength(256)
.IsUnicode(false);
// Bounded unicode message column.
builder.Property(e => e.ErrorMessage)
.HasMaxLength(1024);
// ErrorDetail, RequestSummary, ResponseSummary, Extra: leave as nvarchar(max).
// Indexes — names locked to alog.md §4 for reconciliation/migration discoverability.
builder.HasIndex(e => e.OccurredAtUtc)
.IsDescending(true)
.HasDatabaseName("IX_AuditLog_OccurredAtUtc");
builder.HasIndex(e => new { e.SourceSiteId, e.OccurredAtUtc })
.IsDescending(false, true)
.HasDatabaseName("IX_AuditLog_Site_Occurred");
builder.HasIndex(e => e.CorrelationId)
.HasFilter("[CorrelationId] IS NOT NULL")
.HasDatabaseName("IX_AuditLog_CorrelationId");
builder.HasIndex(e => new { e.Channel, e.Status, e.OccurredAtUtc })
.IsDescending(false, false, true)
.HasDatabaseName("IX_AuditLog_Channel_Status_Occurred");
builder.HasIndex(e => new { e.Target, e.OccurredAtUtc })
.IsDescending(false, true)
.HasFilter("[Target] IS NOT NULL")
.HasDatabaseName("IX_AuditLog_Target_Occurred");
}
}

View File

@@ -84,6 +84,7 @@ public class ScadaLinkDbContext : DbContext, IDataProtectionKeyContext
// Audit
public DbSet<AuditLogEntry> AuditLogEntries => Set<AuditLogEntry>();
public DbSet<AuditEvent> AuditLogs => Set<AuditEvent>();
// Data Protection Keys (for shared ASP.NET Data Protection across nodes)
public DbSet<DataProtectionKey> DataProtectionKeys => Set<DataProtectionKey>();