

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;


CREATE EXTENSION IF NOT EXISTS "pgsodium";






COMMENT ON SCHEMA "public" IS 'standard public schema';



CREATE EXTENSION IF NOT EXISTS "pg_graphql" WITH SCHEMA "graphql";






CREATE EXTENSION IF NOT EXISTS "pg_stat_statements" WITH SCHEMA "extensions";






CREATE EXTENSION IF NOT EXISTS "pg_trgm" WITH SCHEMA "extensions";






CREATE EXTENSION IF NOT EXISTS "pgcrypto" WITH SCHEMA "extensions";






CREATE EXTENSION IF NOT EXISTS "pgjwt" WITH SCHEMA "extensions";






CREATE EXTENSION IF NOT EXISTS "supabase_vault" WITH SCHEMA "vault";






CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA "extensions";






CREATE TYPE "public"."comparison_operator" AS ENUM (
    'less_than',
    'less_than_equal',
    'greater_than',
    'greater_than_equal',
    'equal_to',
    'not_equal_to'
);


ALTER TYPE "public"."comparison_operator" OWNER TO "postgres";


CREATE TYPE "public"."metric_category" AS ENUM (
    'performance',
    'seo',
    'accessibility',
    'best_practices',
    'security',
    'pwa'
);


ALTER TYPE "public"."metric_category" OWNER TO "postgres";


CREATE TYPE "public"."notification_channel" AS ENUM (
    'email',
    'slack',
    'webhook',
    'in_app'
);


ALTER TYPE "public"."notification_channel" OWNER TO "postgres";


CREATE TYPE "public"."resource_type" AS ENUM (
    'script',
    'stylesheet',
    'image',
    'font',
    'document',
    'media',
    'other'
);


ALTER TYPE "public"."resource_type" OWNER TO "postgres";


CREATE TYPE "public"."scan_status" AS ENUM (
    'pending',
    'queued',
    'running',
    'completed',
    'failed',
    'cancelled'
);


ALTER TYPE "public"."scan_status" OWNER TO "postgres";


CREATE TYPE "public"."severity_level" AS ENUM (
    'critical',
    'high',
    'medium',
    'low',
    'info'
);


ALTER TYPE "public"."severity_level" OWNER TO "postgres";


CREATE TYPE "public"."subscription_tier" AS ENUM (
    'free',
    'starter',
    'professional',
    'enterprise'
);


ALTER TYPE "public"."subscription_tier" OWNER TO "postgres";


CREATE TYPE "public"."user_role" AS ENUM (
    'owner',
    'admin',
    'editor',
    'viewer'
);


ALTER TYPE "public"."user_role" OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."apply_data_retention"() RETURNS "void"
    LANGUAGE "plpgsql" SECURITY DEFINER
    SET "search_path" TO 'public', 'pg_temp'
    AS $$
BEGIN
  -- Delete old scan results (older than 90 days)
  DELETE FROM public.scan_results 
  WHERE created_at < NOW() - INTERVAL '90 days';
  
  -- Delete old metric values (older than 90 days)
  DELETE FROM public.metric_values 
  WHERE created_at < NOW() - INTERVAL '90 days';
  
  -- Delete old alert history (older than 365 days)
  DELETE FROM public.alert_history 
  WHERE created_at < NOW() - INTERVAL '365 days';
  
  -- Delete old audit logs (older than 365 days)
  DELETE FROM public.audit_logs 
  WHERE created_at < NOW() - INTERVAL '365 days';
END;
$$;


ALTER FUNCTION "public"."apply_data_retention"() OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."calculate_competitor_comparison"("website_id" "uuid") RETURNS TABLE("metric_key" character varying, "your_score" numeric, "competitor_avg" numeric, "competitor_best" numeric, "percentile" numeric)
    LANGUAGE "plpgsql"
    SET "search_path" TO 'public', 'pg_temp'
    AS $$
BEGIN
    RETURN QUERY
    WITH your_metrics AS (
        SELECT 
            m.key,
            mv.value
        FROM scans s
        JOIN metric_values mv ON mv.scan_id = s.id
        JOIN metric_definitions m ON m.id = mv.metric_id
        WHERE s.website_id = calculate_competitor_comparison.website_id
        AND s.created_at = (
            SELECT MAX(created_at)
            FROM scans
            WHERE website_id = calculate_competitor_comparison.website_id
        )
    ),
    competitor_metrics AS (
        SELECT 
            m.key,
            mv.value,
            PERCENT_RANK() OVER (PARTITION BY m.key ORDER BY mv.value) as percentile
        FROM scans s
        JOIN metric_values mv ON mv.scan_id = s.id
        JOIN metric_definitions m ON m.id = mv.metric_id
        WHERE s.website_id IN (
            SELECT competitor_url_id
            FROM competitor_websites
            WHERE website_id = calculate_competitor_comparison.website_id
        )
        AND s.created_at >= NOW() - INTERVAL '30 days'
    )
    SELECT 
        ym.key,
        ym.value as your_score,
        AVG(cm.value) as competitor_avg,
        MAX(cm.value) as competitor_best,
        MAX(cm.percentile) * 100 as percentile
    FROM your_metrics ym
    LEFT JOIN competitor_metrics cm ON cm.key = ym.key
    GROUP BY ym.key, ym.value;
END;
$$;


ALTER FUNCTION "public"."calculate_competitor_comparison"("website_id" "uuid") OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."calculate_competitor_comparison"("website_id_param" "uuid", "competitor_id_param" "uuid") RETURNS "jsonb"
    LANGUAGE "plpgsql" SECURITY DEFINER
    SET "search_path" TO 'public', 'pg_temp'
    AS $$
DECLARE
  result jsonb;
BEGIN
  -- Calculate comparison metrics between website and competitor
  SELECT jsonb_build_object(
    'performance_score_diff', 
    COALESCE(w.performance_score - c.performance_score, 0),
    'seo_score_diff',
    COALESCE(w.seo_score - c.seo_score, 0),
    'accessibility_score_diff',
    COALESCE(w.accessibility_score - c.accessibility_score, 0)
  ) INTO result
  FROM public.websites w
  CROSS JOIN public.competitor_websites c
  WHERE w.id = website_id_param 
    AND c.id = competitor_id_param;
  
  RETURN COALESCE(result, '{}'::jsonb);
END;
$$;


ALTER FUNCTION "public"."calculate_competitor_comparison"("website_id_param" "uuid", "competitor_id_param" "uuid") OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."calculate_health_score"("website_id_param" "uuid") RETURNS numeric
    LANGUAGE "plpgsql" SECURITY DEFINER
    SET "search_path" TO 'public', 'pg_temp'
    AS $$
DECLARE
  health_score numeric;
BEGIN
  -- Calculate weighted health score based on latest metrics
  SELECT 
    COALESCE(
      (performance_score * 0.4 + 
       seo_score * 0.3 + 
       accessibility_score * 0.2 + 
       best_practices_score * 0.1), 
      0
    )
  INTO health_score
  FROM public.websites
  WHERE id = website_id_param;
  
  RETURN COALESCE(health_score, 0);
END;
$$;


ALTER FUNCTION "public"."calculate_health_score"("website_id_param" "uuid") OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."email_exists"("email_to_check" "text") RETURNS boolean
    LANGUAGE "sql" SECURITY DEFINER
    AS $$
  select exists(
    select 1 from users where lower(email) = lower(email_to_check)
  );
$$;


ALTER FUNCTION "public"."email_exists"("email_to_check" "text") OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."generate_performance_report"("website_id" "uuid", "days" integer) RETURNS "jsonb"
    LANGUAGE "plpgsql"
    SET "search_path" TO 'public', 'pg_temp'
    AS $$
