auth/audit_log_ddl.ts

Audit log DDL — CREATE TABLE + index statements for the audit_log table.

Consumed by auth/migrations.ts. Separated from auth/audit_log_schema.ts so the schema module stays Zod-only (paired with auth/auth_ddl.ts and auth/role_grant_offer_ddl.ts).

Multi-actor invariants the envelope columns assume:

  • actor_id + account_id, when both populated, refer to the same account (derivable via actor.account_id). Denormalized for indexed audit queries; do not let them disagree.
  • target_actor_id + target_account_id, same rule when both populated.
  • target_account_id is the SSE/WS socket-close key — sessions stay account-grain after multi-actor lands, so this column carries the routing identity even on actor-bound events.
  • target_actor_id is populated iff the event subject is actor-bound (see AuditLogEvent.target_actor_id doc-comment for the rule).

No FK on the four identity columns. They are plain UUID, not REFERENCES … ON DELETE SET NULL. An audit log is an append-only historical record, not a live relational entity; SET NULL erased the very attribution the log exists to preserve. With soft-delete as the default (account.deleted_at) the rows stay and the ids JOIN-resolve; on a hard purge the raw id survives instead of nulling, and the purge audit event snapshots the identity into metadata (delete = soft, purge = hard).

view source

Declarations
#

2 declarations

AUDIT_LOG_INDEXES
#

AUDIT_LOG_SCHEMA
#

auth/audit_log_ddl.ts view source

"\nCREATE TABLE IF NOT EXISTS audit_log (\n id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n seq BIGSERIAL NOT NULL,\n event_type TEXT NOT NULL,\n outcome TEXT NOT NULL DEFAULT 'success',\n actor_id UUID,\n account_id UUID,\n target_account_id UUID,\n target_actor_id UUID,\n ip TEXT,\n created_at TIMESTAMP... import {AUDIT_LOG_SCHEMA} from '@fuzdev/fuz_app/auth/audit_log_ddl.js';

Imported by
#