Capture who did what, to whom, and when in an append-only ledger built for SOC2 and ISO27001 review, where audit completeness is never sacrificed for request latency.
Compliance review starts with one demand: prove who did what. The Audit domain is PMAP compliance-grade security event ledger. It keeps two complementary trails, a synchronous security log for high-consequence actions and a high-throughput activity log for every entity mutation, so an auditor can reconstruct access history without trusting application memory.
The security audit writes typed events directly to PostgreSQL on the request path, so login, access grant, revoke, role change, and destructive delete land in strict order with no goroutine reordering. The activity audit batches every finding, asset, scan, and import mutation through a background flusher, with a synchronous fallback that fires when the buffer is full so no row is ever silently dropped.

Auditing must not add a second failure mode to the operations it records. Errors from the audit write are logged, never propagated, so a ledger write failure cannot break the action it was meant to evidence.
At a glance
- Two trails: Security audit (access_audit_events) plus activity audit (activity_logs)
- Security write: Synchronous INSERT on the request path; strict ordering, no reorder
- Activity write: Buffered channel drained by a background flusher; sync fallback when full
- Typed events: Twelve named security kinds plus a DB CHECK constraint catching typos
- Event bus: In-process dispatcher fans 34 event types to audit, notify, runbook, and SSE
- Completeness: Audit write errors logged, never propagated; graceful drain on shutdown
- Read access: Platform-admin only; names JOIN-resolved so the UI never shows a raw UUID
How it works
Two append-only trails, one synchronous for high-consequence security actions and one batched for every entity mutation, kept complete over fast, name-resolved for human review, and readable only by a platform admin, so an auditor can reconstruct who did what without trusting application memory.
A security event is captured where it happens. The handler calls LogFromRequest, which enriches the event with actor identity, client IP, and user agent pulled from the request context, then writes it synchronously. The caller writes no boilerplate and waits on no second failure mode, because a write error is logged and never returned.
A ledger is only evidence if nothing is lost and an auditor can read it. The activity queue flushes in batches but falls back to a direct write under pressure, drains fully on shutdown, and the security log is queried with names resolved server-side so a reviewer never decodes a raw UUID, all behind a platform-admin gate.
Key capabilities
- Completeness over latency. Both trails treat audit completeness as the higher priority. The synchronous fallback fires when the channel buffer fills, so an entity mutation is never lost just because the queue is busy, and the recorded operation is never blocked waiting on the audit write.
- Graceful drain on shutdown. The queue Stop call is deferred until after the HTTP server closes and every in-flight request finishes, draining all pending events before the process exits. No activity row is lost on a SIGTERM, and Stop is safe to call more than once.
- Name resolution for review. The List query resolves actor name, actor email, target user, target role, target scope, and target entity name through LEFT JOINs and correlated subqueries. For deleted entities the payload supplies the captured name, so the audit screen never falls back to a bare identifier.
- Filtered, capped queries. Auditors filter the security log by actor, target, event type, and a since and until time range. The query returns 100 rows by default and is capped at 500, so a review is paginated and bounded rather than pulling an unbounded result set.
Use cases
- Pass a SOC2 access review. A compliance auditor filters the security log to access_granted and access_revoked over the audit window, reads each grant by actor name, target principal, role, and scope, and exports the bounded result as evidence that access changes were authorized and recorded in order.
- Investigate a suspicious login pattern. A SOC analyst queries login_failed by a single actor across a time range, sees each attempt with its client IP and user agent enriched from the request, and correlates the failures against the access_granted events that followed to scope a possible account takeover.
- Reconstruct a destructive delete. A reviewer pulls the finding_deleted and project_deleted events for the quarter and reads the entity name straight from the payload, because the name was captured at emit time, so the trail names the deleted record even though the underlying row is long gone.
Two append-only trails, complete over fast, readable as evidence.


