diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts index 57d8bf11..c43304b2 100644 --- a/src/integrations/supabase/types.ts +++ b/src/integrations/supabase/types.ts @@ -335,6 +335,13 @@ export type Database = { referencedRelation: "content_submissions" referencedColumns: ["id"] }, + { + foreignKeyName: "company_submissions_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: true + referencedRelation: "moderation_queue_with_entities" + referencedColumns: ["id"] + }, ] } company_versions: { @@ -448,6 +455,13 @@ export type Database = { referencedRelation: "content_submissions" referencedColumns: ["id"] }, + { + foreignKeyName: "company_versions_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: false + referencedRelation: "moderation_queue_with_entities" + referencedColumns: ["id"] + }, ] } conflict_resolutions: { @@ -486,6 +500,13 @@ export type Database = { referencedRelation: "content_submissions" referencedColumns: ["id"] }, + { + foreignKeyName: "conflict_resolutions_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: false + referencedRelation: "moderation_queue_with_entities" + referencedColumns: ["id"] + }, ] } contact_email_threads: { @@ -783,6 +804,13 @@ export type Database = { referencedRelation: "content_submissions" referencedColumns: ["id"] }, + { + foreignKeyName: "content_submissions_original_submission_id_fkey" + columns: ["original_submission_id"] + isOneToOne: false + referencedRelation: "moderation_queue_with_entities" + referencedColumns: ["id"] + }, { foreignKeyName: "content_submissions_reviewer_id_fkey" columns: ["reviewer_id"] @@ -955,6 +983,13 @@ export type Database = { referencedRelation: "content_submissions" referencedColumns: ["id"] }, + { + foreignKeyName: "entity_timeline_events_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: false + referencedRelation: "moderation_queue_with_entities" + referencedColumns: ["id"] + }, { foreignKeyName: "entity_timeline_events_to_location_id_fkey" columns: ["to_location_id"] @@ -1319,6 +1354,13 @@ export type Database = { referencedRelation: "content_submissions" referencedColumns: ["id"] }, + { + foreignKeyName: "moderation_audit_log_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: false + referencedRelation: "moderation_queue_with_entities" + referencedColumns: ["id"] + }, ] } notification_channels: { @@ -1660,6 +1702,13 @@ export type Database = { referencedRelation: "content_submissions" referencedColumns: ["id"] }, + { + foreignKeyName: "park_submissions_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: true + referencedRelation: "moderation_queue_with_entities" + referencedColumns: ["id"] + }, ] } park_versions: { @@ -1806,6 +1855,13 @@ export type Database = { referencedRelation: "content_submissions" referencedColumns: ["id"] }, + { + foreignKeyName: "park_versions_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: false + referencedRelation: "moderation_queue_with_entities" + referencedColumns: ["id"] + }, ] } parks: { @@ -2024,6 +2080,13 @@ export type Database = { referencedRelation: "content_submissions" referencedColumns: ["id"] }, + { + foreignKeyName: "photo_submissions_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: false + referencedRelation: "moderation_queue_with_entities" + referencedColumns: ["id"] + }, ] } photos: { @@ -2921,6 +2984,13 @@ export type Database = { referencedRelation: "content_submissions" referencedColumns: ["id"] }, + { + foreignKeyName: "ride_model_submissions_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: true + referencedRelation: "moderation_queue_with_entities" + referencedColumns: ["id"] + }, ] } ride_model_technical_specifications: { @@ -3070,6 +3140,13 @@ export type Database = { referencedRelation: "content_submissions" referencedColumns: ["id"] }, + { + foreignKeyName: "ride_model_versions_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: false + referencedRelation: "moderation_queue_with_entities" + referencedColumns: ["id"] + }, ] } ride_models: { @@ -3433,6 +3510,13 @@ export type Database = { referencedRelation: "content_submissions" referencedColumns: ["id"] }, + { + foreignKeyName: "ride_submissions_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: true + referencedRelation: "moderation_queue_with_entities" + referencedColumns: ["id"] + }, ] } ride_technical_specifications: { @@ -3808,6 +3892,13 @@ export type Database = { referencedRelation: "content_submissions" referencedColumns: ["id"] }, + { + foreignKeyName: "ride_versions_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: false + referencedRelation: "moderation_queue_with_entities" + referencedColumns: ["id"] + }, ] } ride_water_details: { @@ -4208,6 +4299,13 @@ export type Database = { referencedRelation: "content_submissions" referencedColumns: ["id"] }, + { + foreignKeyName: "submission_items_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: false + referencedRelation: "moderation_queue_with_entities" + referencedColumns: ["id"] + }, ] } test_data_registry: { @@ -4333,6 +4431,13 @@ export type Database = { referencedRelation: "content_submissions" referencedColumns: ["id"] }, + { + foreignKeyName: "timeline_event_submissions_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: false + referencedRelation: "moderation_queue_with_entities" + referencedColumns: ["id"] + }, { foreignKeyName: "timeline_event_submissions_to_location_id_fkey" columns: ["to_location_id"] @@ -4691,6 +4796,71 @@ export type Database = { } Relationships: [] } + moderation_queue_with_entities: { + Row: { + assigned_profile: Json | null + assigned_to: string | null + escalated: boolean | null + escalation_reason: string | null + id: string | null + is_test_data: boolean | null + locked_until: string | null + review_notes: string | null + reviewed_at: string | null + reviewed_by: string | null + reviewer_profile: Json | null + status: string | null + submission_items: Json | null + submission_type: string | null + submitted_at: string | null + submitted_by: string | null + submitter_profile: Json | null + } + Relationships: [ + { + foreignKeyName: "content_submissions_assigned_to_fkey" + columns: ["assigned_to"] + isOneToOne: false + referencedRelation: "filtered_profiles" + referencedColumns: ["user_id"] + }, + { + foreignKeyName: "content_submissions_assigned_to_fkey" + columns: ["assigned_to"] + isOneToOne: false + referencedRelation: "profiles" + referencedColumns: ["user_id"] + }, + { + foreignKeyName: "content_submissions_reviewer_id_fkey" + columns: ["reviewed_by"] + isOneToOne: false + referencedRelation: "filtered_profiles" + referencedColumns: ["user_id"] + }, + { + foreignKeyName: "content_submissions_reviewer_id_fkey" + columns: ["reviewed_by"] + isOneToOne: false + referencedRelation: "profiles" + referencedColumns: ["user_id"] + }, + { + foreignKeyName: "content_submissions_user_id_fkey" + columns: ["submitted_by"] + isOneToOne: false + referencedRelation: "filtered_profiles" + referencedColumns: ["user_id"] + }, + { + foreignKeyName: "content_submissions_user_id_fkey" + columns: ["submitted_by"] + isOneToOne: false + referencedRelation: "profiles" + referencedColumns: ["user_id"] + }, + ] + } moderation_sla_metrics: { Row: { avg_resolution_hours: number | null @@ -4852,6 +5022,10 @@ export type Database = { dependent_item_type: string }[] } + get_submission_item_entity_data: { + Args: { p_item_data_id: string; p_item_type: string } + Returns: Json + } get_user_management_permissions: { Args: { _user_id: string } Returns: Json diff --git a/supabase/migrations/20251103162832_4e759640-7e86-4ce8-bb02-8b8c9d171f9a.sql b/supabase/migrations/20251103162832_4e759640-7e86-4ce8-bb02-8b8c9d171f9a.sql new file mode 100644 index 00000000..9b6987e0 --- /dev/null +++ b/supabase/migrations/20251103162832_4e759640-7e86-4ce8-bb02-8b8c9d171f9a.sql @@ -0,0 +1,123 @@ +-- Create function to dynamically get entity data from submission tables +CREATE OR REPLACE FUNCTION get_submission_item_entity_data( + p_item_type text, + p_item_data_id uuid +) RETURNS jsonb AS $$ +DECLARE + v_result jsonb; +BEGIN + CASE p_item_type + WHEN 'park' THEN + SELECT to_jsonb(ps.*) INTO v_result + FROM park_submissions ps + WHERE ps.id = p_item_data_id; + WHEN 'ride' THEN + SELECT to_jsonb(rs.*) INTO v_result + FROM ride_submissions rs + WHERE rs.id = p_item_data_id; + WHEN 'manufacturer', 'operator', 'designer', 'property_owner' THEN + SELECT to_jsonb(cs.*) INTO v_result + FROM company_submissions cs + WHERE cs.id = p_item_data_id; + WHEN 'ride_model' THEN + SELECT to_jsonb(rms.*) INTO v_result + FROM ride_model_submissions rms + WHERE rms.id = p_item_data_id; + WHEN 'photo' THEN + SELECT to_jsonb(ps.*) INTO v_result + FROM photo_submissions ps + WHERE ps.id = p_item_data_id; + ELSE + v_result := NULL; + END CASE; + + RETURN v_result; +END; +$$ LANGUAGE plpgsql STABLE SECURITY DEFINER; + +-- Create optimized view for moderation queue with pre-joined entity data +CREATE OR REPLACE VIEW moderation_queue_with_entities AS +SELECT + cs.id, + cs.submission_type, + cs.status, + cs.submitted_at, + cs.user_id as submitted_by, + cs.reviewed_at, + cs.reviewer_id as reviewed_by, + cs.reviewer_notes as review_notes, + cs.assigned_to, + cs.locked_until, + cs.escalated, + cs.escalation_reason, + cs.is_test_data, + -- Pre-load submitter profile + jsonb_build_object( + 'id', submitter.id, + 'username', submitter.username, + 'role', submitter_role.role + ) as submitter_profile, + -- Pre-load reviewer profile (if exists) + CASE + WHEN reviewer.id IS NOT NULL THEN + jsonb_build_object( + 'id', reviewer.id, + 'username', reviewer.username, + 'role', reviewer_role.role + ) + ELSE NULL + END as reviewer_profile, + -- Pre-load assigned moderator profile (if exists) + CASE + WHEN assigned.id IS NOT NULL THEN + jsonb_build_object( + 'id', assigned.id, + 'username', assigned.username, + 'role', assigned_role.role + ) + ELSE NULL + END as assigned_profile, + -- Pre-load submission items with entity data + COALESCE( + ( + SELECT jsonb_agg( + jsonb_build_object( + 'id', si.id, + 'submission_id', si.submission_id, + 'item_type', si.item_type, + 'item_data_id', si.item_data_id, + 'action_type', si.action_type, + 'status', si.status, + 'depends_on', si.depends_on, + 'rejection_reason', si.rejection_reason, + 'order_index', si.order_index, + 'approved_entity_id', si.approved_entity_id, + 'created_at', si.created_at, + 'entity_data', get_submission_item_entity_data(si.item_type, si.item_data_id) + ) + ORDER BY si.order_index, si.created_at + ) + FROM submission_items si + WHERE si.submission_id = cs.id + ), + '[]'::jsonb + ) as submission_items +FROM content_submissions cs +LEFT JOIN profiles submitter ON cs.user_id = submitter.user_id +LEFT JOIN user_roles submitter_role ON submitter.user_id = submitter_role.user_id +LEFT JOIN profiles reviewer ON cs.reviewer_id = reviewer.user_id +LEFT JOIN user_roles reviewer_role ON reviewer.user_id = reviewer_role.user_id +LEFT JOIN profiles assigned ON cs.assigned_to = assigned.user_id +LEFT JOIN user_roles assigned_role ON assigned.user_id = assigned_role.user_id; + +-- Create indexes for better query performance +CREATE INDEX IF NOT EXISTS idx_content_submissions_queue + ON content_submissions(status, submitted_at DESC) + WHERE status IN ('pending', 'in_review'); + +CREATE INDEX IF NOT EXISTS idx_content_submissions_locks + ON content_submissions(assigned_to, locked_until) + WHERE assigned_to IS NOT NULL; + +CREATE INDEX IF NOT EXISTS idx_submission_items_item_data_id + ON submission_items(item_data_id, item_type); \ No newline at end of file