Two audit systems
The PoC keeps two overlapping audit trails plus a third auth-specific log:
case_audit_events— the case-level event stream. Columns:case_id,company_id,actor_user_id,actor_type(INTERNAL_USER/ …),actor_identifier,event_type,entity_type,entity_id,metadatajsonb. Written from many places (useAuditLog.useLogEvent,useWorkflow,useChecklistOperations,Cases, edge functions). Read byCaseAuditLog/OrgAuditLog(cappedlimit(200)).checklist_audit_log— item-level, withaction,old_value,new_value,performed_by. Written byuseChecklistOperationsalongside the case event.auth_audit_log— login/logout, written server-side via the SECURITY DEFINER RPClog_auth_event(the one audit path that is not client-authored).
OrgAuditLog merges (1) and (3) client-side, re-sorts, and prefixes synthetic IDs
(auth- / case-) to avoid React key collisions — so the "org log" is two independent
200-row queries stitched together (≤ 400 rows, oldest lost beyond that).
Problems (detailed elsewhere)
- (1) is client-authored, best-effort, conditional, truncated.
- Only (3) is server-authored — an inconsistent trust boundary.
- The
event_type/entity_typestring vocabularies must match across writers, label maps, and filter lists, and they drift.
Rebuild implication
Collapse to one server-authored, append-only, tamper-evident audit stream with a typed event vocabulary and pagination. Item-level detail becomes structured metadata on that one stream, not a parallel table.