FeaturesCalmony Sanctions MonitorUpdated March 12, 2026
Audit Logging
Audit Logging
The platform maintains an immutable audit log of all significant operations, including state-changing actions and every read of sensitive PII fields. The audit log supports SOC 2 Type II compliance (CC6.1, CC6.3) and GDPR Article 20 obligations.
Audit Actions Reference
PII Read Access (SOC 2 CC6.1 / CC6.3)
Added in v0.1.128.
| Action | Description |
|---|---|
person.accessed | An individual person record was read, exposing dateOfBirth, nationality, and registrationNumber |
export.accessed | A bulk export of screening data, people records, or the audit trail was downloaded |
person.accessed — Metadata Fields
{
"fullName": "Jane Smith",
"fieldsAccessed": ["dateOfBirth", "nationality", "registrationNumber"],
"matchCount": 3,
"via": "rest_api_v1" // present only for external REST API v1 calls
}
export.accessed — Metadata Fields
For people exports (/api/export/people):
{
"format": "csv",
"recordCount": 42,
"exportType": "people_list",
"fieldsExported": ["fullName", "dateOfBirth", "nationality", "registrationNumber", "status"]
}
For screening history exports (/api/export/screening-history):
{
"format": "csv",
"peopleCount": 42,
"matchCount": 18,
"reviewCount": 12,
"exportType": "screening_history",
"fieldsExported": ["personName", "sanctionedEntityName", "confidenceScore", "matchAlgorithm", "reviewDecisions"]
}
For audit trail exports (/api/export/audit-trail):
{
"format": "csv",
"recordCount": 500,
"exportType": "audit_trail"
}
Dual-Log Pattern for Exports
All export endpoints write two audit entries per request:
export.accessed— records the SOC 2 access event (CC6.1/CC6.3)gdpr.data_exported— records the GDPR Article 20 portability event
Both entries are written in sequence before the response is returned. If either write fails, the failure is swallowed silently — audit errors never interrupt or fail the main data response.
Endpoints That Emit PII Read Audit Entries
| Endpoint | Audit Action | Notes |
|---|---|---|
GET /api/people/[id] | person.accessed | Internal Next.js app |
GET /api/v1/people/[id] | person.accessed | External REST API v1; includes via: "rest_api_v1" |
GET /api/export/people | export.accessed + gdpr.data_exported | Bulk export |
GET /api/export/screening-history | export.accessed + gdpr.data_exported | Bulk export |
GET /api/export/audit-trail | export.accessed + gdpr.data_exported | Bulk export |
Compliance Coverage
| Requirement | Controls Met | Mechanism |
|---|---|---|
| SOC 2 Type II | CC6.1, CC6.3 | person.accessed and export.accessed audit entries |
| GDPR Article 20 | Data portability logging | gdpr.data_exported audit entries (unchanged) |
Implementation Notes
- All audit writes use
writeAuditLogWithRequest, which automatically extractsipAddressanduserAgentfrom the incoming request - Audit log entries are immutable — there is no update or delete path
- A failed audit write will not cause the endpoint to return an error; the main response is always returned