Enterprise Audit Trail
Full audit logging with 23 entity fields, module auto-detection, correlation tracking, real-time SignalR broadcasting, and 45+ event types across 13 categories.
SCRIPE's enterprise audit trail captures every significant action across the platform — from authentication events and entity mutations to permission changes, security incidents, and guardian protection enforcement. Each audit entry records 23 fields including CorrelationId for request tracing, TenantId for multi-tenant isolation, ModuleTag for module-level filtering, and IpAddress/UserAgent for forensic analysis. Events are broadcast in real-time via SignalR to connected dashboards.
Audit Trail Architecture
AuditLog Entity Schema (23 Fields)
The AuditLog entity captures comprehensive context for every auditable event. Old and new values are stored as JSON snapshots for full change history and regulatory compliance. The entity includes forensic data (IpAddress, UserAgent) and operational metadata (DurationMs, StatusCode, Metadata).
| Column | Type | Nullable | Purpose |
|---|---|---|---|
| Id | Guid | No | Unique audit entry identifier (auto-generated) |
| EventType | string(50) | No | Event classification — see Event Types table below |
| HttpMethod | string(10) | Yes | HTTP verb (GET, POST, PUT, DELETE) |
| Endpoint | string(500) | Yes | API path that was called (e.g., /api/admins/123) |
| EntityType | string(100) | Yes | Entity affected (Admin, Role, Tenant, Edition, etc.) |
| EntityId | string(100) | Yes | Encrypted entity ID (AES-256 encrypted) |
| OldValues | JSON (nvarchar max) | Yes | Previous state snapshot — stored for update/delete operations |
| NewValues | JSON (nvarchar max) | Yes | New state snapshot — stored for create/update operations |
| ChangedProperties | string(1000) | Yes | Comma-separated list of changed field names |
| UserId | Guid | Yes | Who performed the action (null for anonymous/system) |
| TenantId | Guid | Yes | Tenant context — used for scoping in tenant dashboards |
| Username | string(100) | Yes | Display name of the user who performed the action |
| IsAdmin | bool | No | Whether the user is an admin (for client-user distinction) |
| IpAddress | string(50) | Yes | Client IP address (IPv4 or IPv6) |
| UserAgent | string(500) | Yes | Browser/device user agent string |
| CorrelationId | string(50) | Yes | Links all audit entries from the same HTTP request |
| ModuleTag | string(50) | Yes | Auto-detected module (Identity, Entitlements, System, etc.) |
| StatusCode | int | Yes | HTTP response status code (200, 400, 401, 403, 500, etc.) |
| DurationMs | long | Yes | Request processing time in milliseconds |
| IsSuccess | bool | No | Whether the operation succeeded (default: true) |
| ErrorMessage | string(max) | Yes | Error details if operation failed |
| Metadata | JSON (nvarchar max) | Yes | Additional context data as JSON (e.g., batch counts, custom data) |
| Timestamp | DateTime | No | UTC timestamp of the event (default: DateTime.UtcNow) |
Module Auto-Detection
The AuditService automatically determines which module generated each audit event using a 3-priority detection chain: (1) Event-type hardcoded mapping for auth events, (2) API endpoint path-based mapping, (3) Entity type name-based mapping. Unknown modules are auto-capitalized from the URL segment. This eliminates manual tagging and ensures consistent module attribution.
| Detection Source | Example Input | Detected Module | Priority |
|---|---|---|---|
| Event Type (hardcoded) | Login, LoginFailed, Logout | Identity | Highest — event-based override |
| Endpoint path | /api/admins/123 | Identity | Primary — URL-based detection |
| Endpoint path | /api/roles | Identity | Primary |
| Endpoint path | /api/tenants | Identity | Primary |
| Endpoint path | /api/editions | Entitlements | Primary |
| Endpoint path | /api/features | Entitlements | Primary |
| Endpoint path | /api/subscriptions | Entitlements | Primary |
| Endpoint path | /api/audit-logs | System | Primary |
| Endpoint path | /api/products | Products (auto-capitalized) | Fallback — unknown modules auto-mapped |
| Entity Type name | Admin, Role, Tenant | Identity | Secondary — entity-based detection |
| Entity Type name | Edition, Feature | Entitlements | Secondary |
private string DetectModule(AuditLog log)
{
// Priority 1: Event-type hardcoded mapping
if (log.EventType is AuditEventTypes.Login
or AuditEventTypes.LoginFailed
or AuditEventTypes.Logout
or AuditEventTypes.TokenRefresh)
return "Identity";
// Priority 2: Endpoint path-based mapping
if (!string.IsNullOrEmpty(log.Endpoint))
{
var segment = ExtractFirstSegment(log.Endpoint);
return _endpointModuleMap.GetValueOrDefault(
segment, Capitalize(segment));
}
// Priority 3: Entity type-based mapping
if (!string.IsNullOrEmpty(log.EntityType))
return _entityModuleMap.GetValueOrDefault(
log.EntityType, "System");
return "System"; // Fallback
}Audit Event Types (45+)
| Category | Event Types | Description |
|---|---|---|
| Authentication | Login, LoginFailed, Logout, TokenRefresh | User session lifecycle events |
| CRUD Operations | Create, Update, Delete | Entity data mutations with old/new value snapshots |
| Security | AccessDenied, PrivilegeEscalationAttempt, AdminImpersonation | Security-sensitive or blocked actions |
| Password | PasswordChange, PasswordReset, PasswordChanged | Credential management events |
| Account | AccountLocked, AccountUnlocked, AdminStatusChanged | Account state changes |
| 2FA | TwoFactorEnabled, TwoFactorDisabled, TwoFactorVerified, BackupCodeUsed, BackupCodesRegenerated | Multi-factor authentication lifecycle |
| Session | SessionRevoked, AllSessionsRevoked | Session management and forced logout |
| RBAC | RoleAssigned, RoleUnassigned, PermissionGranted, PermissionRevoked, ScopeChanged | Access control changes |
| Tenant | TenantAccess, HierarchyAccess, TenantPermissionsUpdated, BulkTenantCascadeDelete | Tenant hierarchy and cross-tenant operations |
| Bulk Operations | BulkAdminDelete, BulkAdminStatusUpdate | Batch mutations affecting multiple entities |
| Profile | ProfileUpdated | User self-service profile changes |
| Guardian | GuardianAdminDeleteBlocked, GuardianAdminTransferBlocked, GuardianAdminDemoteBlocked, GuardianAdminDeactivateBlocked, GuardianRoleDeleteBlocked, GuardianRolePermissionBlocked, GuardianTenantCreated | Protection system enforcement — prevents destruction of critical resources |
| System | Request, Error | HTTP request logging and unhandled error tracking |
Real-Time Broadcasting
Audit events (excluding routine HTTP Request logs to avoid flooding) are broadcast via SignalR to connected clients. Events are scoped by tenant — tenant admins only see their own tenant's events via tenant-specific groups, while super admins receive all events via the global group.
// Audit events are broadcast to connected dashboards in real-time.
// Routine HTTP request logs (EventType == "Request") are excluded
// to avoid flooding the WebSocket channel.
if (log.EventType != AuditEventTypes.Request)
{
var dto = MapToSignalRDto(log);
// 1. Tenant-specific group (tenant admins see their own events)
if (log.TenantId.HasValue)
{
await _hubContext.Clients
.Group(HubGroupNames.ForTenant(log.TenantId.Value))
.AuditEvent(dto);
}
// 2. Global group (super admins see everything)
await _hubContext.Clients
.Group(HubGroupNames.Global)
.AuditEvent(dto);
}Audit Log Query API
The audit log query endpoint supports comprehensive filtering with 12 parameters. All filters are optional and can be combined. Results are paginated (default: 20 items, max: 100) and sorted by timestamp descending. Encrypted IDs are used for UserId and TenantId filters.
# Get all audit logs (paginated)
GET /api/audit-logs?page=1&pageSize=20
# Filter by event type
GET /api/audit-logs?eventType=Login&page=1&pageSize=50
# Filter by module
GET /api/audit-logs?moduleTag=Identity
# Filter by date range
GET /api/audit-logs?dateFrom=2026-04-01&dateTo=2026-04-06
# Filter by user
GET /api/audit-logs?userId=<encrypted-id>
# Trace a request (find all logs from one HTTP request)
GET /api/audit-logs?correlationId=abc-123-def
# Combined filters
GET /api/audit-logs?eventType=Create&entityType=Admin&moduleTag=Identity&dateFrom=2026-04-01| Filter Parameter | Type | Description |
|---|---|---|
| eventType | string | Filter by AuditEventType (Login, Create, Update, Delete, etc.) |
| entityType | string | Filter by entity name (Admin, Role, Tenant, Edition) |
| userId | string (encrypted) | Filter by the user who performed the action |
| tenantId | string (encrypted) | Filter by tenant context |
| moduleTag | string | Filter by module (Identity, Entitlements, System) |
| dateFrom | datetime | Start of date range (ISO 8601 format) |
| dateTo | datetime | End of date range (ISO 8601 format) |
| correlationId | string | Trace all entries from a single HTTP request |
| isSuccess | bool | Filter by success/failure status |
| search | string | Full-text search across Endpoint, EntityType, Username |
| page | int | Page number (default: 1) |
| pageSize | int | Items per page (default: 20, max: 100) |