eng-audit-log-schema
Rating is derived from the repo's GitHub stars and shown for reference.
name: eng-audit-log-schema
description: Use when designing or reviewing the audit log schema for a legal AI product. Defines the canonical event record structure, required fields for legal-product compliance (attorney-client privilege considerations, regulatory retention rules, tamper-evidence), indexing strategy, retention policies, and the specific event types that must be logged in a law-firm or legal-AI context. Engineering skill — no practice-area jurisdictional notes.
license: MIT
metadata:
id: eng.audit-log-schema
category: eng
jurisdictions: [multi]
priority: P2
intent: [audit-log, schema, compliance, tamper-evidence, retention, observability]
related:
- eng-langfuse-trace-inspector
- eng-latency-slo-by-skill
- eng-cost-per-message-tracker
- eng-mcp-tool-registry
source: Louis — HAQQ Legal AI (github.com/sboghossian/mini-claude-for-legal)
version: "1.0"
Audit Log Schema
What it does
The audit log is the system of record for every meaningful event in the legal AI platform. It answers: who did what, to what, when, from where, and with what result. In a legal product, the audit log serves dual purposes: operational observability and legal/regulatory accountability.
Specifically, the audit log must be able to answer:
- "Did the AI access this client's documents before the conflict check was complete?"
- "What version of skill X was used when the AI generated this engagement letter?"
- "Who approved the deletion of matter Y's data, and when?"
- "Was the user's session authenticated before they queried a privileged document?"
Canonical event record
Every audit log entry is a single JSON object:
{
"event_id": "ulid or uuid-v7",
"event_type": "skill.invoked | user.auth | document.accessed | matter.created | ...",
"timestamp": "2025-05-14T09:31:42.123Z",
"timestamp_local": "2025-05-14T12:31:42.123+03:00",
"actor": {
"user_id": "usr_abc123",
"role": "associate | partner | admin | system",
"session_id": "sess_xyz789",
"ip_address": "203.0.113.42",
"user_agent": "..."
},
"resource": {
"type": "matter | document | skill | tool | session | user | org",
"id": "matter_2025-UAE-0147",
"name": "Al Baraka SPA"
},
"action": {
"name": "read | create | update | delete | invoke | approve | reject | transmit",
"detail": "Skill efirm-conflict-check invoked for new matter",
"result": "success | failure | partial",
"error_code": null,
"error_message": null
},
"context": {
"skill_id": "efirm-conflict-check",
"skill_version": "1.0",
"model_id": "claude-sonnet-4-6",
"trace_id": "langfuse-trace-id",
"request_id": "req_abc123"
},
"metadata": {
"org_id": "org_haqq",
"workspace_id": "ws_default",
"environment": "production | staging"
},
"integrity": {
"prev_hash": "sha256-of-previous-entry",
"entry_hash": "sha256-of-this-entry"
}
}
Required fields (no nullable)
| Field | Type | Purpose |
|---|---|---|
event_id |
ULID or UUIDv7 | Monotonic ordering + uniqueness |
event_type |
enum string | Fast filtering and alerting |
timestamp |
ISO 8601 UTC | Canonical time reference |
actor.user_id |
string | Who acted; "system" for automated events |
actor.role |
enum | Authorization context |
actor.session_id |
string | Links to authentication record |
resource.type |
enum | What was acted upon |
resource.id |
string | Specific resource identifier |
action.name |
enum | What happened |
action.result |
enum | Success / failure / partial |
context.request_id |
string | Links to request log |
Event type taxonomy
Authentication events
user.auth.login.successuser.auth.login.failureuser.auth.logoutuser.auth.token.refreshuser.auth.mfa.successuser.auth.mfa.failure
Matter and document events
matter.createdmatter.status.changedmatter.accesseddocument.createddocument.accesseddocument.transmitted(to external party — high importance)document.deleteddocument.version.created
Skill invocation events
skill.invokedskill.completedskill.failedskill.escalated(skill routed to human review)
Conflict and compliance events
conflict.check.runconflict.check.result.cleanconflict.check.result.concernconflict.check.result.conflictaml.screening.runaml.flag.raised
Data events
data.export.requesteddata.export.delivereddata.deletion.requesteddata.deletion.completed
Admin events
user.createduser.role.changeduser.access.granteduser.access.revokedorg.settings.changed
Tamper-evidence (chained hashes)
For regulatory and malpractice defensibility, the audit log must be tamper-evident:
- Compute
entry_hash = SHA256(event_id + event_type + timestamp + actor + resource + action + prev_hash). - Each entry's
prev_hashis theentry_hashof the immediately preceding entry. - Any insertion, deletion, or modification breaks the hash chain.
- Periodically anchor the chain head to an external timestamp authority (e.g., RFC 3161 timestamp token) for legal evidentiary strength.
Indexing strategy
| Index | Purpose |
|---|---|
(org_id, timestamp) |
Org-scoped time-range queries |
(actor.user_id, timestamp) |
User activity history |
(resource.id, timestamp) |
Resource event history |
(event_type, timestamp) |
Alert and monitoring queries |
(context.trace_id) |
Cross-service trace correlation |
(action.result, event_type, timestamp) |
Failure analysis |
Use a write-optimized append-only store (e.g., ClickHouse, BigQuery, S3+Athena, or a dedicated audit table in PostgreSQL with UNLOGGED disabled and row-level security). Do not use the same database table as application data.
Retention policy
| Event category | Minimum retention | Rationale |
|---|---|---|
| Authentication | 1 year | Security investigation |
| Matter / document access | 7 years | Bar file retention; malpractice |
| Conflict check | 7 years | Bar discipline defense |
| Skill invocations | 2 years | Operational; AI accountability |
| Financial events (billing, invoices) | 7 years | Tax and audit |
| Data deletion events | Permanent | Proof of compliance |
Retention may be extended by firm policy or jurisdiction-specific requirements.
Access control
- The audit log is readable by: system admins, managing partner (org-level), compliance officer.
- Individual users can read their own events only.
- No user — including admins — can delete or update audit log entries.
- Write access: system only (no user-facing write endpoint).
Related skills
- [[eng-langfuse-trace-inspector]]
- [[eng-latency-slo-by-skill]]
- [[eng-cost-per-message-tracker]]
- [[eng-mcp-tool-registry]]