feat(auditlog): SqliteAuditWriter schema bootstrap (#23)

Adds the site-side SqliteAuditWriter skeleton with schema bootstrap —
20-column AuditLog table + IX_SiteAuditLog_ForwardState_Occurred index +
PRAGMA auto_vacuum = INCREMENTAL — and the SqliteAuditWriterOptions
companion type. Mirrors the SiteEventLogger pattern: single owned
SqliteConnection serialised behind a write lock; the Channel-based
hot-path lands in Bundle B-T2.

Adds Microsoft.Data.Sqlite + Microsoft.Extensions.Logging.Abstractions
project refs to ScadaLink.AuditLog; adds Microsoft.Data.Sqlite +
Microsoft.Extensions.Logging.Abstractions + NSubstitute test refs.

Tests (3 new, total 13 -> 16):
- Opens_Creates_AuditLog_Table_With_20Columns_And_PK_On_EventId
- Opens_Creates_IX_ForwardState_Occurred_Index
- PRAGMA_auto_vacuum_Is_INCREMENTAL
This commit is contained in:
Joseph Doherty
2026-05-20 12:17:02 -04:00
parent d745ef0715
commit 7173a79ad7
5 changed files with 269 additions and 0 deletions
@@ -0,0 +1,27 @@
namespace ScadaLink.AuditLog.Site;
/// <summary>
/// Options for the site-side SQLite hot-path audit writer.
/// Mirrors the ScadaLink.SiteEventLogging pattern: a single SQLite connection
/// fed by a background writer task draining a bounded
/// <see cref="System.Threading.Channels.Channel{T}"/> so script-thread enqueues
/// never block on disk I/O.
/// </summary>
public sealed class SqliteAuditWriterOptions
{
/// <summary>SQLite database path (or in-memory URI for tests).</summary>
public string DatabasePath { get; set; } = "auditlog.db";
/// <summary>
/// Capacity of the bounded write queue. Set high enough that ordinary
/// script bursts never fill it; <see cref="System.Threading.Channels.BoundedChannelFullMode.Wait"/>
/// applies when the writer falls behind.
/// </summary>
public int ChannelCapacity { get; set; } = 4096;
/// <summary>Max number of pending events the writer drains in one transaction.</summary>
public int BatchSize { get; set; } = 256;
/// <summary>Soft flush interval the writer enforces when fewer than BatchSize events are queued.</summary>
public int FlushIntervalMs { get; set; } = 50;
}