import { getSessionUser, canMutate } from "@/lib/session"; import { getTranslations } from "next-intl/server"; import { redirect } from "next/navigation"; import { OnboardingFlow } from "@/components/onboarding/onboarding-flow"; import { BackLink } from "@/components/ui/back-link"; import { listTenants } from "@/lib/k8s"; import { listActiveTenantRequestsByOrgId, getOrgBilling, getPlatformPricing } from "@/lib/db"; import { personalAccountAtCapacity } from "@/lib/personal-org"; /** * /dashboard/new — wizard for creating an additional instance for an * existing customer. Reachable from the dashboard "+ Create new instance" * link. * * Slice 3: this page is the entry point for follow-up instances. The * first-instance case is still served inline on /dashboard. Both paths * mount the same ; the API resolves the difference * server-side based on whether prior approved rows exist for the org. * * Platform admins are redirected to /dashboard — they shouldn't be * creating tenant instances under their own org. * * Slice 5: customer-side `user` role is also redirected — only owners * may create new instances. The server-side POST handler enforces the * same; this redirect is purely UX so /user-role members don't land on * a wizard that will 403 on submit. * * Bug 5: personal accounts that already hold a tenant or have one * in-flight are sent back to the dashboard with the same UX rationale. * Matching API guard lives in `/api/onboarding`. */ export default async function NewInstancePage() { const user = await getSessionUser(); if (!user) redirect("/login"); if (user.isPlatform) redirect("/dashboard"); if (!canMutate(user)) redirect("/dashboard"); if (user.isPersonal) { const [allTenants, activeRequests] = await Promise.all([ listTenants(), listActiveTenantRequestsByOrgId(user.orgId), ]); const ownTenants = allTenants.filter( (t) => t.metadata.labels?.["pieced.ch/zitadel-org-id"] === user.orgId ); if ( personalAccountAtCapacity( user.isPersonal, ownTenants.length, activeRequests.length ) ) { redirect("/dashboard"); } } const t = await getTranslations("dashboard"); const [orgBilling, pricing] = await Promise.all([ getOrgBilling(user.orgId), getPlatformPricing(), ]); const hasOrgBilling = orgBilling !== null; return (

{t("createInstance")}

{t("createInstanceDescription")}

); }