Skip to main content

Audit Trail

SureCentric implements a two-layer audit trail designed for regulated health science environments. Every schema change, data operation, configuration update, and AI agent action is recorded in an indelible, tamper-evident audit trail.

FDA 21 CFR Part 11EU Annex 11HIPAA

Design Principles

The audit trail is modeled after the production audit trail in the SureClinical network-service backend (com.sureclinical.network.audit.trail), adapted for MikroORM + Dolt/MySQL:

SC PatternSureCentric Equivalent
AuditTrailEntry (permanent)audit_trail table — append-only, never deleted
AuditTrailLog (5-day TTL)audit_trail_log table — operational, supports rollback
AuditTrailLogCleanUpSchedulerNode.js cron job in CARD API, 24h interval
AuditedEntityChangedEvent (Spring)MikroORM @Subscriber() EventSubscriber
AuditEventType enumSurecentricEventType TypeScript enum

Two-Layer Architecture

Layer 1 — audit_trail (Permanent Record)

The permanent regulatory record. Append-only — no UPDATE or DELETE is ever issued.

ColumnTypeDescription
event_idVARCHAR(36)UUID v4 — unique per event
occurred_atDATETIME(3)UTC, millisecond precision
event_typeVARCHAR(64)See Event Types below
resource_typeVARCHAR(64)schema, card_profile, project, agent, …
resource_idVARCHAR(128)Entity primary key affected
actor_typeENUMuser, system, or agent
actor_idVARCHAR(128)User ID, system, or agent_run_id
actor_emailVARCHAR(320)Email or system@surecentric
agent_run_idVARCHAR(36)UUID of AI Agent execution (null for users)
agent_nameVARCHAR(128)SureAgent, DataAgent, etc. (null for users)
before_stateJSONEntity state before the change
after_stateJSONEntity state after the change
dolt_commit_hashVARCHAR(64)Links to dolt_log — Layer 1 cross-reference
outcomeENUMsuccess, failure, pending
correlation_idVARCHAR(36)Groups related events across a workflow
parent_event_idVARCHAR(36)Parent event in a chain

Dolt's content-addressed storage makes any post-write modification to audit_trail cryptographically detectable in dolt_log.

Layer 2 — audit_trail_log (5-day TTL)

A transient operational log used during active schema deployments to support rollback. Entries expire after 5 days (matching AuditTrailLog.AUDIT_TRAIL_LOG_ENTRY_TTL = 5 in SC). This is not a regulatory record — it is a deployment safety net.

Key additional column: rollback_target VARCHAR(64) — the Dolt commit hash to revert to if a deployment must be rolled back.

Actor Types

enum ActorType {
USER = 'user', // Authenticated human user (JWT session)
SYSTEM = 'system', // Scheduled jobs, migrations, cleanup
AGENT = 'agent', // AI Agent with UUID execution envelope
}

Event Types

CategoryEvent Types
Generic CRUDADD, MOD, DEL
SchemaSCHEMA_CREATE, SCHEMA_UPDATE, SCHEMA_COMPILE, SCHEMA_DEPLOY, SCHEMA_PROMOTE, SCHEMA_ROLLBACK, SCHEMA_DELETE
CARDCARD_PROFILE_CREATE, CARD_PROFILE_UPDATE, CARD_PROFILE_PROVISION, CARD_PROFILE_DELETE
ProjectPROJECT_CREATE, PROJECT_UPDATE, PROJECT_DELETE
AnalyticsSUPERSET_DASHBOARD_EMBED, SUPERSET_GUEST_TOKEN_ISSUE, DUCKDB_QUERY, DUCKDB_DATASET_CREATE
AI AgentsAGENT_RUN_START, AGENT_TOOL_CALL, AGENT_SANDBOX_EXEC, AGENT_ACTION, AGENT_RUN_FINISH
SessionSESSION_LOGIN, SESSION_LOGOUT, SESSION_TOKEN_REFRESH
ConfigCONFIG_UPDATE, API_KEY_CREATE, API_KEY_REVOKE

AI Agent Attribution

AI Agents are identified using the same pattern SC applies to Nuxeo workflow processes: each agent execution gets a UUID and emits a START / FINISH event pair that acts as a traceable envelope around all actions the agent takes.

AGENT_RUN_START   actor_type=agent  agent_run_id=uuid-abc  spawned_by=jane@clinic.org
├── AGENT_TOOL_CALL tool=dolt_commit args={message: "schema: deploy edc.v1.1"}
├── AGENT_ACTION event_type=SCHEMA_DEPLOY resource_id=edc-v1.1
├── AGENT_TOOL_CALL tool=superset_provision args={profileId: "prof-001"}
AGENT_RUN_FINISH outcome=success duration_ms=4231 tokens_used=1840

Agent Dolt commits are attributed to the agent, not the spawning user, making them distinguishable in dolt_log:

SET @@dolt_head_committer_email = 'agent:SureAgent@surecentric';
SET @@dolt_head_committer_name = 'SureAgent (run: uuid-abc)';
CALL dolt_commit('schema: deploy edc.v1.1 [agent:SureAgent spawned-by:jane@clinic.org]');

Nested agents (an orchestrator spawning sub-agents) are linked via parent_run_id.

Schema Deployment Audit Flow

POST /api/sb/card-profiles/:id/provision

├─ 1. Resolve actor context (user JWT | agent_run_id | system)
├─ 2. Layer 2: log CARD_PROFILE_PROVISION → audit_trail_log (pending)
├─ 3. Dolt: checkout new branch schema/deploy-<timestamp>
├─ 4. Compile JSON-LD → DDL → apply to DuckDB
├─ 5. Dolt: SET committer identity → CALL dolt_commit() → capture hash
├─ 6. Layer 2: write SCHEMA_DEPLOY to audit_trail_log (rollback_target = prev hash)
├─ 7. Layer 1: write permanent CARD_PROFILE_PROVISION to audit_trail (with dolt_commit_hash)
└─ 8. Layer 2: mark outcome = success

On failure:
CALL dolt_reset('--hard') ← schema rolled back
audit_trail outcome = 'failure' ← permanent failure record

Regulatory Compliance

StandardClauseImplementation
FDA 21 CFR Part 11§11.10(e)audit_trail — every change recorded with actor, timestamp, before/after state
FDA 21 CFR Part 11§11.10(k)dolt_commit_hash links electronic record to Dolt's tamper-evident commit graph
FDA 21 CFR Part 11§11.50actor_id, actor_email, session_id present on every entry
EU Annex 11§9Append-only audit_trail; Dolt hash-chain provides integrity evidence
EU Annex 11§10Audit trail cannot be disabled — AuditSubscriber is always active
EU Annex 11§12.4dolt push backup to S3 provides disaster recovery

REST API

EndpointDescription
GET /api/audit-trailPaginated audit entries (filter by actor, event_type, resource, date)
GET /api/audit-trail/schema-historyDolt dolt_log system table proxy
GET /api/audit-trail/diff/:from/:todolt_diff() between two commits or branches
GET /api/audit-trail/at/:commitTime-travel: resource state at a Dolt commit
GET /api/audit-trail/agentsList all agent_registry entries
GET /api/audit-trail/agents/:runIdFull agent execution log for a run
GET /api/audit-trail/exportSigned export for regulatory submission