auth/audit_log_ddl.ts view source
string[] import {AUDIT_LOG_INDEXES} from '@fuzdev/fuz_app/auth/audit_log_ddl.js'; 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).
2 declarations
auth/audit_log_ddl.ts view source
string[] import {AUDIT_LOG_INDEXES} from '@fuzdev/fuz_app/auth/audit_log_ddl.js'; 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';