"use server" import { getCloudflareContext } from "@opennextjs/cloudflare" import { getDb } from "@/db" import { organizations, organizationMembers, type Organization, type NewOrganization } from "@/db/schema" import { getCurrentUser } from "@/lib/auth" import { requirePermission } from "@/lib/permissions" import { eq, and } from "drizzle-orm" import { revalidatePath } from "next/cache" import { cookies } from "next/headers" import { isDemoUser } from "@/lib/demo" export async function getOrganizations(): Promise { try { const currentUser = await getCurrentUser() if (!currentUser) return [] requirePermission(currentUser, "organization", "read") const { env } = await getCloudflareContext() if (!env?.DB) return [] const db = getDb(env.DB) // filter to orgs the user is a member of const userOrgs = await db .select({ id: organizations.id, name: organizations.name, slug: organizations.slug, type: organizations.type, logoUrl: organizations.logoUrl, isActive: organizations.isActive, createdAt: organizations.createdAt, updatedAt: organizations.updatedAt, }) .from(organizations) .innerJoin(organizationMembers, eq(organizations.id, organizationMembers.organizationId)) .where(and(eq(organizations.isActive, true), eq(organizationMembers.userId, currentUser.id))) return userOrgs } catch (error) { console.error("Error fetching organizations:", error) return [] } } export async function createOrganization( name: string, slug: string, type: "internal" | "client" | "personal" | "demo" ): Promise<{ success: boolean; error?: string; data?: Organization }> { try { const currentUser = await getCurrentUser() if (!currentUser) { return { success: false, error: "Unauthorized" } } if (isDemoUser(currentUser.id)) { return { success: false, error: "DEMO_READ_ONLY" } } requirePermission(currentUser, "organization", "create") const { env } = await getCloudflareContext() if (!env?.DB) { return { success: false, error: "Database not available" } } const db = getDb(env.DB) const now = new Date().toISOString() // check if slug already exists const existing = await db .select() .from(organizations) .where(eq(organizations.slug, slug)) .get() if (existing) { return { success: false, error: "Organization slug already exists" } } const newOrg: NewOrganization = { id: crypto.randomUUID(), name, slug, type, logoUrl: null, isActive: true, createdAt: now, updatedAt: now, } await db.insert(organizations).values(newOrg).run() revalidatePath("/dashboard/people") return { success: true, data: newOrg as Organization } } catch (error) { console.error("Error creating organization:", error) return { success: false, error: error instanceof Error ? error.message : "Unknown error", } } } export async function getUserOrganizations(): Promise< ReadonlyArray<{ readonly id: string readonly name: string readonly slug: string readonly type: string readonly role: string }> > { try { const currentUser = await getCurrentUser() if (!currentUser) return [] const { env } = await getCloudflareContext() if (!env?.DB) return [] const db = getDb(env.DB) const results = await db .select({ id: organizations.id, name: organizations.name, slug: organizations.slug, type: organizations.type, role: organizationMembers.role, }) .from(organizationMembers) .innerJoin( organizations, eq(organizations.id, organizationMembers.organizationId) ) .where(eq(organizationMembers.userId, currentUser.id)) return results } catch (error) { console.error("Error fetching user organizations:", error) return [] } } export async function switchOrganization( orgId: string ): Promise<{ success: boolean; error?: string }> { try { const currentUser = await getCurrentUser() if (!currentUser) { return { success: false, error: "Not authenticated" } } const { env } = await getCloudflareContext() if (!env?.DB) { return { success: false, error: "Database not available" } } const db = getDb(env.DB) // verify user is member of target org const membership = await db .select() .from(organizationMembers) .where( and( eq(organizationMembers.organizationId, orgId), eq(organizationMembers.userId, currentUser.id) ) ) .get() if (!membership) { return { success: false, error: "Not a member of this organization" } } // set compass-active-org cookie const cookieStore = await cookies() cookieStore.set("compass-active-org", orgId, { httpOnly: true, secure: process.env.NODE_ENV === "production", sameSite: "lax", path: "/", maxAge: 60 * 60 * 24 * 365, // 1 year }) revalidatePath("/dashboard") return { success: true } } catch (error) { console.error("Error switching organization:", error) return { success: false, error: error instanceof Error ? error.message : "Unknown error", } } }