-- t-paliad-214 Slice 1 — create paliad.system_audit_log as the 6th source
-- in the AuditService.ListEntries union. Captures org-wide / scope-spanning
-- actions that don't naturally belong on any single project_events row.
--
-- Design: docs/design-paliad-data-export-2026-05-19.md §4.
--
-- Initial use case is data-export auditing (every export run writes one row,
-- before the artifact is generated, then is patched with row_counts +
-- file_size_bytes on completion). The table is intentionally generic
-- (`event_type` + `metadata jsonb`) so future org-wide actions can land here
-- without a new table per concept.
--
-- Idempotent: CREATE TABLE IF NOT EXISTS + CREATE INDEX IF NOT EXISTS.
-- audit_reason set_config required by the mig 079 trigger pattern when
-- migrations touch the database — universal convention even for pure-DDL
-- migrations.

SELECT set_config(
    'paliad.audit_reason',
    'mig 102: add paliad.system_audit_log for org-wide / scope-spanning audit events (t-paliad-214 Slice 1 — data-export audit chain)',
    true);

CREATE TABLE IF NOT EXISTS paliad.system_audit_log (
    id           uuid PRIMARY KEY DEFAULT gen_random_uuid(),
    event_type   text NOT NULL,
    actor_id     uuid REFERENCES paliad.users(id) ON DELETE SET NULL,
    -- actor_email is captured at write time so the audit row survives a
    -- subsequent user-deletion (FK above sets NULL, but the historical
    -- identity stays readable).
    actor_email  text NOT NULL,
    scope        text NOT NULL CHECK (scope IN ('org', 'project', 'personal')),
    -- scope_root is the project_id for scope='project'; NULL otherwise.
    -- Not a hard FK because we want the audit row to outlive a project
    -- deletion. Resolution happens at read time.
    scope_root   uuid,
    metadata     jsonb NOT NULL DEFAULT '{}'::jsonb,
    created_at   timestamptz NOT NULL DEFAULT now(),
    updated_at   timestamptz NOT NULL DEFAULT now()
);

-- Indexes mirror the read patterns:
--   - actor lookup ("show me what I've exported"): actor_id + created_at desc
--   - scope rollup ("how much org-wide activity in the last 30 days"): event_type + created_at desc
CREATE INDEX IF NOT EXISTS system_audit_log_actor_id_created_at_idx
    ON paliad.system_audit_log (actor_id, created_at DESC);

CREATE INDEX IF NOT EXISTS system_audit_log_event_type_created_at_idx
    ON paliad.system_audit_log (event_type, created_at DESC);

-- RLS: every authenticated user can SELECT their own rows (actor_id = auth.uid());
-- global_admins see everything. INSERT / UPDATE happen via the Go service path
-- under the migration-runner role (no end-user write surface) so no INSERT
-- policy is needed for end users.
ALTER TABLE paliad.system_audit_log ENABLE ROW LEVEL SECURITY;

DROP POLICY IF EXISTS system_audit_log_select_self ON paliad.system_audit_log;
CREATE POLICY system_audit_log_select_self ON paliad.system_audit_log
    FOR SELECT
    USING (actor_id = auth.uid());

DROP POLICY IF EXISTS system_audit_log_select_admin ON paliad.system_audit_log;
CREATE POLICY system_audit_log_select_admin ON paliad.system_audit_log
    FOR SELECT
    USING (
        EXISTS (
            SELECT 1 FROM paliad.users u
             WHERE u.id = auth.uid()
               AND u.global_role = 'global_admin'
        )
    );

COMMENT ON TABLE paliad.system_audit_log IS
    'Org-wide / scope-spanning audit events. 6th source of AuditService union. Generic event_type + metadata jsonb. Initial users: data-export audit chain (t-paliad-214). Audit rows persist forever; artifact retention is separate.';

COMMENT ON COLUMN paliad.system_audit_log.actor_email IS
    'Captured at write time so the audit row survives user deletion (actor_id FK uses ON DELETE SET NULL).';

COMMENT ON COLUMN paliad.system_audit_log.scope_root IS
    'project_id for scope=project; NULL otherwise. Not a hard FK so audit survives project deletion.';
