Invite partner organizations at /admin/experience/partners or with the SQL cookbook below.
App UI (recommended when configured)
Use the admin Partners page when your deployment has SUPABASE_SERVICE_ROLE_KEY set in server env (see Getting started).
- Open Partners in the admin nav.
- Enter name, optional website, and owner email or owner user UUID.
- Submit — if the owner already has a BoardingPass account, they receive partner role access.
The app uses the service-role client to look up users (with paginated email search) and assign roles without manual trigger workarounds.
Partners then use the partner portal and Partner help to create challenges.
SQL cookbook (Supabase SQL Editor)
Use these blocks in the Supabase SQL Editor when bootstrapping the first admin, recovering access, or working without the service-role key.
Migration 20260612120000_profiles_role_protection.sql installs trigger profiles_prevent_role_self_update, which blocks profiles.role changes unless the JWT role is service_role. The SQL Editor does not run as service role, so you must disable the trigger, run the update, then re-enable it.
1. Find a user by email
Replace the email before running:
select
u.id as user_id,
u.email,
p.role as profile_role,
p.full_name
from auth.users u
left join public.profiles p on p.id = u.id
where lower(u.email) = lower('owner@example.com');
Copy the user_id UUID for the steps below.
2. Bootstrap the first admin
Replace YOUR-USER-UUID with the id from step 1:
alter table public.profiles disable trigger profiles_prevent_role_self_update;
update public.profiles
set role = 'admin',
updated_at = now()
where id = 'YOUR-USER-UUID';
alter table public.profiles enable trigger profiles_prevent_role_self_update;
Sign out and back in, then open /admin/experience. You should see the Admin link in the main navbar.
3. Create a partner organization
insert into public.partner_orgs (name, website, slug, description)
values (
'Acme Corp',
'https://acme.example',
'acme-corp',
'Optional public about text for /experience/partners/acme-corp'
)
returning id, name, slug;
Copy the returned id as ORG-UUID. Slug must be unique (lowercase letters, numbers, hyphens).
4. Add an owner and grant partner role
Replace ORG-UUID and USER-UUID:
insert into public.partner_members (org_id, user_id, role)
values ('ORG-UUID', 'USER-UUID', 'owner')
on conflict (org_id, user_id) do update
set role = excluded.role;
alter table public.profiles disable trigger profiles_prevent_role_self_update;
update public.profiles
set role = 'partner',
updated_at = now()
where id = 'USER-UUID';
alter table public.profiles enable trigger profiles_prevent_role_self_update;
5. Add another org member
Additional teammates need a partner_members row. Give them partner profile role if they should use the partner portal:
insert into public.partner_members (org_id, user_id, role)
values ('ORG-UUID', 'USER-UUID', 'member')
on conflict (org_id, user_id) do nothing;
alter table public.profiles disable trigger profiles_prevent_role_self_update;
update public.profiles
set role = 'partner',
updated_at = now()
where id = 'USER-UUID';
alter table public.profiles enable trigger profiles_prevent_role_self_update;
6. Verify org membership
select
o.id as org_id,
o.name as org_name,
o.slug,
u.id as user_id,
u.email,
pm.role as member_role,
p.role as profile_role
from public.partner_orgs o
join public.partner_members pm on pm.org_id = o.id
join auth.users u on u.id = pm.user_id
left join public.profiles p on p.id = u.id
order by o.name, pm.role, u.email;
When to use app UI vs SQL
| Situation | Use |
|---|---|
| Production partner onboarding, service key configured | Admin Partners UI |
| First admin before any admin exists | SQL cookbook step 2 |
Local dev without SUPABASE_SERVICE_ROLE_KEY | SQL cookbook |
| Bulk fixes, recovery, or scripting | SQL cookbook |
| Assign role with API/service role only | admin_set_user_role() via service-role client (not SQL Editor) |
Operational notes
- Keep the partner roster aligned with real collaborating organizations.
- Rejected gallery submissions should include clear notes so students can improve and resubmit.
- Coordinate with partners before approving challenges that go live to all students.
See Partner help → Getting started for the partner-side workflow.