From 7fffb9435b22a5ea67cde44873dd55a4af9ca9bf Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Wed, 25 Feb 2026 00:30:07 -0800 Subject: [PATCH] Add internal provision endpoint for rSpace Registry Auth-free POST /api/internal/provision creates Space + system User + ADMIN membership with starting credits when called by the registry. Co-Authored-By: Claude Opus 4.6 --- src/app/api/internal/provision/route.ts | 51 +++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/app/api/internal/provision/route.ts diff --git a/src/app/api/internal/provision/route.ts b/src/app/api/internal/provision/route.ts new file mode 100644 index 0000000..d76adf4 --- /dev/null +++ b/src/app/api/internal/provision/route.ts @@ -0,0 +1,51 @@ +import { NextResponse } from "next/server"; +import { prisma } from "@/lib/prisma"; + +/** + * Internal provision endpoint — called by rSpace Registry when activating + * this app for a space. No auth required (only reachable from Docker network). + * + * Creates Space + a system owner SpaceMember with starting credits. + */ +export async function POST(request: Request) { + const body = await request.json(); + const space: string = body.space?.trim(); + if (!space) { + return NextResponse.json({ error: "Missing space name" }, { status: 400 }); + } + + const existing = await prisma.space.findUnique({ where: { slug: space } }); + if (existing) { + return NextResponse.json({ status: "exists", id: existing.id, slug: existing.slug }); + } + + const systemEmail = `system+${space}@rspace.online`; + const systemDid = `did:system:${space}`; + + const user = await prisma.user.upsert({ + where: { email: systemEmail }, + update: { did: systemDid }, + create: { email: systemEmail, name: `${space}-admin`, did: systemDid }, + }); + + const visibility = body.public ? "public" : "public_read"; + + const created = await prisma.space.create({ + data: { + name: space.charAt(0).toUpperCase() + space.slice(1), + slug: space, + description: body.description || `${space} governance space`, + visibility, + ownerDid: systemDid, + members: { + create: { + userId: user.id, + role: "ADMIN", + credits: 50, + }, + }, + }, + }); + + return NextResponse.json({ status: "created", id: created.id, slug: created.slug }, { status: 201 }); +}