-- ============================================================================ -- RAPPORT — Mitarbeiter einladen (Admin-Aktion) -- ============================================================================ -- Two-Step-Flow (vom Frontend orchestriert): -- 1. Admin ruft `supabase.auth.signUp(email, tempPassword)` mit einem -- temporären Client (ohne Session-persist), damit Admin-Session nicht -- "übernommen" wird. → liefert neue user_id. -- 2. Admin ruft `attach_user_to_studio(user_id, studio_id, role, username, name)` -- mit seinem eigenen Auth-Token. RPC prüft, dass Caller Admin im -- Ziel-Studio ist, und legt Profil + Membership an. -- -- Sicherheit: nur Admins eines Studios können dort Mitglieder hinzufügen. -- `attach` ist idempotent (ON CONFLICT update), damit der Flow re-runnable ist. -- ============================================================================ create or replace function attach_user_to_studio( p_user_id uuid, p_studio_id uuid, p_app_role_id text, p_username text, p_display_name text ) returns void language plpgsql security definer as $$ declare v_caller_id uuid := auth.uid(); begin if v_caller_id is null then raise exception 'Authentication required'; end if; -- Caller muss Admin in Ziel-Studio sein if not exists ( select 1 from studio_members where user_id = v_caller_id and studio_id = p_studio_id and app_role_id = 'r-admin' and active = true ) then raise exception 'Only admins of the studio can invite members'; end if; -- Profile insert into profiles (id, username, display_name) values (p_user_id, p_username, p_display_name) on conflict (id) do update set username = excluded.username, display_name = excluded.display_name; -- Membership (idempotent) insert into studio_members (studio_id, user_id, app_role_id) values (p_studio_id, p_user_id, p_app_role_id) on conflict (studio_id, user_id) do update set app_role_id = excluded.app_role_id, active = true; end; $$; grant execute on function attach_user_to_studio(uuid, uuid, text, text, text) to authenticated;