feat(provisioning): echtes Modell-A-Provisioning via create_studio_for_user
studio-adapter ruft jetzt den neuen service_role-RPC (APP 0011): Auth-User anlegen (oder bei 422 bestehenden holen) → create_studio_for_user → Instanz-URL. MOCK-Modus bleibt für lokalen Test ohne Rapport-Stack. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -41,31 +41,38 @@ export async function provision({ account, plan }) {
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
};
|
};
|
||||||
|
|
||||||
// 1. Auth-User anlegen (GoTrue Admin-API), bereits bestätigt.
|
// 1. Auth-User anlegen (GoTrue Admin-API), bereits bestätigt. Existiert die
|
||||||
|
// E-Mail schon (422), holen wir den bestehenden User per Listen-Filter.
|
||||||
const tempPassword = randomUUID();
|
const tempPassword = randomUUID();
|
||||||
const userRes = await fetch(`${base}/auth/v1/admin/users`, {
|
const userRes = await fetch(`${base}/auth/v1/admin/users`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers,
|
headers,
|
||||||
body: JSON.stringify({ email: account.email, password: tempPassword, email_confirm: true }),
|
body: JSON.stringify({ email: account.email, password: tempPassword, email_confirm: true }),
|
||||||
});
|
});
|
||||||
if (!userRes.ok) throw new Error(`GoTrue admin/users: ${userRes.status} ${await userRes.text()}`);
|
let user;
|
||||||
const user = await userRes.json();
|
if (userRes.ok) {
|
||||||
|
user = await userRes.json();
|
||||||
|
} else if (userRes.status === 422) {
|
||||||
|
const list = await fetch(`${base}/auth/v1/admin/users?filter=${encodeURIComponent(account.email)}`, { headers });
|
||||||
|
const body = list.ok ? await list.json() : null;
|
||||||
|
user = body?.users?.find((u) => (u.email || "").toLowerCase() === account.email.toLowerCase());
|
||||||
|
if (!user) throw new Error(`Auth-User existiert, aber nicht auffindbar: ${account.email}`);
|
||||||
|
} else {
|
||||||
|
throw new Error(`GoTrue admin/users: ${userRes.status} ${await userRes.text()}`);
|
||||||
|
}
|
||||||
|
|
||||||
// 2.+3. Profil + Studio per RPC. Da create_studio_with_admin auth.uid() nutzt,
|
// 2. Profil + Studio in einem service_role-RPC (create_studio_for_user, 0011).
|
||||||
// muss der Aufruf im Kontext des neuen Users laufen — hier vereinfacht über
|
// Studio-Name = lokaler Teil der E-Mail als sinnvoller Default.
|
||||||
// einen service_role-RPC, der die Ziel-User-ID als Argument nimmt. Diese
|
const studioName = account.email.split("@")[0];
|
||||||
// server-seitige Variante (create_studio_for_user) ist im Rapport-Schema noch
|
|
||||||
// anzulegen; bis dahin schützt der MOCK-Modus den lokalen Test.
|
|
||||||
const slugForStudio = slug;
|
|
||||||
const rpcRes = await fetch(`${base}/rest/v1/rpc/create_studio_for_user`, {
|
const rpcRes = await fetch(`${base}/rest/v1/rpc/create_studio_for_user`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers,
|
headers,
|
||||||
body: JSON.stringify({ p_user_id: user.id, p_name: account.email.split("@")[0], p_slug: slugForStudio }),
|
body: JSON.stringify({ p_user_id: user.id, p_name: studioName, p_slug: slug }),
|
||||||
});
|
});
|
||||||
if (!rpcRes.ok) throw new Error(`create_studio_for_user: ${rpcRes.status} ${await rpcRes.text()}`);
|
if (!rpcRes.ok) throw new Error(`create_studio_for_user: ${rpcRes.status} ${await rpcRes.text()}`);
|
||||||
const studioId = (await rpcRes.json());
|
const studioId = await rpcRes.json();
|
||||||
|
|
||||||
return { studioId, slug: slugForStudio, instanceUrl: instanceUrl(slugForStudio) };
|
return { studioId, slug, instanceUrl: instanceUrl(slug) };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deprovision({ instance }) {
|
export async function deprovision({ instance }) {
|
||||||
|
|||||||
Reference in New Issue
Block a user