DECLARE
    report JSONB;
BEGIN
    SELECT jsonb_build_object(
        'website_info', (
            SELECT jsonb_build_object(
                'name', name,
                'url', base_url,
                'report_period', jsonb_build_object(
                    'start', NOW() - (days || ' days')::interval,
                    'end', NOW()
                )
            )
            FROM websites
            WHERE id = website_id
        ),
        'performance_summary', (
            SELECT jsonb_build_object(
                'average_performance_score', AVG(mv.value),
                'best_performance_score', MAX(mv.value),
                'worst_performance_score', MIN(mv.value),
                'trend', jsonb_agg(
                    jsonb_build_object(
                        'date', DATE(s.created_at),
                        'score', mv.value
                    ) ORDER BY s.created_at
                )
            )
            FROM scans s
            JOIN metric_values mv ON mv.scan_id = s.id
            JOIN metric_definitions md ON md.id = mv.metric_id
            WHERE s.website_id = generate_performance_report.website_id
            AND md.key = 'performance'
            AND s.created_at >= NOW() - (days || ' days')::interval
        ),
        'core_metrics', (
            SELECT jsonb_object_agg(
                md.key,
                jsonb_build_object(
                    'average', AVG(mv.value),
                    'best', MAX(mv.value),
                    'worst', MIN(mv.value)
                )
            )
            FROM scans s
            JOIN metric_values mv ON mv.scan_id = s.id
            JOIN metric_definitions md ON md.id = mv.metric_id
            WHERE s.website_id = generate_performance_report.website_id
            AND md.is_core_metric = true
            AND s.created_at >= NOW() - (days || ' days')::interval
        ),
        'resource_summary', (
            SELECT jsonb_object_agg(
                resource_type,
                jsonb_build_object(
                    'count', COUNT(*),
                    'total_size', SUM(size_bytes),
                    'average_duration', AVG(duration_ms)
                )
            )
            FROM scans s
            JOIN resource_analysis ra ON ra.scan_id = s.id
            WHERE s.website_id = generate_performance_report.website_id
            AND s.created_at >= NOW() - (days || ' days')::interval
        ),
        'alerts', (
            SELECT jsonb_agg(
                jsonb_build_object(
                    'severity', severity,
                    'message', message,
                    'created_at', created_at
                )
            )
            FROM alerts
            WHERE website_id = generate_performance_report.website_id
            AND created_at >= NOW() - (days || ' days')::interval
        )
    ) INTO report;

    RETURN report;
END;
$$;


ALTER FUNCTION "public"."generate_performance_report"("website_id" "uuid", "days" integer) OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."generate_performance_report"("website_id_param" "uuid", "start_date" timestamp with time zone DEFAULT ("now"() - '30 days'::interval), "end_date" timestamp with time zone DEFAULT "now"()) RETURNS "jsonb"
    LANGUAGE "plpgsql" SECURITY DEFINER
    SET "search_path" TO 'public', 'pg_temp'
    AS $$
DECLARE
  report jsonb;
BEGIN
  -- Generate comprehensive performance report
  SELECT jsonb_build_object(
    'website_id', website_id_param,
    'period', jsonb_build_object(
      'start_date', start_date,
      'end_date', end_date
    ),
    'summary', jsonb_build_object(
      'total_scans', COUNT(s.id),
      'avg_performance_score', AVG(w.performance_score),
      'avg_seo_score', AVG(w.seo_score),
      'avg_accessibility_score', AVG(w.accessibility_score)
    ),
    'trends', jsonb_agg(
      jsonb_build_object(
        'date', DATE(s.created_at),
        'performance_score', w.performance_score,
        'seo_score', w.seo_score
      )
    )
  ) INTO report
  FROM public.scans s
  JOIN public.websites w ON w.id = s.website_id
  WHERE s.website_id = website_id_param
    AND s.created_at BETWEEN start_date AND end_date
  GROUP BY website_id_param;
  
  RETURN COALESCE(report, '{}'::jsonb);
END;
$$;


ALTER FUNCTION "public"."generate_performance_report"("website_id_param" "uuid", "start_date" timestamp with time zone, "end_date" timestamp with time zone) OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."handle_new_user"() RETURNS "trigger"
    LANGUAGE "plpgsql" SECURITY DEFINER
    SET "search_path" TO 'public', 'pg_temp'
    AS $$
BEGIN
  -- Log the new row to Postgres logs for debugging
  RAISE LOG 'New user created: %', ROW(NEW.*);
  
  -- Insert into public.users table
  INSERT INTO public.users (id, email, organization_id, role, created_at, updated_at)
  VALUES (
    NEW.id,
    NEW.email,
    NEW.raw_user_meta_data->>'organization_id',
    COALESCE(NEW.raw_user_meta_data->>'role', 'member'),
    NOW(),
    NOW()
  );
  
  RETURN NEW;
END;
$$;


ALTER FUNCTION "public"."handle_new_user"() OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."perform_maintenance"() RETURNS "void"
    LANGUAGE "plpgsql"
    SET "search_path" TO 'public', 'pg_temp'
    AS $$
BEGIN
    -- Clean up old rate limit records
    DELETE FROM rate_limits
    WHERE window_start < NOW() - INTERVAL '1 day';

    -- Archive old notifications
    UPDATE notification_deliveries
    SET status = 'archived'
    WHERE created_at < NOW() - INTERVAL '30 days';

    -- Clean up expired API keys
    UPDATE api_keys
    SET is_active = false
    WHERE expires_at < NOW();

    -- Update statistics
    ANALYZE websites;
    ANALYZE scans;
    ANALYZE metric_values;
    ANALYZE resource_analysis;

    -- Vacuum analyze for better query planning
    VACUUM ANALYZE websites;
    VACUUM ANALYZE scans;
    VACUUM ANALYZE metric_values;
    VACUUM ANALYZE resource_analysis;
END;
$$;


ALTER FUNCTION "public"."perform_maintenance"() OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."process_alert_notifications"() RETURNS "trigger"
    LANGUAGE "plpgsql"
    SET "search_path" TO 'public', 'pg_temp'
    AS $$
DECLARE
    website_record RECORD;
    user_record RECORD;
BEGIN
    -- Get website details
    SELECT * INTO website_record 
    FROM websites 
    WHERE id = NEW.website_id;

    -- Insert notification for each user in the organization
    FOR user_record IN 
        SELECT u.* 
        FROM users u
        WHERE u.organization_id = website_record.organization_id
        AND (u.settings->>'email_notifications')::boolean = true
    LOOP
        INSERT INTO notification_deliveries (
            alert_id,
            channel,
            recipient,
            content
        ) VALUES (
            NEW.id,
            'email',
            user_record.email,
            format(
                'Alert for %s: %s. Severity: %s',
                website_record.name,
                NEW.message,
                NEW.severity
            )
        );
    END LOOP;

    RETURN NEW;
END;
$$;


ALTER FUNCTION "public"."process_alert_notifications"() OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."update_scan_status"() RETURNS "trigger"
    LANGUAGE "plpgsql"
    SET "search_path" TO 'public', 'pg_temp'
    AS $$
