From 5cc17e05e76aecfc8857c32affc029caa6f4a845 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Wed, 25 Feb 2026 13:20:01 -0800 Subject: [PATCH] feat: add space subdomain routing and ownership support - Traefik wildcard HostRegexp for .r*.online subdomains - Middleware subdomain extraction and path rewriting - Provision endpoint with owner_did acknowledgement - Registry enforces space ownership via EncryptID JWT Co-Authored-By: Claude Opus 4.6 --- src/app/api/internal/provision/route.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/app/api/internal/provision/route.ts b/src/app/api/internal/provision/route.ts index 9534334..5ceb7d7 100644 --- a/src/app/api/internal/provision/route.ts +++ b/src/app/api/internal/provision/route.ts @@ -5,6 +5,9 @@ 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). * + * Payload: { space, description, admin_email, public, owner_did } + * The owner_did identifies who registered the space via the registry. + * * Creates a default Notebook scoped to the workspace slug + a system collaborator. */ export async function POST(request: Request) { @@ -13,13 +16,14 @@ export async function POST(request: Request) { if (!space) { return NextResponse.json({ error: "Missing space name" }, { status: 400 }); } + const ownerDid: string = body.owner_did || ""; // Check if a notebook already exists for this workspace const existing = await prisma.notebook.findFirst({ where: { workspaceSlug: space }, }); if (existing) { - return NextResponse.json({ status: "exists", id: existing.id, slug: existing.slug }); + return NextResponse.json({ status: "exists", id: existing.id, slug: existing.slug, owner_did: ownerDid }); } const systemDid = `did:system:${space}`; @@ -42,5 +46,5 @@ export async function POST(request: Request) { }, }); - return NextResponse.json({ status: "created", id: notebook.id, slug: notebook.slug }, { status: 201 }); + return NextResponse.json({ status: "created", id: notebook.id, slug: notebook.slug, owner_did: ownerDid }, { status: 201 }); }