38980-vm/app-9w9pd00g5j41/supabase/migrations/00044_create_admin_advanced_features.sql
2026-03-04 18:25:09 +00:00

229 lines
6.6 KiB
PL/PgSQL

-- Admin Logs Table for System Activity Tracking
CREATE TABLE IF NOT EXISTS admin_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
admin_id UUID REFERENCES auth.users(id) ON DELETE SET NULL,
action TEXT NOT NULL,
entity_type TEXT NOT NULL,
entity_id TEXT,
details JSONB DEFAULT '{}'::jsonb,
ip_address TEXT,
user_agent TEXT,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX idx_admin_logs_admin_id ON admin_logs(admin_id);
CREATE INDEX idx_admin_logs_created_at ON admin_logs(created_at DESC);
CREATE INDEX idx_admin_logs_action ON admin_logs(action);
CREATE INDEX idx_admin_logs_entity_type ON admin_logs(entity_type);
-- Admin Analytics Table for Metrics Storage
CREATE TABLE IF NOT EXISTS admin_analytics (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
metric_name TEXT NOT NULL,
metric_value NUMERIC NOT NULL,
metric_type TEXT NOT NULL, -- 'count', 'revenue', 'percentage', etc.
period TEXT NOT NULL, -- 'daily', 'weekly', 'monthly'
period_start TIMESTAMPTZ NOT NULL,
period_end TIMESTAMPTZ NOT NULL,
metadata JSONB DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX idx_admin_analytics_metric_name ON admin_analytics(metric_name);
CREATE INDEX idx_admin_analytics_period ON admin_analytics(period, period_start DESC);
-- Admin Images Table for Image Management
CREATE TABLE IF NOT EXISTS admin_images (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
uploaded_by UUID REFERENCES auth.users(id) ON DELETE SET NULL,
title TEXT NOT NULL,
description TEXT,
file_path TEXT NOT NULL,
file_size INTEGER,
mime_type TEXT,
width INTEGER,
height INTEGER,
generation_method TEXT, -- 'upload', 'ai_generated'
generation_prompt TEXT,
tags TEXT[] DEFAULT ARRAY[]::TEXT[],
metadata JSONB DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ DEFAULT now(),
updated_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX idx_admin_images_uploaded_by ON admin_images(uploaded_by);
CREATE INDEX idx_admin_images_created_at ON admin_images(created_at DESC);
CREATE INDEX idx_admin_images_tags ON admin_images USING GIN(tags);
CREATE INDEX idx_admin_images_generation_method ON admin_images(generation_method);
-- Admin Search History Table
CREATE TABLE IF NOT EXISTS admin_search_history (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
admin_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
search_type TEXT NOT NULL, -- 'ai_search', 'smart_search'
query TEXT NOT NULL,
results_count INTEGER DEFAULT 0,
response_time_ms INTEGER,
metadata JSONB DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX idx_admin_search_history_admin_id ON admin_search_history(admin_id);
CREATE INDEX idx_admin_search_history_created_at ON admin_search_history(created_at DESC);
CREATE INDEX idx_admin_search_history_search_type ON admin_search_history(search_type);
-- RLS Policies (Admin Only Access)
ALTER TABLE admin_logs ENABLE ROW LEVEL SECURITY;
ALTER TABLE admin_analytics ENABLE ROW LEVEL SECURITY;
ALTER TABLE admin_images ENABLE ROW LEVEL SECURITY;
ALTER TABLE admin_search_history ENABLE ROW LEVEL SECURITY;
-- Admin Logs Policies
CREATE POLICY "Admins can view all logs"
ON admin_logs FOR SELECT
TO authenticated
USING (
EXISTS (
SELECT 1 FROM profiles
WHERE profiles.id = auth.uid()
AND profiles.role = 'admin'
)
);
CREATE POLICY "Admins can insert logs"
ON admin_logs FOR INSERT
TO authenticated
WITH CHECK (
EXISTS (
SELECT 1 FROM profiles
WHERE profiles.id = auth.uid()
AND profiles.role = 'admin'
)
);
-- Admin Analytics Policies
CREATE POLICY "Admins can view analytics"
ON admin_analytics FOR SELECT
TO authenticated
USING (
EXISTS (
SELECT 1 FROM profiles
WHERE profiles.id = auth.uid()
AND profiles.role = 'admin'
)
);
CREATE POLICY "Admins can manage analytics"
ON admin_analytics FOR ALL
TO authenticated
USING (
EXISTS (
SELECT 1 FROM profiles
WHERE profiles.id = auth.uid()
AND profiles.role = 'admin'
)
);
-- Admin Images Policies
CREATE POLICY "Admins can view all images"
ON admin_images FOR SELECT
TO authenticated
USING (
EXISTS (
SELECT 1 FROM profiles
WHERE profiles.id = auth.uid()
AND profiles.role = 'admin'
)
);
CREATE POLICY "Admins can manage images"
ON admin_images FOR ALL
TO authenticated
USING (
EXISTS (
SELECT 1 FROM profiles
WHERE profiles.id = auth.uid()
AND profiles.role = 'admin'
)
);
-- Admin Search History Policies
CREATE POLICY "Admins can view their search history"
ON admin_search_history FOR SELECT
TO authenticated
USING (
admin_id = auth.uid() AND
EXISTS (
SELECT 1 FROM profiles
WHERE profiles.id = auth.uid()
AND profiles.role = 'admin'
)
);
CREATE POLICY "Admins can insert search history"
ON admin_search_history FOR INSERT
TO authenticated
WITH CHECK (
admin_id = auth.uid() AND
EXISTS (
SELECT 1 FROM profiles
WHERE profiles.id = auth.uid()
AND profiles.role = 'admin'
)
);
-- Helper Functions
CREATE OR REPLACE FUNCTION log_admin_action(
p_action TEXT,
p_entity_type TEXT,
p_entity_id TEXT DEFAULT NULL,
p_details JSONB DEFAULT '{}'::jsonb
)
RETURNS UUID
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
v_log_id UUID;
BEGIN
INSERT INTO admin_logs (admin_id, action, entity_type, entity_id, details)
VALUES (auth.uid(), p_action, p_entity_type, p_entity_id, p_details)
RETURNING id INTO v_log_id;
RETURN v_log_id;
END;
$$;
-- Function to get admin dashboard stats
CREATE OR REPLACE FUNCTION get_admin_dashboard_stats()
RETURNS JSONB
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
v_stats JSONB;
BEGIN
-- Check if user is admin
IF NOT EXISTS (
SELECT 1 FROM profiles
WHERE id = auth.uid() AND role = 'admin'
) THEN
RAISE EXCEPTION 'Unauthorized';
END IF;
SELECT jsonb_build_object(
'total_users', (SELECT COUNT(*) FROM profiles),
'total_trips', (SELECT COUNT(*) FROM trips),
'total_places', (SELECT COUNT(*) FROM places),
'total_leads', (SELECT COUNT(*) FROM provider_leads),
'total_providers', (SELECT COUNT(*) FROM provider_profiles),
'active_providers', (SELECT COUNT(*) FROM provider_profiles WHERE is_active = true),
'total_revenue', (SELECT COALESCE(SUM(amount), 0) FROM provider_transactions WHERE type = 'lead_purchase'),
'recent_activity_count', (SELECT COUNT(*) FROM admin_logs WHERE created_at > now() - interval '24 hours'),
'pending_leads', (SELECT COUNT(*) FROM provider_leads WHERE status = 'available'),
'sold_leads', (SELECT COUNT(*) FROM provider_leads WHERE status = 'sold')
) INTO v_stats;
RETURN v_stats;
END;
$$;