namespace Campaign_Tracker.Server.Audit; /// /// Shared audit event type constants used across all application features. /// public static class AuditEventType { public const string SessionLogin = "SESSION_LOGIN"; public const string SessionLoginFailure = "SESSION_LOGIN_FAILURE"; public const string SessionRefresh = "SESSION_REFRESH"; public const string SessionRefreshFailure = "SESSION_REFRESH_FAILURE"; public const string SessionLogout = "SESSION_LOGOUT"; public const string AuthorizationAllowed = "AUTHORIZATION_ALLOWED"; public const string AuthorizationDenied = "AUTHORIZATION_DENIED"; } /// /// A general-purpose audit event record written by any application feature. /// All fields are required; no nullable properties to prevent incomplete records. /// public sealed record AuditEvent( string EventType, string ActorIdentity, string Resource, string Outcome, string TraceIdentifier, DateTimeOffset RecordedAt); /// /// Shared audit logging service contract. All application features record /// security-relevant events through this interface — features must not /// implement their own audit persistence (AC #3). /// /// Record() is synchronous and throws if the underlying store is unavailable. /// Callers must not silently swallow these exceptions; failed audit writes /// must block or surface the originating action (AC #5). /// public interface IAuditService { /// /// Appends an audit event to the durable store. /// Throws if the store cannot be written to. /// void Record(AuditEvent auditEvent); /// /// Returns the most recent events from the in-process cache for review and testing. /// For full historical queries spanning 365+ days, read the underlying store directly. /// IReadOnlyCollection GetRecent(int maxCount = 200); } public sealed class AuditServiceUnavailableException : Exception { public AuditServiceUnavailableException(string message, Exception innerException) : base(message, innerException) { } }