ALTER TABLE public.portal_function_visibility ADD COLUMN IF NOT EXISTS association_id UUID REFERENCES public.associations(id) ON DELETE CASCADE; DROP INDEX IF EXISTS idx_portal_function_visibility_unique_scope; CREATE UNIQUE INDEX IF NOT EXISTS idx_portal_function_visibility_unique_scope ON public.portal_function_visibility ( portal, function_key, COALESCE(association_id, '00000000-0000-0000-0000-000000000000'::uuid), COALESCE(owner_user_id, '00000000-0000-0000-0000-000000000000'::uuid) ); CREATE INDEX IF NOT EXISTS idx_portal_function_visibility_association_id ON public.portal_function_visibility (association_id); CREATE OR REPLACE FUNCTION public.can_view_portal_function( _portal text, _function_key text, _user_id uuid DEFAULT auth.uid(), _association_id uuid DEFAULT NULL ) RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public' AS $function$ SELECT COALESCE(( SELECT pfv.enabled FROM public.portal_function_visibility pfv WHERE pfv.portal = _portal AND pfv.function_key = _function_key AND (pfv.owner_user_id = _user_id OR pfv.owner_user_id IS NULL) AND (pfv.association_id = _association_id OR pfv.association_id IS NULL) ORDER BY (pfv.owner_user_id = _user_id) DESC, (pfv.association_id = _association_id) DESC LIMIT 1 ), true) $function$;