Files
openccb/services/cms-service/migrations/20260111000002_advanced_auditing.sql
T
Nurfog b1eb23926e feat: database-first refactor, unified architecture and visual developer manual
Summary of changes:
- Consolidated Studio+CMS and Experience+LMS into unified services.
- Moved core business logic (enrollment, grading, auth) to PostgreSQL functions.
- Implemented advanced auditing via DB triggers and session context.
- Added gamification (XP/Levels/Leaderboards) and logic encapsulation.
- Updated installation/diagnostic scripts for the new architecture.
- Created a comprehensive Visual Developer Manual in README.md with hardware scaling.
2026-01-11 02:34:23 -03:00

131 lines
3.7 KiB
PL/PgSQL

-- Migration: Advanced Auditing and Automatic Triggers
-- Upgrade audit_logs table and implement automated change tracking
-- 1. Upgrade audit_logs table
ALTER TABLE audit_logs
ADD COLUMN IF NOT EXISTS event_type VARCHAR(50) DEFAULT 'USER_EVENT',
ADD COLUMN IF NOT EXISTS old_data JSONB,
ADD COLUMN IF NOT EXISTS new_data JSONB,
ADD COLUMN IF NOT EXISTS ip_address INET,
ADD COLUMN IF NOT EXISTS public_ip INET,
ADD COLUMN IF NOT EXISTS user_agent TEXT,
ADD COLUMN IF NOT EXISTS metadata JSONB DEFAULT '{}';
-- 2. Create Audit Trigger Function
CREATE OR REPLACE FUNCTION fn_trigger_audit_log()
RETURNS TRIGGER AS $$
DECLARE
v_user_id UUID;
v_org_id UUID;
v_ip INET;
v_user_agent TEXT;
v_event_type VARCHAR(50);
v_old_data JSONB := NULL;
v_new_data JSONB := NULL;
v_action VARCHAR(50);
BEGIN
-- Try to get context from session variables
BEGIN
v_user_id := current_setting('app.current_user_id', true)::UUID;
EXCEPTION WHEN OTHERS THEN
v_user_id := NULL;
END;
BEGIN
v_org_id := current_setting('app.current_org_id', true)::UUID;
EXCEPTION WHEN OTHERS THEN
v_org_id := NULL;
END;
BEGIN
v_ip := current_setting('app.client_ip', true)::INET;
EXCEPTION WHEN OTHERS THEN
v_ip := NULL;
END;
BEGIN
v_user_agent := current_setting('app.user_agent', true);
EXCEPTION WHEN OTHERS THEN
v_user_agent := NULL;
END;
BEGIN
v_event_type := current_setting('app.event_type', true);
EXCEPTION WHEN OTHERS THEN
v_event_type := 'USER_EVENT';
END;
-- Handle different operations
IF (TG_OP = 'DELETE') THEN
v_old_data := to_jsonb(OLD);
v_action := 'DELETE';
ELSIF (TG_OP = 'UPDATE') THEN
v_old_data := to_jsonb(OLD);
v_new_data := to_jsonb(NEW);
v_action := 'UPDATE';
ELSIF (TG_OP = 'INSERT') THEN
v_new_data := to_jsonb(NEW);
v_action := 'INSERT';
END IF;
-- Insert into audit_logs
INSERT INTO audit_logs (
organization_id,
user_id,
action,
entity_type,
entity_id,
event_type,
old_data,
new_data,
ip_address,
user_agent
)
VALUES (
COALESCE(v_org_id, (CASE WHEN TG_OP = 'DELETE' THEN OLD.organization_id ELSE NEW.organization_id END)),
v_user_id,
v_action,
TG_TABLE_NAME,
CASE WHEN TG_OP = 'DELETE' THEN OLD.id ELSE NEW.id END,
COALESCE(v_event_type, 'USER_EVENT'),
v_old_data,
v_new_data,
v_ip,
v_user_agent
);
IF (TG_OP = 'DELETE') THEN
RETURN OLD;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 3. Attach triggers to core tables
DO $$
BEGIN
-- Courses
IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'courses') THEN
DROP TRIGGER IF EXISTS trg_audit_courses ON courses;
CREATE TRIGGER trg_audit_courses
AFTER INSERT OR UPDATE OR DELETE ON courses
FOR EACH ROW EXECUTE FUNCTION fn_trigger_audit_log();
END IF;
-- Lessons
IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'lessons') THEN
DROP TRIGGER IF EXISTS trg_audit_lessons ON lessons;
CREATE TRIGGER trg_audit_lessons
AFTER INSERT OR UPDATE OR DELETE ON lessons
FOR EACH ROW EXECUTE FUNCTION fn_trigger_audit_log();
END IF;
-- Users
IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'users') THEN
DROP TRIGGER IF EXISTS trg_audit_users ON users;
CREATE TRIGGER trg_audit_users
AFTER INSERT OR UPDATE OR DELETE ON users
FOR EACH ROW EXECUTE FUNCTION fn_trigger_audit_log();
END IF;
END $$;