fix: use admin client in onboarding guard to prevent accidental workspace creation

Session client (getUserTeams) can return null when the session token is
expired or stale. The old guard 'if (teams && teams.total > 0) redirect'
was bypassed when teams was null, allowing users to create duplicate
workspaces.

New guard uses admin client (API key, never session-dependent):
- lists user memberships via users.listMemberships(userId)
- checks for a tenant_settings row in this app
- redirects to /dashboard if found; shows form only for genuinely new users
This commit is contained in:
egecankomur
2026-05-12 15:45:33 +03:00
parent b71edd880b
commit 95e30a74c7
+24 -4
View File
@@ -1,8 +1,10 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
import { Query } from "node-appwrite";
import { getCurrentUser } from "@/lib/appwrite/server"; import { getCurrentUser, createAdminClient } from "@/lib/appwrite/server";
import { getUserTeams, getCrossAppTeams } from "@/lib/appwrite/tenant"; import { getCrossAppTeams } from "@/lib/appwrite/tenant";
import { DATABASE_ID, TABLES } from "@/lib/appwrite/schema";
import { CreateWorkspaceForm } from "./components/create-workspace-form"; import { CreateWorkspaceForm } from "./components/create-workspace-form";
export const metadata: Metadata = { export const metadata: Metadata = {
@@ -14,8 +16,26 @@ export default async function OnboardingPage() {
const user = await getCurrentUser(); const user = await getCurrentUser();
if (!user) redirect("/sign-in"); if (!user) redirect("/sign-in");
const teams = await getUserTeams(); // Use admin client — never fails due to expired session tokens.
if (teams && teams.total > 0) redirect("/dashboard"); // If user already has a team with CRM settings, send them to dashboard.
try {
const { users, tablesDB } = createAdminClient();
const memberships = await users.listMemberships(user.$id);
if (memberships.total > 0) {
const teamIds = memberships.memberships.map((m) => m.teamId);
const settings = await tablesDB.listRows({
databaseId: DATABASE_ID,
tableId: TABLES.tenantSettings,
queries: [Query.equal("tenantId", teamIds), Query.limit(1)],
});
if (settings.rows.length > 0) redirect("/dashboard");
}
} catch {
// Admin client uses an API key (not a session), so this is extremely rare.
// If it does fail, show a 500 rather than silently letting the user create
// a duplicate workspace.
throw new Error("Onboarding guard check failed — server configuration issue.");
}
const crossAppTeams = await getCrossAppTeams(); const crossAppTeams = await getCrossAppTeams();