diff --git a/supabase/migrations/0011_create_studio_for_user.sql b/supabase/migrations/0011_create_studio_for_user.sql new file mode 100644 index 0000000..848e8cd --- /dev/null +++ b/supabase/migrations/0011_create_studio_for_user.sql @@ -0,0 +1,65 @@ +-- ============================================================================ +-- RAPPORT — Studio für einen bestimmten User anlegen (Server-/Hosting-Pfad) +-- ============================================================================ +-- `create_studio_with_admin` nutzt auth.uid() und läuft nur im Kontext eines +-- eingeloggten Users (Frontend). RAPPORT-HOST provisioniert aber serverseitig +-- mit service_role und kennt keinen auth.uid() — es übergibt die Ziel-User-ID +-- explizit. +-- +-- `create_studio_for_user` ist die service_role-Variante: identische Wirkung +-- (Studio + Admin-Membership + Settings), aber die User-ID ist ein Parameter. +-- Bewusst NICHT an `authenticated` gegrantet — nur service_role darf das, sonst +-- könnte ein User sich selbst zum Admin beliebiger Studios machen. +-- ============================================================================ + +create or replace function create_studio_for_user( + p_user_id uuid, + p_name text, + p_slug text, + p_username text default null, + p_display_name text default null +) + returns uuid + language plpgsql + security definer +as $$ +declare + v_studio_id uuid; + v_email text; + v_username text; + v_display text; +begin + if p_user_id is null then + raise exception 'p_user_id required'; + end if; + select email into v_email from auth.users where id = p_user_id; + if v_email is null then + raise exception 'user % does not exist', p_user_id; + end if; + + -- Profil sicherstellen (profiles.username/display_name sind NOT NULL; das + -- Frontend braucht sie beim ersten Login in die Instanz). Aus E-Mail + -- abgeleitet, falls nicht explizit übergeben. + v_username := coalesce(nullif(p_username, ''), split_part(v_email, '@', 1)); + v_display := coalesce(nullif(p_display_name, ''), v_username); + insert into profiles (id, username, display_name) + values (p_user_id, v_username, v_display) + on conflict (id) do nothing; + + insert into studios (name, slug) values (p_name, p_slug) returning id into v_studio_id; + insert into studio_members (studio_id, user_id, app_role_id) + values (v_studio_id, p_user_id, 'r-admin'); + + -- Studio-Name + setup_completed in die settings übernehmen (Seed-Trigger hat + -- die Zeile mit Defaults bereits angelegt) — analog create_studio_with_admin. + update studio_settings + set name = p_name, setup_completed = true + where studio_id = v_studio_id; + + return v_studio_id; +end; +$$; + +-- Nur service_role (RAPPORT-HOST). KEIN Grant an anon/authenticated. +revoke all on function create_studio_for_user(uuid, text, text, text, text) from public; +grant execute on function create_studio_for_user(uuid, text, text, text, text) to service_role;