-- ============================================================ -- Audit Trigger Migration — Run on production after 001 -- Adds per-field audit triggers to configuration_items -- ============================================================ BEGIN; -- Fine-grained audit: capture individual field changes CREATE OR REPLACE FUNCTION audit_ci_fields_func() RETURNS TRIGGER AS $$ DECLARE col TEXT; old_val TEXT; new_val TEXT; BEGIN IF TG_OP = 'UPDATE' THEN FOR col IN SELECT unnest(ARRAY[ 'name', 'description', 'status', 'location_id', 'serial_number', 'asset_tag', 'purchase_date', 'warranty_expiry', 'tags' ]) LOOP old_val := row_to_json(OLD) ->> col; new_val := row_to_json(NEW) ->> col; IF old_val IS DISTINCT FROM new_val THEN INSERT INTO changelog (ci_id, action, field_name, old_value, new_value, version, snapshot) VALUES (NEW.id, 'update', col, old_val, NEW.version, NEW.version, to_jsonb(NEW)); END IF; END LOOP; -- JSONB attributes changes IF OLD.attributes IS DISTINCT FROM NEW.attributes THEN INSERT INTO changelog (ci_id, action, field_name, old_value, new_value, version, snapshot) VALUES (NEW.id, 'update', 'attributes', OLD.attributes::text, NEW.attributes::text, NEW.version, to_jsonb(NEW)); END IF; NEW.updated_at = now(); NEW.version = OLD.version + 1; RETURN NEW; END IF; RETURN NULL; END; $$ LANGUAGE plpgsql; DROP TRIGGER IF EXISTS trg_ci_audit ON configuration_items; CREATE TRIGGER trg_ci_field_audit AFTER UPDATE ON configuration_items FOR EACH ROW EXECUTE FUNCTION audit_ci_fields_func(); -- Relationship audit CREATE OR REPLACE FUNCTION audit_relationship_func() RETURNS TRIGGER AS $$ BEGIN IF TG_OP = 'INSERT' THEN INSERT INTO changelog (ci_id, action, field_name, new_value, version, snapshot) VALUES (NEW.source_ci_id, 'relationship_add', NEW.relationship::text, NEW.target_ci_id::text, 0, to_jsonb(NEW)); RETURN NEW; ELSIF TG_OP = 'DELETE' THEN INSERT INTO changelog (ci_id, action, field_name, old_value, version, snapshot) VALUES (OLD.source_ci_id, 'relationship_remove', OLD.relationship::text, OLD.target_ci_id::text, 0, to_jsonb(OLD)); RETURN OLD; END IF; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_relationship_audit AFTER INSERT OR DELETE ON ci_relationships FOR EACH ROW EXECUTE FUNCTION audit_relationship_func(); COMMIT;