All the MD files via Database

This commit is contained in:
2026-04-11 21:14:09 +02:00
parent c67259ebe0
commit fdb56490dd
14 changed files with 1004 additions and 240 deletions

View File

@@ -14,6 +14,7 @@ import { z } from "zod";
const onboardingSchema = z.object({
agentName: z.string().min(1).max(50),
soulMd: z.string().max(10_000).optional(),
agentsMd: z.string().max(10_000).optional(),
packages: z.array(z.string()).optional(),
packageSecrets: z
.record(z.string(), z.record(z.string(), z.string()))
@@ -25,20 +26,20 @@ const onboardingSchema = z.object({
postalCode: z.string().optional(),
country: z.string().optional(),
}),
billingNotes: z.string().max(2000).optional(),
billingNotes: z.string().max(2_000).optional(),
});
/**
* GET /api/onboarding
* Returns the current onboarding status for the logged-in user's org.
* Used by the wizard/provisioning UI to poll state.
* Check the current onboarding state for the logged-in user's org.
*/
export async function GET() {
const user = await getSessionUser();
if (!user)
if (!user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
// Check if tenant already exists
// Check if there's already a running tenant for this org
const allTenants = await listTenants();
const myTenant = allTenants.find(
(t) => t.metadata.labels?.["pieced.ch/zitadel-org-id"] === user.orgId
@@ -46,13 +47,9 @@ export async function GET() {
if (myTenant) {
return NextResponse.json({
state: "provisioned",
tenant: {
name: myTenant.metadata.name,
phase: myTenant.status?.phase ?? "Pending",
message: myTenant.status?.message,
conditions: myTenant.status?.conditions,
},
state: "active",
tenantName: myTenant.metadata.name,
phase: myTenant.status?.phase ?? "Unknown",
});
}
@@ -63,29 +60,17 @@ export async function GET() {
return NextResponse.json({ state: "no_request" });
}
// If approved and tenant_name set, check provisioning status
if (
request.status === "provisioning" &&
request.tenantName
) {
const tenant = await getTenant(request.tenantName);
if (tenant) {
return NextResponse.json({
state: "provisioning",
request,
tenant: {
name: tenant.metadata.name,
phase: tenant.status?.phase ?? "Pending",
message: tenant.status?.message,
conditions: tenant.status?.conditions,
},
});
}
}
return NextResponse.json({
state: request.status,
request,
request: {
id: request.id,
agentName: request.agentName,
packages: request.packages,
status: request.status,
adminNotes: request.adminNotes,
tenantName: request.tenantName,
createdAt: request.createdAt,
},
});
}
@@ -101,8 +86,18 @@ export async function GET() {
*/
export async function POST(request: Request) {
const user = await getSessionUser();
if (!user)
if (!user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const body = await request.json();
const parsed = onboardingSchema.safeParse(body);
if (!parsed.success) {
return NextResponse.json(
{ error: "Invalid input", details: parsed.error.flatten() },
{ status: 400 }
);
}
// Check for existing request
const existing = await getTenantRequestByOrgId(user.orgId);
@@ -123,23 +118,20 @@ export async function POST(request: Request) {
const myTenant = allTenants.find(
(t) => t.metadata.labels?.["pieced.ch/zitadel-org-id"] === user.orgId
);
if (myTenant) {
return NextResponse.json(
{ error: "Tenant already exists." },
{
error: "You already have a tenant provisioned.",
tenantName: myTenant.metadata.name,
},
{ status: 409 }
);
}
const body = await request.json();
const parsed = onboardingSchema.safeParse(body);
if (!parsed.success) {
return NextResponse.json(
{ error: "Validation failed", details: parsed.error.flatten() },
{ status: 400 }
);
}
const input: OnboardingInput & { packageSecrets?: Record<string, Record<string, string>> } = parsed.data;
const input: OnboardingInput & {
packageSecrets?: Record<string, Record<string, string>>;
} = parsed.data;
// Encrypt package secrets if provided
let encryptedSecrets: Buffer | undefined;
@@ -159,10 +151,11 @@ export async function POST(request: Request) {
zitadelOrgId: user.orgId,
zitadelUserId: user.id,
companyName: user.orgName,
contactName: user.name || user.email,
contactName: user.name,
contactEmail: user.email,
agentName: input.agentName,
soulMd: input.soulMd,
agentsMd: input.agentsMd,
packages: input.packages ?? [],
billingAddress: input.billingAddress,
billingNotes: input.billingNotes,
@@ -170,14 +163,18 @@ export async function POST(request: Request) {
});
// Notify admin about the new request
await sendAdminNotificationEmail(
user.orgName,
user.name || user.email,
user.email
);
try {
await sendAdminNotificationEmail(
tenantRequest.contactEmail,
tenantRequest.contactName,
tenantRequest.companyName
);
} catch (e) {
console.error("Failed to send admin notification:", e);
}
return NextResponse.json(
{ message: "Onboarding request submitted.", request: tenantRequest },
{ message: "Request submitted.", request: tenantRequest },
{ status: 201 }
);
}