Audit logs record who did what, when, from where. Enterprise buyers ask about them in the first security review.
Audit logs are the immutable record of security-relevant events in your system: who signed in, who changed a permission, who exported data, who invited a user, who deleted a record. They are the primary evidence used in incident investigation, in customer forensics after their own breach, and in the enterprise procurement process ('can you show us the audit log surface?'). Building audit logging as an afterthought produces a scattered, unreliable trail that is worse than none.
Authentication: sign-in success/failure, MFA challenge, password change, session revocation, SSO events. Authorization: role assignment, permission grant/revoke, group membership change. Account lifecycle: user invite, activation, suspension, deletion. Data access at sensitivity: export, download, bulk read of PII, cross-tenant queries. Data modification: create/update/delete of any object customers care about (records, integrations, settings). Administrative actions: config changes, feature flag flips, impersonation start/end, API key creation. Do NOT log routine application actions (page views, low-stakes queries) — that noise makes the log unsearchable and expensive.
Every audit event should carry: event_id (ULID), timestamp (UTC, microsecond precision), actor (user_id + email at time of event + auth method), on_behalf_of (for impersonation and API-key-owned-by-user cases), source_ip, user_agent, session_id, tenant_id, action (dotted namespace: user.invite, integration.create, data.export), target (resource_type + resource_id + human-readable label), before/after (for updates, redacted where needed), outcome (success/failure/denied), reason (denial reason or free-text context), request_id (correlates to app logs). Version the schema; downstream consumers will break if you rename fields casually.
Do not store audit logs in the same primary database that generates them — an attacker who compromises the app can rewrite the trail. Ship to append-only storage: dedicated database with revoked update/delete grants, or object storage with object lock (S3 Object Lock, GCS Bucket Lock), or a purpose-built system (Datadog Audit Trail, AWS CloudTrail Lake, Vanta/Drata audit stores). Consider hash-chaining (each event's hash includes the prior event's hash) for tamper-evidence. Retention: 1 year minimum for SOC 2, 6 years for HIPAA, 7+ years for SOX. Storage cost is trivial; do not skimp.
Enterprise buyers expect self-service access to their own audit trail — filterable, exportable, and available via API. Build a UI (searchable table with actor, action, resource, timestamp filters) and a paginated API (cursor-based, JSON lines format for streaming). Support SIEM export via webhook or Splunk HEC endpoint on request. Retention shown in the UI (e.g., 'showing events from the last 90 days; contact support for older'). Scope strictly to the customer's tenant — cross-tenant leakage here is a headline-grade incident. Do not include internal Lovable/staff actions in the customer-visible view; those belong in your internal log only.
Audit logging must not silently fail. If the log store is unavailable, the safer default for security-relevant actions is to fail closed (block the action) rather than proceed unlogged — at minimum for the highest-sensitivity actions (permission grants, data exports). Use a durable write path: emit to a local buffer that flushes to the log store, with retries and dead-letter alerting. Never let audit writes happen inside the same transaction as the business action in a way that couples them (a slow log store then breaks user workflows) — instead, write locally durably first, then async ship. Test the failure paths.
Investor directory · Fundraising library · Articles A–Z · Company funding database