BEGIN
    IF NEW.status = 'completed' THEN
        -- Update website's last scan timestamp
        UPDATE websites 
        SET last_scan_at = NOW()
        WHERE id = NEW.website_id;
        
        -- Check for alerts
        INSERT INTO alerts (website_id, page_id, severity, title, message)
        SELECT 
            NEW.website_id,
            NEW.page_id,
            ac.severity,
            'Metric threshold exceeded',
            format('%s is %s threshold of %s', m.name, ac.comparison, ac.threshold)
        FROM metric_values mv
        JOIN metric_definitions m ON m.id = mv.metric_id
        JOIN alert_configurations ac ON ac.metric_id = m.id
        WHERE mv.scan_id = NEW.id
        AND ac.website_id = NEW.website_id
        AND (
            CASE ac.comparison
                WHEN 'less_than' THEN mv.value < ac.threshold
                WHEN 'greater_than' THEN mv.value > ac.threshold
                WHEN 'equal_to' THEN mv.value = ac.threshold
            END
        );
    END IF;
    
    RETURN NEW;
END;
$$;


ALTER FUNCTION "public"."update_scan_status"() OWNER TO "postgres";

SET default_tablespace = '';

SET default_table_access_method = "heap";


CREATE TABLE IF NOT EXISTS "public"."alert_configurations" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "website_id" "uuid" NOT NULL,
    "name" character varying NOT NULL,
    "description" "text",
    "metric_id" "uuid" NOT NULL,
    "threshold" numeric NOT NULL,
    "comparison" "public"."comparison_operator" DEFAULT 'less_than'::"public"."comparison_operator",
    "severity" "public"."severity_level" DEFAULT 'medium'::"public"."severity_level",
    "consecutive_count" integer DEFAULT 1,
    "cooldown_minutes" integer DEFAULT 60,
    "notification_channels" "public"."notification_channel"[] DEFAULT ARRAY['email'::"public"."notification_channel"],
    "notification_template" "text",
    "is_active" boolean DEFAULT true,
    "last_triggered_at" timestamp with time zone,
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."alert_configurations" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."alert_history" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "alert_id" "uuid" NOT NULL,
    "event_type" character varying NOT NULL,
    "event_data" "jsonb" NOT NULL,
    "created_by" "uuid",
    "created_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."alert_history" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."alerts" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "website_id" "uuid" NOT NULL,
    "page_id" "uuid",
    "config_id" "uuid",
    "metric_id" "uuid",
    "severity" "public"."severity_level" DEFAULT 'medium'::"public"."severity_level",
    "title" character varying NOT NULL,
    "message" "text" NOT NULL,
    "details" "jsonb" DEFAULT '{}'::"jsonb",
    "status" character varying DEFAULT 'open'::character varying,
    "acknowledged_by" "uuid",
    "acknowledged_at" timestamp with time zone,
    "resolved_at" timestamp with time zone,
    "resolution_note" "text",
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."alerts" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."api_keys" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "organization_id" "uuid" NOT NULL,
    "name" character varying NOT NULL,
    "key_hash" character varying NOT NULL,
    "scopes" character varying[] DEFAULT ARRAY['read'::"text"],
    "rate_limit_per_minute" integer DEFAULT 60,
    "is_active" boolean DEFAULT true,
    "last_used_at" timestamp with time zone,
    "expires_at" timestamp with time zone,
    "created_by" "uuid",
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."api_keys" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."audit_logs" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "organization_id" "uuid",
    "user_id" "uuid",
    "action" character varying NOT NULL,
    "entity_type" character varying NOT NULL,
    "entity_id" "uuid",
    "changes" "jsonb",
    "ip_address" character varying,
    "user_agent" character varying,
    "created_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."audit_logs" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."budget_violations" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "budget_id" "uuid" NOT NULL,
    "scan_id" "uuid" NOT NULL,
    "actual_value" numeric NOT NULL,
    "threshold_value" numeric NOT NULL,
    "percentage_over" numeric,
    "created_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."budget_violations" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."competitor_websites" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "website_id" "uuid" NOT NULL,
    "competitor_url" character varying NOT NULL,
    "name" character varying NOT NULL,
    "is_active" boolean DEFAULT true,
    "scan_frequency" character varying DEFAULT 'daily'::character varying,
    "metrics_to_track" character varying[] DEFAULT ARRAY['performance'::"text", 'seo'::"text", 'accessibility'::"text", 'best_practices'::"text"],
    "last_scan_at" timestamp with time zone,
    "metadata" "jsonb" DEFAULT '{}'::"jsonb",
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."competitor_websites" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."crawl_queue" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "website_id" "uuid" NOT NULL,
    "url" character varying NOT NULL,
    "priority" integer DEFAULT 1,
    "status" character varying DEFAULT 'pending'::character varying,
    "parent_url" character varying,
    "discovery_depth" integer DEFAULT 0,
    "attempts" integer DEFAULT 0,
    "last_attempt_at" timestamp with time zone,
    "next_attempt_at" timestamp with time zone,
    "error_message" "text",
    "metadata" "jsonb" DEFAULT '{}'::"jsonb",
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."crawl_queue" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."crawl_sessions" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "website_id" "uuid" NOT NULL,
    "status" character varying DEFAULT 'running'::character varying,
    "pages_discovered" integer DEFAULT 0,
    "pages_processed" integer DEFAULT 0,
    "start_url" character varying NOT NULL,
    "max_depth" integer,
    "started_at" timestamp with time zone DEFAULT "now"(),
    "completed_at" timestamp with time zone,
    "error_message" "text",
    "metadata" "jsonb" DEFAULT '{}'::"jsonb",
    "created_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."crawl_sessions" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."dashboard_widgets" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "dashboard_id" "uuid" NOT NULL,
    "widget_type" character varying NOT NULL,
    "name" character varying NOT NULL,
    "config" "jsonb" NOT NULL,
    "position" "jsonb" NOT NULL,
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."dashboard_widgets" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."dashboards" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "organization_id" "uuid" NOT NULL,
    "name" character varying NOT NULL,
    "description" "text",
    "layout" "jsonb" DEFAULT '[]'::"jsonb",
    "is_default" boolean DEFAULT false,
    "created_by" "uuid",
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."dashboards" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."generated_reports" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "template_id" "uuid" NOT NULL,
    "website_id" "uuid",
    "generated_by" "uuid",
    "report_data" "jsonb" NOT NULL,
    "format" character varying DEFAULT 'pdf'::character varying,
    "file_url" character varying,
    "created_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."generated_reports" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."metric_definitions" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "key" character varying NOT NULL,
    "name" character varying NOT NULL,
    "description" "text" NOT NULL,
    "category" "public"."metric_category" NOT NULL,
    "unit" character varying,
    "is_core_metric" boolean DEFAULT false,
    "default_threshold" numeric,
    "warning_threshold" numeric,
    "critical_threshold" numeric,
    "direction" character varying DEFAULT 'higher_is_better'::character varying NOT NULL,
    "weight" numeric DEFAULT 1.0,
    "documentation_url" "text",
    "created_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."metric_definitions" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."metric_values" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "scan_id" "uuid" NOT NULL,
    "metric_id" "uuid" NOT NULL,
    "value" numeric NOT NULL,
    "raw_value" character varying,
    "unit" character varying,
    "is_passing" boolean,
    "created_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."metric_values" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."notification_deliveries" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "alert_id" "uuid" NOT NULL,
    "channel" "public"."notification_channel" NOT NULL,
    "recipient" character varying NOT NULL,
    "content" "text" NOT NULL,
    "status" character varying DEFAULT 'pending'::character varying,
    "sent_at" timestamp with time zone,
    "error_message" "text",
    "retry_count" integer DEFAULT 0,
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."notification_deliveries" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."organizations" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "name" character varying NOT NULL,
    "subscription_tier" character varying DEFAULT 'free'::character varying,
    "subscription_status" character varying DEFAULT 'active'::character varying,
    "settings" "jsonb" DEFAULT '{"retention_days": 90, "alert_email_digest": "daily", "default_scan_depth": 3, "enable_competitor_analysis": false}'::"jsonb",
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."organizations" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."pages" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "website_id" "uuid" NOT NULL,
    "url" character varying NOT NULL,
    "path" character varying NOT NULL,
    "title" character varying,
    "description" "text",
    "content_hash" character varying,
    "content_type" character varying,
    "status_code" integer,
    "is_active" boolean DEFAULT true,
    "priority" integer DEFAULT 1,
    "depth" integer DEFAULT 0,
    "parent_page_id" "uuid",
    "discovery_method" character varying DEFAULT 'crawl'::character varying,
    "last_seen_at" timestamp with time zone,
    "metadata" "jsonb" DEFAULT '{"word_count": 0, "is_indexable": true, "has_canonical": false, "inbound_links": 0, "outbound_links": 0}'::"jsonb",
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."pages" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."performance_budgets" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "website_id" "uuid" NOT NULL,
    "name" character varying NOT NULL,
    "description" "text",
    "metric_id" "uuid",
    "budget_type" character varying NOT NULL,
    "threshold" numeric NOT NULL,
    "applies_to" "jsonb" DEFAULT '{"paths": ["/*"], "resource_types": ["all"]}'::"jsonb",
    "is_active" boolean DEFAULT true,
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."performance_budgets" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."scans" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "website_id" "uuid" NOT NULL,
    "page_id" "uuid" NOT NULL,
    "triggered_by" "uuid",
    "scan_type" character varying DEFAULT 'full'::character varying NOT NULL,
    "status" "public"."scan_status" DEFAULT 'pending'::"public"."scan_status",
    "priority" integer DEFAULT 1,
    "categories" "public"."metric_category"[] DEFAULT ARRAY['performance'::"public"."metric_category", 'seo'::"public"."metric_category", 'accessibility'::"public"."metric_category", 'best_practices'::"public"."metric_category"],
    "device_type" character varying DEFAULT 'desktop'::character varying,
    "user_agent" character varying,
    "lighthouse_version" character varying,
    "chrome_version" character varying,
    "environment" "jsonb" DEFAULT '{}'::"jsonb",
    "started_at" timestamp with time zone DEFAULT "now"(),
    "completed_at" timestamp with time zone,
    "duration_ms" integer,
    "error_message" "text",
    "retry_count" integer DEFAULT 0,
    "metadata" "jsonb" DEFAULT '{}'::"jsonb",
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"(),
    "scheduled_at" timestamp with time zone
);


