Audit log
EstimateIQ keeps an append-only audit trail. Nothing changes in the system without a line in it: every mutating API call, every admin clear/load, and every queue/workflow action is recorded.
What gets logged
- API mutations — a middleware wraps every
POST/PUT/PATCH/DELETEunder/api/*and records the call after it runs. The method + path are parsed into a readableactionand the affected entity id (e.g.POST /api/estimates/est_X/submit→ actionestimate.submit, targetest_X). - Admin operations —
admin.clearandadmin.loadare logged explicitly when data is loaded (see Data loading), with the loaded row counts in the summary. - Background actions — queue ingest and workflow steps record their own entries.
Recording is best-effort: it can never break the request it describes. Reads are never logged, and
/api/audit itself is excluded so viewing the trail doesn’t pollute it.
Entry shape
Each row (Drizzle table audit_log):
| Field | Meaning |
|---|---|
ts | ISO timestamp. |
actor | Who — the x-actor request header, or operator / admin / system. |
action | noun.verb, e.g. estimate.submit, carrier.update, followup.complete, admin.load. |
method · path | The HTTP method and request path (for API-driven entries). |
target | The affected entity id (estimate / carrier / …), when present. |
summary | Human-readable line. |
status | HTTP status the call returned. |
source | api · admin · queue · workflow · webhook. |
Reading the trail
GET /api/audit?limit=300Returns entries newest first (default 300). See the API reference.
The Audit log page (Operations → Audit log) renders the same data server-side (zero-flash, newest
first) with source pills and a link from each target straight to the affected estimate.