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) { }
}