ALTER TABLE "public"."scans" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."websites" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "organization_id" "uuid" NOT NULL,
    "base_url" character varying NOT NULL,
    "name" character varying NOT NULL,
    "is_active" boolean DEFAULT true,
    "crawl_settings" "jsonb" DEFAULT '{"max_depth": 3, "max_pages": 100, "crawl_timing": "off_peak", "crawl_frequency": "daily", "exclude_patterns": ["/admin/*", "/api/*", "*.pdf", "*.jpg", "*.png"], "include_patterns": ["/*"], "respect_robots_txt": true}'::"jsonb",
    "scan_schedule" "jsonb" DEFAULT '{"days": ["monday", "tuesday", "wednesday", "thursday", "friday"], "frequency": "hourly", "time_windows": ["0-6", "20-23"]}'::"jsonb",
    "performance_budgets" "jsonb" DEFAULT '{"max_requests": 100, "page_weight_kb": 1000, "time_to_interactive_ms": 3000, "first_contentful_paint_ms": 1000}'::"jsonb",
    "notifications" "jsonb" DEFAULT '{"channels": ["email"], "thresholds": {"seo": 90, "performance": 90, "accessibility": 90, "best_practices": 90}}'::"jsonb",
    "last_crawl_at" timestamp with time zone,
    "last_scan_at" timestamp with time zone,
    "metadata" "jsonb" DEFAULT '{}'::"jsonb",
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."websites" OWNER TO "postgres";


