audit logic
This commit is contained in:
207
water-api/sql/add_audit_logs.sql
Normal file
207
water-api/sql/add_audit_logs.sql
Normal file
@@ -0,0 +1,207 @@
|
||||
-- ============================================================================
|
||||
-- Audit Logs Migration
|
||||
-- Add audit logging table to track user actions and system changes
|
||||
-- ============================================================================
|
||||
|
||||
-- ============================================================================
|
||||
-- ENUM TYPE: audit_action
|
||||
-- ============================================================================
|
||||
CREATE TYPE audit_action AS ENUM (
|
||||
'CREATE',
|
||||
'UPDATE',
|
||||
'DELETE',
|
||||
'LOGIN',
|
||||
'LOGOUT',
|
||||
'READ',
|
||||
'EXPORT',
|
||||
'BULK_UPLOAD',
|
||||
'STATUS_CHANGE',
|
||||
'PERMISSION_CHANGE'
|
||||
);
|
||||
|
||||
-- ============================================================================
|
||||
-- TABLE: audit_logs
|
||||
-- ============================================================================
|
||||
CREATE TABLE audit_logs (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
|
||||
-- User information
|
||||
user_id UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
user_email VARCHAR(255) NOT NULL,
|
||||
user_name VARCHAR(255) NOT NULL,
|
||||
|
||||
-- Action details
|
||||
action audit_action NOT NULL,
|
||||
table_name VARCHAR(100) NOT NULL,
|
||||
record_id UUID,
|
||||
|
||||
-- Change tracking
|
||||
old_values JSONB,
|
||||
new_values JSONB,
|
||||
description TEXT,
|
||||
|
||||
-- Request metadata
|
||||
ip_address INET,
|
||||
user_agent TEXT,
|
||||
|
||||
-- Status
|
||||
success BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
error_message TEXT,
|
||||
|
||||
-- Timestamp
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- ============================================================================
|
||||
-- INDEXES
|
||||
-- ============================================================================
|
||||
CREATE INDEX idx_audit_logs_user_id ON audit_logs(user_id);
|
||||
CREATE INDEX idx_audit_logs_action ON audit_logs(action);
|
||||
CREATE INDEX idx_audit_logs_table_name ON audit_logs(table_name);
|
||||
CREATE INDEX idx_audit_logs_record_id ON audit_logs(record_id);
|
||||
CREATE INDEX idx_audit_logs_created_at ON audit_logs(created_at DESC);
|
||||
CREATE INDEX idx_audit_logs_user_id_created_at ON audit_logs(user_id, created_at DESC);
|
||||
CREATE INDEX idx_audit_logs_table_name_record_id ON audit_logs(table_name, record_id);
|
||||
|
||||
-- Index for JSON queries on old_values and new_values
|
||||
CREATE INDEX idx_audit_logs_old_values ON audit_logs USING GIN (old_values);
|
||||
CREATE INDEX idx_audit_logs_new_values ON audit_logs USING GIN (new_values);
|
||||
|
||||
-- ============================================================================
|
||||
-- COMMENTS
|
||||
-- ============================================================================
|
||||
COMMENT ON TABLE audit_logs IS 'System audit log tracking all user actions and data changes';
|
||||
COMMENT ON COLUMN audit_logs.user_id IS 'Reference to user who performed the action (nullable if user deleted)';
|
||||
COMMENT ON COLUMN audit_logs.user_email IS 'Email snapshot at time of action';
|
||||
COMMENT ON COLUMN audit_logs.user_name IS 'Name snapshot at time of action';
|
||||
COMMENT ON COLUMN audit_logs.action IS 'Type of action performed';
|
||||
COMMENT ON COLUMN audit_logs.table_name IS 'Database table affected by the action';
|
||||
COMMENT ON COLUMN audit_logs.record_id IS 'ID of the specific record affected';
|
||||
COMMENT ON COLUMN audit_logs.old_values IS 'JSON snapshot of values before change';
|
||||
COMMENT ON COLUMN audit_logs.new_values IS 'JSON snapshot of values after change';
|
||||
COMMENT ON COLUMN audit_logs.description IS 'Human-readable description of the action';
|
||||
COMMENT ON COLUMN audit_logs.ip_address IS 'IP address of the user';
|
||||
COMMENT ON COLUMN audit_logs.user_agent IS 'Browser/client user agent string';
|
||||
COMMENT ON COLUMN audit_logs.success IS 'Whether the action completed successfully';
|
||||
COMMENT ON COLUMN audit_logs.error_message IS 'Error message if action failed';
|
||||
|
||||
-- ============================================================================
|
||||
-- HELPER FUNCTION: Get current user info from request context
|
||||
-- ============================================================================
|
||||
CREATE OR REPLACE FUNCTION get_current_user_info()
|
||||
RETURNS TABLE (
|
||||
user_id UUID,
|
||||
user_email VARCHAR(255),
|
||||
user_name VARCHAR(255)
|
||||
) AS $$
|
||||
BEGIN
|
||||
-- This will be called from application code with current_setting
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
NULLIF(current_setting('app.current_user_id', true), '')::UUID,
|
||||
NULLIF(current_setting('app.current_user_email', true), ''),
|
||||
NULLIF(current_setting('app.current_user_name', true), '');
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- ============================================================================
|
||||
-- HELPER FUNCTION: Log audit entry
|
||||
-- ============================================================================
|
||||
CREATE OR REPLACE FUNCTION log_audit(
|
||||
p_user_id UUID,
|
||||
p_user_email VARCHAR(255),
|
||||
p_user_name VARCHAR(255),
|
||||
p_action audit_action,
|
||||
p_table_name VARCHAR(100),
|
||||
p_record_id UUID DEFAULT NULL,
|
||||
p_old_values JSONB DEFAULT NULL,
|
||||
p_new_values JSONB DEFAULT NULL,
|
||||
p_description TEXT DEFAULT NULL,
|
||||
p_ip_address INET DEFAULT NULL,
|
||||
p_user_agent TEXT DEFAULT NULL,
|
||||
p_success BOOLEAN DEFAULT TRUE,
|
||||
p_error_message TEXT DEFAULT NULL
|
||||
)
|
||||
RETURNS UUID AS $$
|
||||
DECLARE
|
||||
v_log_id UUID;
|
||||
BEGIN
|
||||
INSERT INTO audit_logs (
|
||||
user_id,
|
||||
user_email,
|
||||
user_name,
|
||||
action,
|
||||
table_name,
|
||||
record_id,
|
||||
old_values,
|
||||
new_values,
|
||||
description,
|
||||
ip_address,
|
||||
user_agent,
|
||||
success,
|
||||
error_message
|
||||
) VALUES (
|
||||
p_user_id,
|
||||
p_user_email,
|
||||
p_user_name,
|
||||
p_action,
|
||||
p_table_name,
|
||||
p_record_id,
|
||||
p_old_values,
|
||||
p_new_values,
|
||||
p_description,
|
||||
p_ip_address,
|
||||
p_user_agent,
|
||||
p_success,
|
||||
p_error_message
|
||||
) RETURNING id INTO v_log_id;
|
||||
|
||||
RETURN v_log_id;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- ============================================================================
|
||||
-- VIEW: audit_logs_summary
|
||||
-- ============================================================================
|
||||
CREATE OR REPLACE VIEW audit_logs_summary AS
|
||||
SELECT
|
||||
al.id,
|
||||
al.user_email,
|
||||
al.user_name,
|
||||
al.action,
|
||||
al.table_name,
|
||||
al.record_id,
|
||||
al.description,
|
||||
al.success,
|
||||
al.created_at,
|
||||
al.ip_address,
|
||||
-- User reference (may be null if user deleted)
|
||||
u.id AS current_user_id,
|
||||
u.is_active AS user_is_active
|
||||
FROM audit_logs al
|
||||
LEFT JOIN users u ON al.user_id = u.id
|
||||
ORDER BY al.created_at DESC;
|
||||
|
||||
COMMENT ON VIEW audit_logs_summary IS 'Audit logs with user status information';
|
||||
|
||||
-- ============================================================================
|
||||
-- VIEW: audit_statistics
|
||||
-- ============================================================================
|
||||
CREATE OR REPLACE VIEW audit_statistics AS
|
||||
SELECT
|
||||
DATE(created_at) AS date,
|
||||
action,
|
||||
table_name,
|
||||
COUNT(*) AS action_count,
|
||||
COUNT(DISTINCT user_id) AS unique_users,
|
||||
SUM(CASE WHEN success THEN 1 ELSE 0 END) AS successful_actions,
|
||||
SUM(CASE WHEN NOT success THEN 1 ELSE 0 END) AS failed_actions
|
||||
FROM audit_logs
|
||||
GROUP BY DATE(created_at), action, table_name
|
||||
ORDER BY date DESC, action_count DESC;
|
||||
|
||||
COMMENT ON VIEW audit_statistics IS 'Daily statistics of audit log actions';
|
||||
|
||||
-- ============================================================================
|
||||
-- END OF MIGRATION
|
||||
-- ============================================================================
|
||||
Reference in New Issue
Block a user