CREATE OR REPLACE VIEW "public"."performance_trends" WITH ("security_invoker"='on') AS
 SELECT "w"."id" AS "website_id",
    "w"."name" AS "website_name",
    "p"."url" AS "page_url",
    "m"."key" AS "metric_key",
    "mv"."value" AS "metric_value",
    "s"."created_at" AS "scan_date",
    "avg"("mv"."value") OVER (PARTITION BY "w"."id", "p"."id", "m"."id" ORDER BY "s"."created_at" ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS "rolling_average"
   FROM (((("public"."websites" "w"
     JOIN "public"."pages" "p" ON (("p"."website_id" = "w"."id")))
     JOIN "public"."scans" "s" ON (("s"."page_id" = "p"."id")))
     JOIN "public"."metric_values" "mv" ON (("mv"."scan_id" = "s"."id")))
     JOIN "public"."metric_definitions" "m" ON (("m"."id" = "mv"."metric_id")))
  WHERE ("s"."created_at" >= ("now"() - '30 days'::interval));


ALTER TABLE "public"."performance_trends" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."rate_limits" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "key_type" character varying NOT NULL,
    "key_value" character varying NOT NULL,
    "window_start" timestamp with time zone NOT NULL,
    "request_count" integer DEFAULT 1,
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."rate_limits" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."report_templates" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "organization_id" "uuid" NOT NULL,
    "name" character varying NOT NULL,
    "description" "text",
    "template_type" character varying NOT NULL,
    "content" "jsonb" NOT NULL,
    "schedule" "jsonb",
    "is_active" boolean DEFAULT true,
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."report_templates" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."resource_analysis" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "scan_id" "uuid" NOT NULL,
    "resource_type" "public"."resource_type" NOT NULL,
    "url" character varying NOT NULL,
    "size_bytes" integer NOT NULL,
    "transfer_size_bytes" integer,
    "duration_ms" integer,
    "is_third_party" boolean DEFAULT false,
    "is_cached" boolean,
    "compression_ratio" numeric,
    "mime_type" character varying,
    "protocol" character varying,
    "priority" character varying,
    "status_code" integer,
    "metadata" "jsonb" DEFAULT '{}'::"jsonb",
    "created_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."resource_analysis" OWNER TO "postgres";


CREATE OR REPLACE VIEW "public"."resource_usage_summary" WITH ("security_invoker"='on') AS
 SELECT "w"."id" AS "website_id",
    "w"."name" AS "website_name",
    "ra"."resource_type",
    "count"(*) AS "resource_count",
    "avg"("ra"."size_bytes") AS "avg_size",
    "sum"("ra"."size_bytes") AS "total_size",
    "avg"("ra"."duration_ms") AS "avg_duration"
   FROM (("public"."websites" "w"
     JOIN "public"."scans" "s" ON (("s"."website_id" = "w"."id")))
     JOIN "public"."resource_analysis" "ra" ON (("ra"."scan_id" = "s"."id")))
  WHERE ("s"."created_at" >= ("now"() - '24:00:00'::interval))
  GROUP BY "w"."id", "w"."name", "ra"."resource_type";


ALTER TABLE "public"."resource_usage_summary" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."scan_results" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "scan_id" "uuid" NOT NULL,
    "category" "public"."metric_category" NOT NULL,
    "score" numeric,
    "raw_data" "jsonb",
    "created_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."scan_results" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."url_patterns" (
    "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL,
    "website_id" "uuid" NOT NULL,
    "pattern" character varying NOT NULL,
    "pattern_type" character varying NOT NULL,
    "description" "text",
    "is_regex" boolean DEFAULT false,
    "is_active" boolean DEFAULT true,
    "priority" integer DEFAULT 1,
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."url_patterns" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."users" (
    "id" "uuid" NOT NULL,
    "email" character varying NOT NULL,
    "name" character varying,
    "organization_id" "uuid",
    "role" character varying DEFAULT 'viewer'::character varying,
    "is_active" boolean DEFAULT true,
    "settings" "jsonb" DEFAULT '{"dashboard_layout": "default", "email_notifications": true, "notification_frequency": "instant"}'::"jsonb",
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."users" OWNER TO "postgres";


ALTER TABLE ONLY "public"."alert_configurations"
    ADD CONSTRAINT "alert_configurations_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."alert_history"
    ADD CONSTRAINT "alert_history_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."alerts"
    ADD CONSTRAINT "alerts_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."api_keys"
    ADD CONSTRAINT "api_keys_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."audit_logs"
    ADD CONSTRAINT "audit_logs_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."budget_violations"
    ADD CONSTRAINT "budget_violations_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."competitor_websites"
    ADD CONSTRAINT "competitor_websites_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."competitor_websites"
    ADD CONSTRAINT "competitor_websites_website_id_competitor_url_key" UNIQUE ("website_id", "competitor_url");



ALTER TABLE ONLY "public"."crawl_queue"
    ADD CONSTRAINT "crawl_queue_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."crawl_sessions"
    ADD CONSTRAINT "crawl_sessions_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."dashboard_widgets"
    ADD CONSTRAINT "dashboard_widgets_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."dashboards"
    ADD CONSTRAINT "dashboards_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."generated_reports"
    ADD CONSTRAINT "generated_reports_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."metric_definitions"
    ADD CONSTRAINT "metric_definitions_key_key" UNIQUE ("key");



ALTER TABLE ONLY "public"."metric_definitions"
    ADD CONSTRAINT "metric_definitions_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."metric_values"
    ADD CONSTRAINT "metric_values_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."notification_deliveries"
    ADD CONSTRAINT "notification_deliveries_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."organizations"
    ADD CONSTRAINT "organizations_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."pages"
    ADD CONSTRAINT "pages_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."pages"
    ADD CONSTRAINT "pages_website_id_url_key" UNIQUE ("website_id", "url");



ALTER TABLE ONLY "public"."performance_budgets"
    ADD CONSTRAINT "performance_budgets_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."rate_limits"
    ADD CONSTRAINT "rate_limits_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."report_templates"
    ADD CONSTRAINT "report_templates_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."resource_analysis"
    ADD CONSTRAINT "resource_analysis_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."scan_results"
    ADD CONSTRAINT "scan_results_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."scans"
    ADD CONSTRAINT "scans_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."url_patterns"
    ADD CONSTRAINT "url_patterns_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."users"
    ADD CONSTRAINT "users_email_key" UNIQUE ("email");



ALTER TABLE ONLY "public"."users"
    ADD CONSTRAINT "users_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."websites"
    ADD CONSTRAINT "websites_organization_id_base_url_key" UNIQUE ("organization_id", "base_url");



ALTER TABLE ONLY "public"."websites"
    ADD CONSTRAINT "websites_pkey" PRIMARY KEY ("id");



CREATE INDEX "idx_alert_configurations_metric_id" ON "public"."alert_configurations" USING "btree" ("metric_id");



CREATE INDEX "idx_alert_configurations_website_id" ON "public"."alert_configurations" USING "btree" ("website_id");



CREATE INDEX "idx_alert_history_alert_id" ON "public"."alert_history" USING "btree" ("alert_id");



CREATE INDEX "idx_alerts_config_id" ON "public"."alerts" USING "btree" ("config_id");



CREATE INDEX "idx_alerts_metric_id" ON "public"."alerts" USING "btree" ("metric_id");



CREATE INDEX "idx_alerts_page_id" ON "public"."alerts" USING "btree" ("page_id");



CREATE INDEX "idx_alerts_website_id" ON "public"."alerts" USING "btree" ("website_id");



CREATE INDEX "idx_budget_violations_budget_id" ON "public"."budget_violations" USING "btree" ("budget_id");



CREATE INDEX "idx_budget_violations_scan_id" ON "public"."budget_violations" USING "btree" ("scan_id");



CREATE INDEX "idx_crawl_queue_website_id" ON "public"."crawl_queue" USING "btree" ("website_id");



CREATE INDEX "idx_crawl_sessions_website_id" ON "public"."crawl_sessions" USING "btree" ("website_id");



CREATE INDEX "idx_dashboard_widgets_dashboard_id" ON "public"."dashboard_widgets" USING "btree" ("dashboard_id");



CREATE INDEX "idx_generated_reports_template_id" ON "public"."generated_reports" USING "btree" ("template_id");



CREATE INDEX "idx_generated_reports_website_id" ON "public"."generated_reports" USING "btree" ("website_id");



CREATE INDEX "idx_metric_values_metric_id" ON "public"."metric_values" USING "btree" ("metric_id");



CREATE INDEX "idx_metric_values_scan_id" ON "public"."metric_values" USING "btree" ("scan_id");



CREATE INDEX "idx_notification_deliveries_alert_id" ON "public"."notification_deliveries" USING "btree" ("alert_id");



CREATE INDEX "idx_pages_parent_page_id" ON "public"."pages" USING "btree" ("parent_page_id");



CREATE INDEX "idx_performance_budgets_metric_id" ON "public"."performance_budgets" USING "btree" ("metric_id");



CREATE INDEX "idx_performance_budgets_website_id" ON "public"."performance_budgets" USING "btree" ("website_id");



CREATE INDEX "idx_resource_analysis_scan_id" ON "public"."resource_analysis" USING "btree" ("scan_id");



CREATE INDEX "idx_scan_results_scan_id" ON "public"."scan_results" USING "btree" ("scan_id");



CREATE INDEX "idx_scans_page_id" ON "public"."scans" USING "btree" ("page_id");



CREATE INDEX "idx_scans_website_id" ON "public"."scans" USING "btree" ("website_id");



CREATE INDEX "idx_url_patterns_website_id" ON "public"."url_patterns" USING "btree" ("website_id");



CREATE INDEX "idx_users_organization_id" ON "public"."users" USING "btree" ("organization_id");



CREATE OR REPLACE TRIGGER "alert_notification_trigger" AFTER INSERT ON "public"."alerts" FOR EACH ROW EXECUTE FUNCTION "public"."process_alert_notifications"();



CREATE OR REPLACE TRIGGER "scan_status_update" AFTER UPDATE OF "status" ON "public"."scans" FOR EACH ROW WHEN (("old"."status" IS DISTINCT FROM "new"."status")) EXECUTE FUNCTION "public"."update_scan_status"();



ALTER TABLE ONLY "public"."alert_configurations"
    ADD CONSTRAINT "alert_configurations_metric_id_fkey" FOREIGN KEY ("metric_id") REFERENCES "public"."metric_definitions"("id");



ALTER TABLE ONLY "public"."alert_configurations"
    ADD CONSTRAINT "alert_configurations_website_id_fkey" FOREIGN KEY ("website_id") REFERENCES "public"."websites"("id");



ALTER TABLE ONLY "public"."alert_history"
    ADD CONSTRAINT "alert_history_alert_id_fkey" FOREIGN KEY ("alert_id") REFERENCES "public"."alerts"("id");



ALTER TABLE ONLY "public"."alerts"
    ADD CONSTRAINT "alerts_config_id_fkey" FOREIGN KEY ("config_id") REFERENCES "public"."alert_configurations"("id");



ALTER TABLE ONLY "public"."alerts"
    ADD CONSTRAINT "alerts_metric_id_fkey" FOREIGN KEY ("metric_id") REFERENCES "public"."metric_definitions"("id");



ALTER TABLE ONLY "public"."alerts"
    ADD CONSTRAINT "alerts_page_id_fkey" FOREIGN KEY ("page_id") REFERENCES "public"."pages"("id");



ALTER TABLE ONLY "public"."alerts"
    ADD CONSTRAINT "alerts_website_id_fkey" FOREIGN KEY ("website_id") REFERENCES "public"."websites"("id");



ALTER TABLE ONLY "public"."budget_violations"
    ADD CONSTRAINT "budget_violations_budget_id_fkey" FOREIGN KEY ("budget_id") REFERENCES "public"."performance_budgets"("id");



ALTER TABLE ONLY "public"."budget_violations"
    ADD CONSTRAINT "budget_violations_scan_id_fkey" FOREIGN KEY ("scan_id") REFERENCES "public"."scans"("id");



ALTER TABLE ONLY "public"."competitor_websites"
    ADD CONSTRAINT "competitor_websites_website_id_fkey" FOREIGN KEY ("website_id") REFERENCES "public"."websites"("id");



ALTER TABLE ONLY "public"."crawl_queue"
    ADD CONSTRAINT "crawl_queue_website_id_fkey" FOREIGN KEY ("website_id") REFERENCES "public"."websites"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."crawl_sessions"
    ADD CONSTRAINT "crawl_sessions_website_id_fkey" FOREIGN KEY ("website_id") REFERENCES "public"."websites"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."dashboard_widgets"
    ADD CONSTRAINT "dashboard_widgets_dashboard_id_fkey" FOREIGN KEY ("dashboard_id") REFERENCES "public"."dashboards"("id");



ALTER TABLE ONLY "public"."users"
    ADD CONSTRAINT "fk_organization" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."generated_reports"
    ADD CONSTRAINT "generated_reports_template_id_fkey" FOREIGN KEY ("template_id") REFERENCES "public"."report_templates"("id");



ALTER TABLE ONLY "public"."generated_reports"
    ADD CONSTRAINT "generated_reports_website_id_fkey" FOREIGN KEY ("website_id") REFERENCES "public"."websites"("id");



ALTER TABLE ONLY "public"."metric_values"
    ADD CONSTRAINT "metric_values_metric_id_fkey" FOREIGN KEY ("metric_id") REFERENCES "public"."metric_definitions"("id");



ALTER TABLE ONLY "public"."metric_values"
    ADD CONSTRAINT "metric_values_scan_id_fkey" FOREIGN KEY ("scan_id") REFERENCES "public"."scans"("id");



ALTER TABLE ONLY "public"."notification_deliveries"
    ADD CONSTRAINT "notification_deliveries_alert_id_fkey" FOREIGN KEY ("alert_id") REFERENCES "public"."alerts"("id");



ALTER TABLE ONLY "public"."pages"
    ADD CONSTRAINT "pages_parent_page_id_fkey" FOREIGN KEY ("parent_page_id") REFERENCES "public"."pages"("id");



ALTER TABLE ONLY "public"."pages"
    ADD CONSTRAINT "pages_website_id_fkey" FOREIGN KEY ("website_id") REFERENCES "public"."websites"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."performance_budgets"
    ADD CONSTRAINT "performance_budgets_metric_id_fkey" FOREIGN KEY ("metric_id") REFERENCES "public"."metric_definitions"("id");



ALTER TABLE ONLY "public"."performance_budgets"
    ADD CONSTRAINT "performance_budgets_website_id_fkey" FOREIGN KEY ("website_id") REFERENCES "public"."websites"("id");



ALTER TABLE ONLY "public"."resource_analysis"
    ADD CONSTRAINT "resource_analysis_scan_id_fkey" FOREIGN KEY ("scan_id") REFERENCES "public"."scans"("id");



ALTER TABLE ONLY "public"."scan_results"
    ADD CONSTRAINT "scan_results_scan_id_fkey" FOREIGN KEY ("scan_id") REFERENCES "public"."scans"("id");



ALTER TABLE ONLY "public"."scans"
    ADD CONSTRAINT "scans_page_id_fkey" FOREIGN KEY ("page_id") REFERENCES "public"."pages"("id");



ALTER TABLE ONLY "public"."scans"
    ADD CONSTRAINT "scans_website_id_fkey" FOREIGN KEY ("website_id") REFERENCES "public"."websites"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."url_patterns"
    ADD CONSTRAINT "url_patterns_website_id_fkey" FOREIGN KEY ("website_id") REFERENCES "public"."websites"("id");



ALTER TABLE ONLY "public"."users"
    ADD CONSTRAINT "users_id_fkey" FOREIGN KEY ("id") REFERENCES "auth"."users"("id");



ALTER TABLE ONLY "public"."users"
    ADD CONSTRAINT "users_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id");



CREATE POLICY "Allow organization insert for authenticated" ON "public"."organizations" FOR INSERT TO "authenticated" WITH CHECK (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."alert_configurations" FOR SELECT USING (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."alert_history" FOR SELECT USING (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."audit_logs" FOR SELECT USING (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."budget_violations" FOR SELECT USING (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."competitor_websites" FOR SELECT USING (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."crawl_queue" FOR SELECT USING (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."crawl_sessions" FOR SELECT USING (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."dashboard_widgets" FOR SELECT USING (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."generated_reports" FOR SELECT USING (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."metric_definitions" FOR SELECT USING (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."notification_deliveries" FOR SELECT USING (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."performance_budgets" FOR SELECT USING (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."rate_limits" FOR SELECT USING (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."report_templates" FOR SELECT USING (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."resource_analysis" FOR SELECT USING (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."scan_results" FOR SELECT USING (true);



CREATE POLICY "Allow read for authenticated users" ON "public"."url_patterns" FOR SELECT USING (true);



CREATE POLICY "Allow user insert for anon" ON "public"."users" FOR INSERT TO "anon" WITH CHECK (true);



CREATE POLICY "Allow user insert for authenticated" ON "public"."users" FOR INSERT TO "authenticated" WITH CHECK (true);



CREATE POLICY "Allow user insert for authenticator" ON "public"."users" FOR INSERT TO "authenticator" WITH CHECK (true);



CREATE POLICY "Allow user insert for dashboard_user" ON "public"."users" FOR INSERT TO "dashboard_user" WITH CHECK (true);



CREATE POLICY "Allow user update for anon" ON "public"."users" FOR UPDATE TO "anon" USING (("id" = ( SELECT "auth"."uid"() AS "uid")));



CREATE POLICY "Allow user update for authenticated" ON "public"."users" FOR UPDATE TO "authenticated" USING (("id" = ( SELECT "auth"."uid"() AS "uid")));



CREATE POLICY "Allow user update for authenticator" ON "public"."users" FOR UPDATE TO "authenticator" USING (("id" = ( SELECT "auth"."uid"() AS "uid")));



CREATE POLICY "Allow user update for dashboard_user" ON "public"."users" FOR UPDATE TO "dashboard_user" USING (("id" = ( SELECT "auth"."uid"() AS "uid")));



CREATE POLICY "Users can delete pages of their organization" ON "public"."pages" FOR DELETE USING (("website_id" IN ( SELECT "websites"."id"
   FROM "public"."websites"
  WHERE ("websites"."organization_id" = ( SELECT "users"."organization_id"
           FROM "public"."users"
          WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))))));



CREATE POLICY "Users can delete scans of their organization" ON "public"."scans" FOR DELETE USING (("website_id" IN ( SELECT "w"."id"
   FROM "public"."websites" "w"
  WHERE ("w"."organization_id" = ( SELECT "users"."organization_id"
           FROM "public"."users"
          WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))))));



CREATE POLICY "Users can delete websites of their organization" ON "public"."websites" FOR DELETE USING (("organization_id" = ( SELECT "users"."organization_id"
   FROM "public"."users"
  WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))));



CREATE POLICY "Users can insert pages for their organization" ON "public"."pages" FOR INSERT WITH CHECK (("website_id" IN ( SELECT "websites"."id"
   FROM "public"."websites"
  WHERE ("websites"."organization_id" = ( SELECT "users"."organization_id"
           FROM "public"."users"
          WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))))));



CREATE POLICY "Users can insert scans for their organization" ON "public"."scans" FOR INSERT WITH CHECK (("website_id" IN ( SELECT "w"."id"
   FROM "public"."websites" "w"
  WHERE ("w"."organization_id" = ( SELECT "users"."organization_id"
           FROM "public"."users"
          WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))))));



CREATE POLICY "Users can insert websites for their organization" ON "public"."websites" FOR INSERT WITH CHECK (("organization_id" = ( SELECT "users"."organization_id"
   FROM "public"."users"
  WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))));



CREATE POLICY "Users can select their own data" ON "public"."users" FOR SELECT USING (("auth"."uid"() = "id"));



CREATE POLICY "Users can update pages of their organization" ON "public"."pages" FOR UPDATE USING (("website_id" IN ( SELECT "websites"."id"
   FROM "public"."websites"
  WHERE ("websites"."organization_id" = ( SELECT "users"."organization_id"
           FROM "public"."users"
          WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))))));



CREATE POLICY "Users can update scans of their organization" ON "public"."scans" FOR UPDATE USING (("website_id" IN ( SELECT "w"."id"
   FROM "public"."websites" "w"
  WHERE ("w"."organization_id" = ( SELECT "users"."organization_id"
           FROM "public"."users"
          WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))))));



CREATE POLICY "Users can update websites of their organization" ON "public"."websites" FOR UPDATE USING (("organization_id" = ( SELECT "users"."organization_id"
   FROM "public"."users"
  WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))));



CREATE POLICY "Users can view alerts they are allowed to" ON "public"."alerts" FOR SELECT USING (("website_id" IN ( SELECT "w"."id"
   FROM "public"."websites" "w"
  WHERE ("w"."organization_id" = ( SELECT "users"."organization_id"
           FROM "public"."users"
          WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))))));



CREATE POLICY "Users can view dashboards of their organization" ON "public"."dashboards" FOR SELECT USING (("organization_id" = ( SELECT "users"."organization_id"
   FROM "public"."users"
  WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))));



CREATE POLICY "Users can view metric_values of their organization" ON "public"."metric_values" FOR SELECT USING (("scan_id" IN ( SELECT "s"."id"
   FROM ("public"."scans" "s"
     JOIN "public"."websites" "w" ON (("w"."id" = "s"."website_id")))
  WHERE ("w"."organization_id" = ( SELECT "users"."organization_id"
           FROM "public"."users"
          WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))))));



CREATE POLICY "Users can view pages they are allowed to" ON "public"."pages" FOR SELECT USING (("website_id" IN ( SELECT "w"."id"
   FROM "public"."websites" "w"
  WHERE ("w"."organization_id" = ( SELECT "users"."organization_id"
           FROM "public"."users"
          WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))))));



CREATE POLICY "Users can view scans they are allowed to" ON "public"."scans" FOR SELECT USING (("website_id" IN ( SELECT "w"."id"
   FROM "public"."websites" "w"
  WHERE ("w"."organization_id" = ( SELECT "users"."organization_id"
           FROM "public"."users"
          WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))))));



CREATE POLICY "Users can view their org's API keys" ON "public"."api_keys" FOR SELECT USING (("organization_id" IN ( SELECT "users"."organization_id"
   FROM "public"."users"
  WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))));



CREATE POLICY "Users can view their org's websites" ON "public"."websites" FOR SELECT USING (("organization_id" = ( SELECT "users"."organization_id"
   FROM "public"."users"
  WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))));



CREATE POLICY "Users can view their organization" ON "public"."organizations" FOR SELECT USING (("id" = ( SELECT "users"."organization_id"
   FROM "public"."users"
  WHERE ("users"."id" = ( SELECT "auth"."uid"() AS "uid")))));



CREATE POLICY "Users can view their own profile" ON "public"."users" FOR SELECT USING (("id" = ( SELECT "auth"."uid"() AS "uid")));



ALTER TABLE "public"."alert_configurations" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."alert_history" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."alerts" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."api_keys" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."audit_logs" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."budget_violations" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."competitor_websites" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."crawl_queue" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."crawl_sessions" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."dashboard_widgets" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."dashboards" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."generated_reports" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."metric_definitions" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."metric_values" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."notification_deliveries" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."organizations" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."pages" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."performance_budgets" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."rate_limits" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."report_templates" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."resource_analysis" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."scan_results" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."scans" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."url_patterns" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."users" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."websites" ENABLE ROW LEVEL SECURITY;




ALTER PUBLICATION "supabase_realtime" OWNER TO "postgres";






GRANT USAGE ON SCHEMA "public" TO "postgres";
GRANT USAGE ON SCHEMA "public" TO "anon";
GRANT USAGE ON SCHEMA "public" TO "authenticated";
GRANT USAGE ON SCHEMA "public" TO "service_role";

















































































































































































































































































GRANT ALL ON FUNCTION "public"."apply_data_retention"() TO "anon";
GRANT ALL ON FUNCTION "public"."apply_data_retention"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."apply_data_retention"() TO "service_role";



GRANT ALL ON FUNCTION "public"."calculate_competitor_comparison"("website_id" "uuid") TO "anon";
GRANT ALL ON FUNCTION "public"."calculate_competitor_comparison"("website_id" "uuid") TO "authenticated";
GRANT ALL ON FUNCTION "public"."calculate_competitor_comparison"("website_id" "uuid") TO "service_role";



GRANT ALL ON FUNCTION "public"."calculate_competitor_comparison"("website_id_param" "uuid", "competitor_id_param" "uuid") TO "anon";
GRANT ALL ON FUNCTION "public"."calculate_competitor_comparison"("website_id_param" "uuid", "competitor_id_param" "uuid") TO "authenticated";
GRANT ALL ON FUNCTION "public"."calculate_competitor_comparison"("website_id_param" "uuid", "competitor_id_param" "uuid") TO "service_role";



GRANT ALL ON FUNCTION "public"."calculate_health_score"("website_id_param" "uuid") TO "anon";
GRANT ALL ON FUNCTION "public"."calculate_health_score"("website_id_param" "uuid") TO "authenticated";
GRANT ALL ON FUNCTION "public"."calculate_health_score"("website_id_param" "uuid") TO "service_role";



GRANT ALL ON FUNCTION "public"."email_exists"("email_to_check" "text") TO "anon";
GRANT ALL ON FUNCTION "public"."email_exists"("email_to_check" "text") TO "authenticated";
GRANT ALL ON FUNCTION "public"."email_exists"("email_to_check" "text") TO "service_role";



GRANT ALL ON FUNCTION "public"."generate_performance_report"("website_id" "uuid", "days" integer) TO "anon";
GRANT ALL ON FUNCTION "public"."generate_performance_report"("website_id" "uuid", "days" integer) TO "authenticated";
GRANT ALL ON FUNCTION "public"."generate_performance_report"("website_id" "uuid", "days" integer) TO "service_role";



GRANT ALL ON FUNCTION "public"."generate_performance_report"("website_id_param" "uuid", "start_date" timestamp with time zone, "end_date" timestamp with time zone) TO "anon";
GRANT ALL ON FUNCTION "public"."generate_performance_report"("website_id_param" "uuid", "start_date" timestamp with time zone, "end_date" timestamp with time zone) TO "authenticated";
GRANT ALL ON FUNCTION "public"."generate_performance_report"("website_id_param" "uuid", "start_date" timestamp with time zone, "end_date" timestamp with time zone) TO "service_role";



GRANT ALL ON FUNCTION "public"."handle_new_user"() TO "anon";
GRANT ALL ON FUNCTION "public"."handle_new_user"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."handle_new_user"() TO "service_role";



GRANT ALL ON FUNCTION "public"."perform_maintenance"() TO "anon";
GRANT ALL ON FUNCTION "public"."perform_maintenance"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."perform_maintenance"() TO "service_role";



GRANT ALL ON FUNCTION "public"."process_alert_notifications"() TO "anon";
GRANT ALL ON FUNCTION "public"."process_alert_notifications"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."process_alert_notifications"() TO "service_role";



GRANT ALL ON FUNCTION "public"."update_scan_status"() TO "anon";
GRANT ALL ON FUNCTION "public"."update_scan_status"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."update_scan_status"() TO "service_role";



























GRANT ALL ON TABLE "public"."alert_configurations" TO "anon";
GRANT ALL ON TABLE "public"."alert_configurations" TO "authenticated";
GRANT ALL ON TABLE "public"."alert_configurations" TO "service_role";



GRANT ALL ON TABLE "public"."alert_history" TO "anon";
GRANT ALL ON TABLE "public"."alert_history" TO "authenticated";
GRANT ALL ON TABLE "public"."alert_history" TO "service_role";



GRANT ALL ON TABLE "public"."alerts" TO "anon";
GRANT ALL ON TABLE "public"."alerts" TO "authenticated";
GRANT ALL ON TABLE "public"."alerts" TO "service_role";



GRANT ALL ON TABLE "public"."api_keys" TO "anon";
GRANT ALL ON TABLE "public"."api_keys" TO "authenticated";
GRANT ALL ON TABLE "public"."api_keys" TO "service_role";



GRANT ALL ON TABLE "public"."audit_logs" TO "anon";
GRANT ALL ON TABLE "public"."audit_logs" TO "authenticated";
GRANT ALL ON TABLE "public"."audit_logs" TO "service_role";



GRANT ALL ON TABLE "public"."budget_violations" TO "anon";
GRANT ALL ON TABLE "public"."budget_violations" TO "authenticated";
GRANT ALL ON TABLE "public"."budget_violations" TO "service_role";



GRANT ALL ON TABLE "public"."competitor_websites" TO "anon";
GRANT ALL ON TABLE "public"."competitor_websites" TO "authenticated";
GRANT ALL ON TABLE "public"."competitor_websites" TO "service_role";



GRANT ALL ON TABLE "public"."crawl_queue" TO "anon";
GRANT ALL ON TABLE "public"."crawl_queue" TO "authenticated";
GRANT ALL ON TABLE "public"."crawl_queue" TO "service_role";



GRANT ALL ON TABLE "public"."crawl_sessions" TO "anon";
GRANT ALL ON TABLE "public"."crawl_sessions" TO "authenticated";
GRANT ALL ON TABLE "public"."crawl_sessions" TO "service_role";



GRANT ALL ON TABLE "public"."dashboard_widgets" TO "anon";
GRANT ALL ON TABLE "public"."dashboard_widgets" TO "authenticated";
GRANT ALL ON TABLE "public"."dashboard_widgets" TO "service_role";



GRANT ALL ON TABLE "public"."dashboards" TO "anon";
GRANT ALL ON TABLE "public"."dashboards" TO "authenticated";
GRANT ALL ON TABLE "public"."dashboards" TO "service_role";



GRANT ALL ON TABLE "public"."generated_reports" TO "anon";
GRANT ALL ON TABLE "public"."generated_reports" TO "authenticated";
GRANT ALL ON TABLE "public"."generated_reports" TO "service_role";



GRANT ALL ON TABLE "public"."metric_definitions" TO "anon";
GRANT ALL ON TABLE "public"."metric_definitions" TO "authenticated";
GRANT ALL ON TABLE "public"."metric_definitions" TO "service_role";



GRANT ALL ON TABLE "public"."metric_values" TO "anon";
GRANT ALL ON TABLE "public"."metric_values" TO "authenticated";
GRANT ALL ON TABLE "public"."metric_values" TO "service_role";



GRANT ALL ON TABLE "public"."notification_deliveries" TO "anon";
GRANT ALL ON TABLE "public"."notification_deliveries" TO "authenticated";
GRANT ALL ON TABLE "public"."notification_deliveries" TO "service_role";



GRANT ALL ON TABLE "public"."organizations" TO "anon";
GRANT ALL ON TABLE "public"."organizations" TO "authenticated";
GRANT ALL ON TABLE "public"."organizations" TO "service_role";



GRANT ALL ON TABLE "public"."pages" TO "anon";
GRANT ALL ON TABLE "public"."pages" TO "authenticated";
GRANT ALL ON TABLE "public"."pages" TO "service_role";



GRANT ALL ON TABLE "public"."performance_budgets" TO "anon";
GRANT ALL ON TABLE "public"."performance_budgets" TO "authenticated";
GRANT ALL ON TABLE "public"."performance_budgets" TO "service_role";



GRANT ALL ON TABLE "public"."scans" TO "anon";
GRANT ALL ON TABLE "public"."scans" TO "authenticated";
GRANT ALL ON TABLE "public"."scans" TO "service_role";



GRANT ALL ON TABLE "public"."websites" TO "anon";
GRANT ALL ON TABLE "public"."websites" TO "authenticated";
GRANT ALL ON TABLE "public"."websites" TO "service_role";



GRANT ALL ON TABLE "public"."performance_trends" TO "anon";
GRANT ALL ON TABLE "public"."performance_trends" TO "authenticated";
GRANT ALL ON TABLE "public"."performance_trends" TO "service_role";



GRANT ALL ON TABLE "public"."rate_limits" TO "anon";
GRANT ALL ON TABLE "public"."rate_limits" TO "authenticated";
GRANT ALL ON TABLE "public"."rate_limits" TO "service_role";



GRANT ALL ON TABLE "public"."report_templates" TO "anon";
GRANT ALL ON TABLE "public"."report_templates" TO "authenticated";
GRANT ALL ON TABLE "public"."report_templates" TO "service_role";



GRANT ALL ON TABLE "public"."resource_analysis" TO "anon";
GRANT ALL ON TABLE "public"."resource_analysis" TO "authenticated";
GRANT ALL ON TABLE "public"."resource_analysis" TO "service_role";



GRANT ALL ON TABLE "public"."resource_usage_summary" TO "anon";
GRANT ALL ON TABLE "public"."resource_usage_summary" TO "authenticated";
GRANT ALL ON TABLE "public"."resource_usage_summary" TO "service_role";



GRANT ALL ON TABLE "public"."scan_results" TO "anon";
GRANT ALL ON TABLE "public"."scan_results" TO "authenticated";
GRANT ALL ON TABLE "public"."scan_results" TO "service_role";



GRANT ALL ON TABLE "public"."url_patterns" TO "anon";
GRANT ALL ON TABLE "public"."url_patterns" TO "authenticated";
GRANT ALL ON TABLE "public"."url_patterns" TO "service_role";



GRANT INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE "public"."users" TO "anon";
GRANT ALL ON TABLE "public"."users" TO "authenticated";
GRANT ALL ON TABLE "public"."users" TO "service_role";









ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES  TO "postgres";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES  TO "anon";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES  TO "authenticated";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES  TO "service_role";






ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS  TO "postgres";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS  TO "anon";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS  TO "authenticated";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS  TO "service_role";






ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES  TO "postgres";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES  TO "anon";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES  TO "authenticated";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES  TO "service_role";






























RESET ALL;
