From 2e3d331995e3805dc845f967d4a3b3ebaeb38ad5 Mon Sep 17 00:00:00 2001
From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com>
Date: Mon, 4 Aug 2025 15:39:38 +0100
Subject: [PATCH 1/5] feat: Implement OTP code, replacing magic auth

---
 apps/web/app/(org)/login/form.tsx             |    6 +-
 apps/web/app/(org)/verify-otp/actions.ts      |   22 +
 apps/web/app/(org)/verify-otp/form.tsx        |  192 ++
 apps/web/app/(org)/verify-otp/page.tsx        |   32 +
 packages/database/auth/auth-options.tsx       |   59 +-
 packages/database/auth/otp.ts                 |  122 ++
 packages/database/emails/otp-email.tsx        |   64 +
 .../migrations/meta/0007_snapshot.json        | 1883 +++++++++++++++++
 .../database/migrations/meta/_journal.json    |    7 +
 packages/database/schema.ts                   |   18 +
 10 files changed, 2395 insertions(+), 10 deletions(-)
 create mode 100644 apps/web/app/(org)/verify-otp/actions.ts
 create mode 100644 apps/web/app/(org)/verify-otp/form.tsx
 create mode 100644 apps/web/app/(org)/verify-otp/page.tsx
 create mode 100644 packages/database/auth/otp.ts
 create mode 100644 packages/database/emails/otp-email.tsx
 create mode 100644 packages/database/migrations/meta/0007_snapshot.json

diff --git a/apps/web/app/(org)/login/form.tsx b/apps/web/app/(org)/login/form.tsx
index 6fb6b2f8e8..1b39b94346 100644
--- a/apps/web/app/(org)/login/form.tsx
+++ b/apps/web/app/(org)/login/form.tsx
@@ -235,7 +235,11 @@ export function LoginForm() {
                             trackEvent("auth_email_sent", {
                               email_domain: email.split("@")[1],
                             });
-                            toast.success("Email sent - check your inbox!");
+                            const params = new URLSearchParams({
+                              email,
+                              ...(next && { next }),
+                            });
+                            window.location.href = `/verify-otp?${params.toString()}`;
                           } else {
                             toast.error("Error sending email - try again?");
                           }
diff --git a/apps/web/app/(org)/verify-otp/actions.ts b/apps/web/app/(org)/verify-otp/actions.ts
new file mode 100644
index 0000000000..fef7266fb8
--- /dev/null
+++ b/apps/web/app/(org)/verify-otp/actions.ts
@@ -0,0 +1,22 @@
+"use server";
+
+import { validateOTP } from "@cap/database/auth/otp";
+
+export async function verifyOTPAction(email: string, code: string) {
+  try {
+    if (!email || !code) {
+      return { success: false, error: "Email and code are required" };
+    }
+
+    const result = await validateOTP(email, code);
+
+    if (result.valid) {
+      return { success: true };
+    } else {
+      return { success: false, error: result.error || "Invalid code" };
+    }
+  } catch (error) {
+    console.error("OTP verification error:", error);
+    return { success: false, error: "An error occurred during verification" };
+  }
+}
\ No newline at end of file
diff --git a/apps/web/app/(org)/verify-otp/form.tsx b/apps/web/app/(org)/verify-otp/form.tsx
new file mode 100644
index 0000000000..02404116ad
--- /dev/null
+++ b/apps/web/app/(org)/verify-otp/form.tsx
@@ -0,0 +1,192 @@
+"use client";
+
+import { useState, useRef, useEffect } from "react";
+import { Button, LogoBadge } from "@cap/ui";
+import { motion } from "framer-motion";
+import { signIn } from "next-auth/react";
+import Link from "next/link";
+import { toast } from "sonner";
+import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { verifyOTPAction } from "./actions";
+
+export function VerifyOTPForm({ email, next }: { email: string; next?: string }) {
+  const [code, setCode] = useState(["", "", "", "", "", ""]);
+  const [loading, setLoading] = useState(false);
+  const [resending, setResending] = useState(false);
+  const inputRefs = useRef<(HTMLInputElement | null)[]>([]);
+
+  useEffect(() => {
+    inputRefs.current[0]?.focus();
+  }, []);
+
+  const handleChange = (index: number, value: string) => {
+    if (value.length > 1) {
+      const pastedCode = value.slice(0, 6).split("");
+      const newCode = [...code];
+      pastedCode.forEach((digit, i) => {
+        if (index + i < 6) {
+          newCode[index + i] = digit;
+        }
+      });
+      setCode(newCode);
+      
+      const nextEmptyIndex = newCode.findIndex((digit) => digit === "");
+      if (nextEmptyIndex !== -1) {
+        inputRefs.current[nextEmptyIndex]?.focus();
+      } else {
+        inputRefs.current[5]?.focus();
+      }
+      return;
+    }
+
+    const newCode = [...code];
+    newCode[index] = value;
+    setCode(newCode);
+
+    if (value && index < 5) {
+      inputRefs.current[index + 1]?.focus();
+    }
+  };
+
+  const handleKeyDown = (index: number, e: React.KeyboardEvent<HTMLInputElement>) => {
+    if (e.key === "Backspace" && !code[index] && index > 0) {
+      inputRefs.current[index - 1]?.focus();
+    }
+  };
+
+  const handleVerify = async () => {
+    const otpCode = code.join("");
+    if (otpCode.length !== 6) {
+      toast.error("Please enter a complete 6-digit code");
+      return;
+    }
+
+    setLoading(true);
+    try {
+      const result = await verifyOTPAction(email, otpCode);
+
+      if (result.success) {
+        await signIn("otp", {
+          email,
+          redirect: true,
+          callbackUrl: next || "/dashboard",
+        });
+      } else {
+        toast.error(result.error || "Invalid code. Please try again.");
+        setCode(["", "", "", "", "", ""]);
+        inputRefs.current[0]?.focus();
+      }
+    } catch (error) {
+      toast.error("An error occurred. Please try again.");
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  const handleResend = async () => {
+    setResending(true);
+    try {
+      await signIn("email", {
+        email,
+        redirect: false,
+      });
+      toast.success("A new code has been sent to your email!");
+      setCode(["", "", "", "", "", ""]);
+      inputRefs.current[0]?.focus();
+    } catch (error) {
+      toast.error("Failed to resend code. Please try again.");
+    } finally {
+      setResending(false);
+    }
+  };
+
+  return (
+    <motion.div
+      initial={{ opacity: 0, y: 20 }}
+      animate={{ opacity: 1, y: 0 }}
+      className="relative w-[calc(100%-5%)] p-[28px] max-w-[432px] bg-gray-3 border border-gray-5 rounded-2xl"
+    >
+      <Link
+        href="/login"
+        className="absolute top-5 left-5 z-20 flex gap-2 items-center py-1.5 px-3 text-gray-12 bg-transparent border border-gray-4 rounded-full hover:bg-gray-1 transition-colors duration-300"
+      >
+        <FontAwesomeIcon className="w-2" icon={faArrowLeft} />
+        <p className="text-xs">Back</p>
+      </Link>
+
+      <Link className="flex mx-auto size-fit" href="/">
+        <LogoBadge className="w-[72px] h-[72px]" />
+      </Link>
+
+      <div className="flex flex-col justify-center items-center my-7 text-center">
+        <h1 className="text-2xl font-semibold text-gray-12">Enter verification code</h1>
+        <p className="text-[16px] text-gray-10 mt-2">
+          We sent a 6-digit code to {email}
+        </p>
+      </div>
+
+      <div className="flex justify-center gap-2 mb-6">
+        {code.map((digit, index) => (
+          <input
+            key={index}
+            ref={(el) => (inputRefs.current[index] = el)}
+            type="text"
+            inputMode="numeric"
+            pattern="[0-9]*"
+            maxLength={1}
+            value={digit}
+            onChange={(e) => handleChange(index, e.target.value.replace(/\D/g, ""))}
+            onKeyDown={(e) => handleKeyDown(index, e)}
+            onPaste={(e) => {
+              e.preventDefault();
+              const pastedData = e.clipboardData.getData("text").replace(/\D/g, "");
+              handleChange(0, pastedData);
+            }}
+            className="w-12 h-14 text-center text-xl font-semibold bg-gray-1 border border-gray-5 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
+            disabled={loading}
+          />
+        ))}
+      </div>
+
+      <Button
+        variant="primary"
+        className="w-full"
+        onClick={handleVerify}
+        disabled={loading || code.some((digit) => !digit)}
+      >
+        {loading ? "Verifying..." : "Verify Code"}
+      </Button>
+
+      <div className="mt-4 text-center">
+        <button
+          onClick={handleResend}
+          disabled={resending}
+          className="text-sm text-gray-10 hover:text-gray-12 underline transition-colors"
+        >
+          {resending ? "Sending..." : "Didn't receive the code? Resend"}
+        </button>
+      </div>
+
+      <p className="mt-6 text-xs text-center text-gray-9">
+        By verifying your email, you acknowledge that you have both read and agree to Cap's{" "}
+        <Link
+          href="/terms"
+          target="_blank"
+          className="text-xs font-semibold text-gray-12 hover:text-blue-300"
+        >
+          Terms of Service
+        </Link>{" "}
+        and{" "}
+        <Link
+          href="/privacy"
+          target="_blank"
+          className="text-xs font-semibold text-gray-12 hover:text-blue-300"
+        >
+          Privacy Policy
+        </Link>
+        .
+      </p>
+    </motion.div>
+  );
+}
\ No newline at end of file
diff --git a/apps/web/app/(org)/verify-otp/page.tsx b/apps/web/app/(org)/verify-otp/page.tsx
new file mode 100644
index 0000000000..31fe339b11
--- /dev/null
+++ b/apps/web/app/(org)/verify-otp/page.tsx
@@ -0,0 +1,32 @@
+import { Suspense } from "react";
+import { VerifyOTPForm } from "./form";
+import { redirect } from "next/navigation";
+import { getSession } from "@cap/database/auth/session";
+
+export const metadata = {
+  title: "Verify Code | Cap",
+};
+
+export default async function VerifyOTPPage({
+  searchParams,
+}: {
+  searchParams: { email?: string; next?: string };
+}) {
+  const session = await getSession();
+
+  if (session?.user) {
+    redirect(searchParams.next || "/dashboard");
+  }
+
+  if (!searchParams.email) {
+    redirect("/login");
+  }
+
+  return (
+    <div className="flex h-screen w-full items-center justify-center">
+      <Suspense fallback={<div>Loading...</div>}>
+        <VerifyOTPForm email={searchParams.email} next={searchParams.next} />
+      </Suspense>
+    </div>
+  );
+}
\ No newline at end of file
diff --git a/packages/database/auth/auth-options.tsx b/packages/database/auth/auth-options.tsx
index f9ddabb1b8..02c72a48d8 100644
--- a/packages/database/auth/auth-options.tsx
+++ b/packages/database/auth/auth-options.tsx
@@ -4,17 +4,20 @@ import type { NextAuthOptions } from "next-auth";
 import EmailProvider from "next-auth/providers/email";
 import GoogleProvider from "next-auth/providers/google";
 import WorkOSProvider from "next-auth/providers/workos";
+import CredentialsProvider from "next-auth/providers/credentials";
 import { serverEnv } from "@cap/env";
 import type { Adapter } from "next-auth/adapters";
 import type { Provider } from "next-auth/providers/index";
 import { cookies } from "next/headers";
 import { dub } from "../dub";
+import crypto from "crypto";
 
 import { db } from "../";
 import { users, organizations, organizationMembers } from "../schema";
 import { nanoId } from "../helpers";
 import { sendEmail } from "../emails/config";
 import { LoginLink } from "../emails/login-link";
+import { generateOTP } from "./otp";
 
 export const config = {
   maxDuration: 120,
@@ -43,6 +46,33 @@ export const authOptions = (): NextAuthOptions => {
     get providers() {
       if (_providers) return _providers;
       _providers = [
+        CredentialsProvider({
+          id: "otp",
+          name: "OTP",
+          credentials: {
+            email: { label: "Email", type: "email" },
+          },
+          async authorize(credentials) {
+            if (!credentials?.email) return null;
+
+            const [user] = await db()
+              .select()
+              .from(users)
+              .where(eq(users.email, credentials.email))
+              .limit(1);
+
+            if (user) {
+              return {
+                id: user.id,
+                email: user.email,
+                name: user.name,
+                image: user.image,
+              };
+            }
+
+            return null;
+          },
+        }),
         GoogleProvider({
           clientId: serverEnv().GOOGLE_CLIENT_ID!,
           clientSecret: serverEnv().GOOGLE_CLIENT_SECRET!,
@@ -71,17 +101,32 @@ export const authOptions = (): NextAuthOptions => {
           },
         }),
         EmailProvider({
-          async sendVerificationRequest({ identifier, url }) {
+          async generateVerificationToken() {
+            return crypto.randomUUID();
+          },
+          async sendVerificationRequest({ identifier, url, token }) {
             console.log("sendVerificationRequest");
+            
+            const otpCode = await generateOTP(identifier);
+            
             if (!serverEnv().RESEND_API_KEY) {
-              console.log(`Login link: ${url}`);
+              console.log("\n");
+              console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
+              console.log("🔐 VERIFICATION CODE (Development Mode)");
+              console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
+              console.log(`📧 Email: ${identifier}`);
+              console.log(`🔢 Code: ${otpCode}`);
+              console.log(`⏱️  Expires in: 10 minutes`);
+              console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
+              console.log("\n");
             } else {
-              console.log({ identifier, url });
-              const email = LoginLink({ url, email: identifier });
+              console.log({ identifier, otpCode });
+              const { OTPEmail } = await import("../emails/otp-email");
+              const email = OTPEmail({ code: otpCode, email: identifier });
               console.log({ email });
               await sendEmail({
                 email: identifier,
-                subject: `Your Cap Login Link`,
+                subject: `Your Cap Verification Code`,
                 react: email,
               });
             }
@@ -104,7 +149,6 @@ export const authOptions = (): NextAuthOptions => {
     },
     events: {
       async signIn({ user, account, isNewUser }) {
-        // Check if user needs organization setup (new user or guest checkout user)
         const [dbUser] = await db()
           .select()
           .from(users)
@@ -131,10 +175,7 @@ export const authOptions = (): NextAuthOptions => {
 
               console.log("Dub tracking successful:", trackResult);
 
-              // Properly delete the dub_id cookie
               cookies().delete("dub_id");
-
-              // Also delete dub_partner_data if it exists
               if (dubPartnerData) {
                 cookies().delete("dub_partner_data");
               }
diff --git a/packages/database/auth/otp.ts b/packages/database/auth/otp.ts
new file mode 100644
index 0000000000..604e3e0a25
--- /dev/null
+++ b/packages/database/auth/otp.ts
@@ -0,0 +1,122 @@
+import { db } from "../";
+import { otpCodes } from "../schema";
+import { eq, and, gt, gte, sql } from "drizzle-orm";
+import { nanoId } from "../helpers";
+import crypto from "crypto";
+
+const OTP_EXPIRY_MINUTES = 10;
+const MAX_ATTEMPTS = 3;
+const MIN_TIME_BETWEEN_REQUESTS_MS = 30000;
+
+export async function generateOTP(identifier: string): Promise<string> {
+  const recentOTP = await db()
+    .select()
+    .from(otpCodes)
+    .where(
+      and(
+        eq(otpCodes.identifier, identifier),
+        gte(otpCodes.createdAt, new Date(Date.now() - MIN_TIME_BETWEEN_REQUESTS_MS))
+      )
+    )
+    .limit(1);
+
+  if (recentOTP.length > 0) {
+    throw new Error("Please wait before requesting a new code");
+  }
+
+  const code = crypto.randomInt(100000, 1000000).toString();
+  
+  const expires = new Date();
+  expires.setMinutes(expires.getMinutes() + OTP_EXPIRY_MINUTES);
+
+  await db().delete(otpCodes).where(eq(otpCodes.identifier, identifier));
+
+  await db().insert(otpCodes).values({
+    id: nanoId(),
+    identifier,
+    code,
+    expires,
+    attempts: 0,
+  });
+
+  return code;
+}
+
+export async function validateOTP(
+  identifier: string,
+  code: string
+): Promise<{ valid: boolean; error?: string }> {
+  if (!code.match(/^\d{6}$/)) {
+    return { valid: false, error: "Invalid code format" };
+  }
+  const otpRecord = await db()
+    .select()
+    .from(otpCodes)
+    .where(
+      and(
+        eq(otpCodes.identifier, identifier),
+        eq(otpCodes.code, code),
+        gt(otpCodes.expires, new Date())
+      )
+    )
+    .limit(1);
+
+  if (otpRecord.length === 0) {
+    const expiredRecord = await db()
+      .select()
+      .from(otpCodes)
+      .where(
+        and(
+          eq(otpCodes.identifier, identifier),
+          eq(otpCodes.code, code)
+        )
+      )
+      .limit(1);
+
+    if (expiredRecord.length > 0) {
+      return { valid: false, error: "Code has expired" };
+    }
+
+    const activeRecord = await db()
+      .select()
+      .from(otpCodes)
+      .where(
+        and(
+          eq(otpCodes.identifier, identifier),
+          gt(otpCodes.expires, new Date())
+        )
+      )
+      .limit(1);
+
+    if (activeRecord.length > 0) {
+      const record = activeRecord[0];
+      
+      if (record.attempts >= MAX_ATTEMPTS) {
+        return { valid: false, error: "Too many attempts. Please request a new code." };
+      }
+
+      await db()
+        .update(otpCodes)
+        .set({ attempts: record.attempts + 1 })
+        .where(eq(otpCodes.id, record.id));
+
+      return { valid: false, error: "Invalid code" };
+    }
+
+    return { valid: false, error: "No active code found. Please request a new one." };
+  }
+
+  const record = otpRecord[0];
+
+  if (record.attempts >= MAX_ATTEMPTS) {
+    return { valid: false, error: "Too many attempts. Please request a new code." };
+  }
+
+  await db().delete(otpCodes).where(eq(otpCodes.id, record.id));
+
+  return { valid: true };
+}
+
+export async function cleanupExpiredOTPs(): Promise<void> {
+  await db().delete(otpCodes).where(gt(new Date(), otpCodes.expires));
+}
\ No newline at end of file
diff --git a/packages/database/emails/otp-email.tsx b/packages/database/emails/otp-email.tsx
new file mode 100644
index 0000000000..a548c12239
--- /dev/null
+++ b/packages/database/emails/otp-email.tsx
@@ -0,0 +1,64 @@
+import { CAP_LOGO_URL } from "@cap/utils";
+import {
+  Body,
+  Container,
+  Head,
+  Heading,
+  Html,
+  Img,
+  Preview,
+  Section,
+  Tailwind,
+  Text,
+} from "@react-email/components";
+import Footer from "./components/Footer";
+
+export function OTPEmail({
+  email = "",
+  code = "",
+}: {
+  email: string;
+  code: string;
+}) {
+  return (
+    <Html>
+      <Head />
+      <Preview>Your Cap Verification Code: {code}</Preview>
+      <Tailwind>
+        <Body className="mx-auto my-auto bg-gray-1 font-sans">
+          <Container className="mx-auto my-10 max-w-[500px] rounded border border-solid border-gray-200 px-10 py-5">
+            <Section className="mt-8">
+              <Img
+                src={CAP_LOGO_URL}
+                width="40"
+                height="40"
+                alt="Cap"
+                className="mx-auto my-0"
+              />
+            </Section>
+            <Heading className="mx-0 my-7 p-0 text-center text-xl font-semibold text-black">
+              Your Verification Code
+            </Heading>
+            <Text className="text-sm leading-6 text-black">
+              Welcome to Cap!
+            </Text>
+            <Text className="text-sm leading-6 text-black">
+              Please use the following verification code to sign in to your account:
+            </Text>
+            <Section className="my-8 text-center">
+              <div className="rounded-lg bg-gray-100 px-8 py-6">
+                <Text className="m-0 text-3xl font-bold tracking-wider text-black">
+                  {code}
+                </Text>
+              </div>
+            </Section>
+            <Text className="text-sm leading-6 text-black">
+              This code will expire in 10 minutes. If you didn't request this code, you can safely ignore this email.
+            </Text>
+            <Footer email={email} />
+          </Container>
+        </Body>
+      </Tailwind>
+    </Html>
+  );
+}
\ No newline at end of file
diff --git a/packages/database/migrations/meta/0007_snapshot.json b/packages/database/migrations/meta/0007_snapshot.json
new file mode 100644
index 0000000000..c4fefccaa8
--- /dev/null
+++ b/packages/database/migrations/meta/0007_snapshot.json
@@ -0,0 +1,1883 @@
+{
+  "version": "5",
+  "dialect": "mysql",
+  "id": "308bd25e-8d1d-4bc6-ba35-880bf4d18a6d",
+  "prevId": "140a5aa9-5b37-4435-baeb-5fd016ef5c6e",
+  "tables": {
+    "accounts": {
+      "name": "accounts",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "userId": {
+          "name": "userId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "type": {
+          "name": "type",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "provider": {
+          "name": "provider",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "providerAccountId": {
+          "name": "providerAccountId",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "access_token": {
+          "name": "access_token",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "expires_in": {
+          "name": "expires_in",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "id_token": {
+          "name": "id_token",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "refresh_token": {
+          "name": "refresh_token",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "refresh_token_expires_in": {
+          "name": "refresh_token_expires_in",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "scope": {
+          "name": "scope",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "token_type": {
+          "name": "token_type",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "createdAt": {
+          "name": "createdAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "updatedAt": {
+          "name": "updatedAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "onUpdate": true,
+          "default": "(now())"
+        },
+        "tempColumn": {
+          "name": "tempColumn",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "user_id_idx": {
+          "name": "user_id_idx",
+          "columns": [
+            "userId"
+          ],
+          "isUnique": false
+        },
+        "provider_account_id_idx": {
+          "name": "provider_account_id_idx",
+          "columns": [
+            "providerAccountId"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "accounts_id": {
+          "name": "accounts_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "accounts_id_unique": {
+          "name": "accounts_id_unique",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    },
+    "auth_api_keys": {
+      "name": "auth_api_keys",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(36)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "userId": {
+          "name": "userId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "createdAt": {
+          "name": "createdAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "auth_api_keys_id": {
+          "name": "auth_api_keys_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "auth_api_keys_id_unique": {
+          "name": "auth_api_keys_id_unique",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    },
+    "comments": {
+      "name": "comments",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "type": {
+          "name": "type",
+          "type": "varchar(6)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "content": {
+          "name": "content",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "timestamp": {
+          "name": "timestamp",
+          "type": "float",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "authorId": {
+          "name": "authorId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "videoId": {
+          "name": "videoId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "createdAt": {
+          "name": "createdAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "updatedAt": {
+          "name": "updatedAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "onUpdate": true,
+          "default": "(now())"
+        },
+        "parentCommentId": {
+          "name": "parentCommentId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "video_id_idx": {
+          "name": "video_id_idx",
+          "columns": [
+            "videoId"
+          ],
+          "isUnique": false
+        },
+        "author_id_idx": {
+          "name": "author_id_idx",
+          "columns": [
+            "authorId"
+          ],
+          "isUnique": false
+        },
+        "parent_comment_id_idx": {
+          "name": "parent_comment_id_idx",
+          "columns": [
+            "parentCommentId"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "comments_id": {
+          "name": "comments_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "comments_id_unique": {
+          "name": "comments_id_unique",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    },
+    "folders": {
+      "name": "folders",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "color": {
+          "name": "color",
+          "type": "varchar(16)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "'normal'"
+        },
+        "organizationId": {
+          "name": "organizationId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "createdById": {
+          "name": "createdById",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "parentId": {
+          "name": "parentId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "spaceId": {
+          "name": "spaceId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "createdAt": {
+          "name": "createdAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "updatedAt": {
+          "name": "updatedAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "onUpdate": true,
+          "default": "(now())"
+        }
+      },
+      "indexes": {
+        "organization_id_idx": {
+          "name": "organization_id_idx",
+          "columns": [
+            "organizationId"
+          ],
+          "isUnique": false
+        },
+        "created_by_id_idx": {
+          "name": "created_by_id_idx",
+          "columns": [
+            "createdById"
+          ],
+          "isUnique": false
+        },
+        "parent_id_idx": {
+          "name": "parent_id_idx",
+          "columns": [
+            "parentId"
+          ],
+          "isUnique": false
+        },
+        "space_id_idx": {
+          "name": "space_id_idx",
+          "columns": [
+            "spaceId"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "folders_id": {
+          "name": "folders_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "folders_id_unique": {
+          "name": "folders_id_unique",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    },
+    "organization_invites": {
+      "name": "organization_invites",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "organizationId": {
+          "name": "organizationId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "invitedEmail": {
+          "name": "invitedEmail",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "invitedByUserId": {
+          "name": "invitedByUserId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "role": {
+          "name": "role",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "status": {
+          "name": "status",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "'pending'"
+        },
+        "createdAt": {
+          "name": "createdAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "updatedAt": {
+          "name": "updatedAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "onUpdate": true,
+          "default": "(now())"
+        },
+        "expiresAt": {
+          "name": "expiresAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "organization_id_idx": {
+          "name": "organization_id_idx",
+          "columns": [
+            "organizationId"
+          ],
+          "isUnique": false
+        },
+        "invited_email_idx": {
+          "name": "invited_email_idx",
+          "columns": [
+            "invitedEmail"
+          ],
+          "isUnique": false
+        },
+        "invited_by_user_id_idx": {
+          "name": "invited_by_user_id_idx",
+          "columns": [
+            "invitedByUserId"
+          ],
+          "isUnique": false
+        },
+        "status_idx": {
+          "name": "status_idx",
+          "columns": [
+            "status"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "organization_invites_id": {
+          "name": "organization_invites_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "organization_invites_id_unique": {
+          "name": "organization_invites_id_unique",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    },
+    "organization_members": {
+      "name": "organization_members",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "userId": {
+          "name": "userId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "organizationId": {
+          "name": "organizationId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "role": {
+          "name": "role",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "createdAt": {
+          "name": "createdAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "updatedAt": {
+          "name": "updatedAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "onUpdate": true,
+          "default": "(now())"
+        }
+      },
+      "indexes": {
+        "user_id_idx": {
+          "name": "user_id_idx",
+          "columns": [
+            "userId"
+          ],
+          "isUnique": false
+        },
+        "organization_id_idx": {
+          "name": "organization_id_idx",
+          "columns": [
+            "organizationId"
+          ],
+          "isUnique": false
+        },
+        "user_id_organization_id_idx": {
+          "name": "user_id_organization_id_idx",
+          "columns": [
+            "userId",
+            "organizationId"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "organization_members_id": {
+          "name": "organization_members_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "organization_members_id_unique": {
+          "name": "organization_members_id_unique",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    },
+    "organizations": {
+      "name": "organizations",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "ownerId": {
+          "name": "ownerId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "metadata": {
+          "name": "metadata",
+          "type": "json",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "allowedEmailDomain": {
+          "name": "allowedEmailDomain",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "customDomain": {
+          "name": "customDomain",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "domainVerified": {
+          "name": "domainVerified",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "iconUrl": {
+          "name": "iconUrl",
+          "type": "varchar(1024)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "createdAt": {
+          "name": "createdAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "updatedAt": {
+          "name": "updatedAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "onUpdate": true,
+          "default": "(now())"
+        },
+        "workosOrganizationId": {
+          "name": "workosOrganizationId",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "workosConnectionId": {
+          "name": "workosConnectionId",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "owner_id_idx": {
+          "name": "owner_id_idx",
+          "columns": [
+            "ownerId"
+          ],
+          "isUnique": false
+        },
+        "custom_domain_idx": {
+          "name": "custom_domain_idx",
+          "columns": [
+            "customDomain"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "organizations_id": {
+          "name": "organizations_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "organizations_id_unique": {
+          "name": "organizations_id_unique",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    },
+    "otp_codes": {
+      "name": "otp_codes",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "identifier": {
+          "name": "identifier",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "code": {
+          "name": "code",
+          "type": "varchar(6)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "expires": {
+          "name": "expires",
+          "type": "datetime",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "attempts": {
+          "name": "attempts",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": 0
+        },
+        "createdAt": {
+          "name": "createdAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "updatedAt": {
+          "name": "updatedAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "onUpdate": true,
+          "default": "(now())"
+        }
+      },
+      "indexes": {
+        "identifier_idx": {
+          "name": "identifier_idx",
+          "columns": [
+            "identifier"
+          ],
+          "isUnique": false
+        },
+        "code_idx": {
+          "name": "code_idx",
+          "columns": [
+            "code"
+          ],
+          "isUnique": false
+        },
+        "expires_idx": {
+          "name": "expires_idx",
+          "columns": [
+            "expires"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "otp_codes_id": {
+          "name": "otp_codes_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "otp_codes_id_unique": {
+          "name": "otp_codes_id_unique",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    },
+    "s3_buckets": {
+      "name": "s3_buckets",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "ownerId": {
+          "name": "ownerId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "region": {
+          "name": "region",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "endpoint": {
+          "name": "endpoint",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "bucketName": {
+          "name": "bucketName",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "accessKeyId": {
+          "name": "accessKeyId",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "secretAccessKey": {
+          "name": "secretAccessKey",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "provider": {
+          "name": "provider",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "('aws')"
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "s3_buckets_id": {
+          "name": "s3_buckets_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "s3_buckets_id_unique": {
+          "name": "s3_buckets_id_unique",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    },
+    "sessions": {
+      "name": "sessions",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "sessionToken": {
+          "name": "sessionToken",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "userId": {
+          "name": "userId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "expires": {
+          "name": "expires",
+          "type": "datetime",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "onUpdate": true,
+          "default": "(now())"
+        }
+      },
+      "indexes": {
+        "session_token_idx": {
+          "name": "session_token_idx",
+          "columns": [
+            "sessionToken"
+          ],
+          "isUnique": true
+        },
+        "user_id_idx": {
+          "name": "user_id_idx",
+          "columns": [
+            "userId"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "sessions_id": {
+          "name": "sessions_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "sessions_id_unique": {
+          "name": "sessions_id_unique",
+          "columns": [
+            "id"
+          ]
+        },
+        "sessions_sessionToken_unique": {
+          "name": "sessions_sessionToken_unique",
+          "columns": [
+            "sessionToken"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    },
+    "shared_videos": {
+      "name": "shared_videos",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "videoId": {
+          "name": "videoId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "organizationId": {
+          "name": "organizationId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "sharedByUserId": {
+          "name": "sharedByUserId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "sharedAt": {
+          "name": "sharedAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        }
+      },
+      "indexes": {
+        "video_id_idx": {
+          "name": "video_id_idx",
+          "columns": [
+            "videoId"
+          ],
+          "isUnique": false
+        },
+        "organization_id_idx": {
+          "name": "organization_id_idx",
+          "columns": [
+            "organizationId"
+          ],
+          "isUnique": false
+        },
+        "shared_by_user_id_idx": {
+          "name": "shared_by_user_id_idx",
+          "columns": [
+            "sharedByUserId"
+          ],
+          "isUnique": false
+        },
+        "video_id_organization_id_idx": {
+          "name": "video_id_organization_id_idx",
+          "columns": [
+            "videoId",
+            "organizationId"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "shared_videos_id": {
+          "name": "shared_videos_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "shared_videos_id_unique": {
+          "name": "shared_videos_id_unique",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    },
+    "space_members": {
+      "name": "space_members",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "spaceId": {
+          "name": "spaceId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "userId": {
+          "name": "userId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "role": {
+          "name": "role",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "'member'"
+        },
+        "createdAt": {
+          "name": "createdAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "updatedAt": {
+          "name": "updatedAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "onUpdate": true,
+          "default": "(now())"
+        }
+      },
+      "indexes": {
+        "space_id_idx": {
+          "name": "space_id_idx",
+          "columns": [
+            "spaceId"
+          ],
+          "isUnique": false
+        },
+        "user_id_idx": {
+          "name": "user_id_idx",
+          "columns": [
+            "userId"
+          ],
+          "isUnique": false
+        },
+        "space_id_user_id_idx": {
+          "name": "space_id_user_id_idx",
+          "columns": [
+            "spaceId",
+            "userId"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "space_members_id": {
+          "name": "space_members_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "space_members_id_unique": {
+          "name": "space_members_id_unique",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    },
+    "space_videos": {
+      "name": "space_videos",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "spaceId": {
+          "name": "spaceId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "folderId": {
+          "name": "folderId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "videoId": {
+          "name": "videoId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "addedById": {
+          "name": "addedById",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "addedAt": {
+          "name": "addedAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        }
+      },
+      "indexes": {
+        "space_id_idx": {
+          "name": "space_id_idx",
+          "columns": [
+            "spaceId"
+          ],
+          "isUnique": false
+        },
+        "folder_id_idx": {
+          "name": "folder_id_idx",
+          "columns": [
+            "folderId"
+          ],
+          "isUnique": false
+        },
+        "video_id_idx": {
+          "name": "video_id_idx",
+          "columns": [
+            "videoId"
+          ],
+          "isUnique": false
+        },
+        "added_by_id_idx": {
+          "name": "added_by_id_idx",
+          "columns": [
+            "addedById"
+          ],
+          "isUnique": false
+        },
+        "space_id_video_id_idx": {
+          "name": "space_id_video_id_idx",
+          "columns": [
+            "spaceId",
+            "videoId"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "space_videos_id": {
+          "name": "space_videos_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "space_videos_id_unique": {
+          "name": "space_videos_id_unique",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    },
+    "spaces": {
+      "name": "spaces",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "primary": {
+          "name": "primary",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": false
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "organizationId": {
+          "name": "organizationId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "createdById": {
+          "name": "createdById",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "iconUrl": {
+          "name": "iconUrl",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "description": {
+          "name": "description",
+          "type": "varchar(1000)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "createdAt": {
+          "name": "createdAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "updatedAt": {
+          "name": "updatedAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "onUpdate": true,
+          "default": "(now())"
+        },
+        "privacy": {
+          "name": "privacy",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "'Private'"
+        }
+      },
+      "indexes": {
+        "organization_id_idx": {
+          "name": "organization_id_idx",
+          "columns": [
+            "organizationId"
+          ],
+          "isUnique": false
+        },
+        "created_by_id_idx": {
+          "name": "created_by_id_idx",
+          "columns": [
+            "createdById"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "spaces_id": {
+          "name": "spaces_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "spaces_id_unique": {
+          "name": "spaces_id_unique",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    },
+    "users": {
+      "name": "users",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "lastName": {
+          "name": "lastName",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "email": {
+          "name": "email",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "emailVerified": {
+          "name": "emailVerified",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "image": {
+          "name": "image",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "stripeCustomerId": {
+          "name": "stripeCustomerId",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "stripeSubscriptionId": {
+          "name": "stripeSubscriptionId",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "thirdPartyStripeSubscriptionId": {
+          "name": "thirdPartyStripeSubscriptionId",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "stripeSubscriptionStatus": {
+          "name": "stripeSubscriptionStatus",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "stripeSubscriptionPriceId": {
+          "name": "stripeSubscriptionPriceId",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "activeOrganizationId": {
+          "name": "activeOrganizationId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "onUpdate": true,
+          "default": "(now())"
+        },
+        "onboarding_completed_at": {
+          "name": "onboarding_completed_at",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "customBucket": {
+          "name": "customBucket",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "inviteQuota": {
+          "name": "inviteQuota",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": 1
+        }
+      },
+      "indexes": {
+        "email_idx": {
+          "name": "email_idx",
+          "columns": [
+            "email"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "users_id": {
+          "name": "users_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "users_id_unique": {
+          "name": "users_id_unique",
+          "columns": [
+            "id"
+          ]
+        },
+        "users_email_unique": {
+          "name": "users_email_unique",
+          "columns": [
+            "email"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    },
+    "verification_tokens": {
+      "name": "verification_tokens",
+      "columns": {
+        "identifier": {
+          "name": "identifier",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "token": {
+          "name": "token",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "expires": {
+          "name": "expires",
+          "type": "datetime",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "onUpdate": true,
+          "default": "(now())"
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "verification_tokens_identifier": {
+          "name": "verification_tokens_identifier",
+          "columns": [
+            "identifier"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "verification_tokens_token_unique": {
+          "name": "verification_tokens_token_unique",
+          "columns": [
+            "token"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    },
+    "videos": {
+      "name": "videos",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "ownerId": {
+          "name": "ownerId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "'My Video'"
+        },
+        "awsRegion": {
+          "name": "awsRegion",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "awsBucket": {
+          "name": "awsBucket",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "bucket": {
+          "name": "bucket",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "metadata": {
+          "name": "metadata",
+          "type": "json",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "public": {
+          "name": "public",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": true
+        },
+        "password": {
+          "name": "password",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "videoStartTime": {
+          "name": "videoStartTime",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "audioStartTime": {
+          "name": "audioStartTime",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "xStreamInfo": {
+          "name": "xStreamInfo",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "jobId": {
+          "name": "jobId",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "jobStatus": {
+          "name": "jobStatus",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "isScreenshot": {
+          "name": "isScreenshot",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": false
+        },
+        "skipProcessing": {
+          "name": "skipProcessing",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": false
+        },
+        "transcriptionStatus": {
+          "name": "transcriptionStatus",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "createdAt": {
+          "name": "createdAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "updatedAt": {
+          "name": "updatedAt",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "onUpdate": true,
+          "default": "(now())"
+        },
+        "source": {
+          "name": "source",
+          "type": "json",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "('{\"type\":\"MediaConvert\"}')"
+        },
+        "folderId": {
+          "name": "folderId",
+          "type": "varchar(15)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "id_idx": {
+          "name": "id_idx",
+          "columns": [
+            "id"
+          ],
+          "isUnique": false
+        },
+        "owner_id_idx": {
+          "name": "owner_id_idx",
+          "columns": [
+            "ownerId"
+          ],
+          "isUnique": false
+        },
+        "is_public_idx": {
+          "name": "is_public_idx",
+          "columns": [
+            "public"
+          ],
+          "isUnique": false
+        },
+        "folder_id_idx": {
+          "name": "folder_id_idx",
+          "columns": [
+            "folderId"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "videos_id": {
+          "name": "videos_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {
+        "videos_id_unique": {
+          "name": "videos_id_unique",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "checkConstraint": {}
+    }
+  },
+  "views": {},
+  "_meta": {
+    "schemas": {},
+    "tables": {},
+    "columns": {}
+  },
+  "internal": {
+    "tables": {},
+    "indexes": {}
+  }
+}
\ No newline at end of file
diff --git a/packages/database/migrations/meta/_journal.json b/packages/database/migrations/meta/_journal.json
index 818cb035bb..0b10325e8d 100644
--- a/packages/database/migrations/meta/_journal.json
+++ b/packages/database/migrations/meta/_journal.json
@@ -50,6 +50,13 @@
       "when": 1751982995648,
       "tag": "0006_woozy_jamie_braddock",
       "breakpoints": true
+    },
+    {
+      "idx": 7,
+      "version": "5",
+      "when": 1754314124918,
+      "tag": "0007_cheerful_rocket_raccoon",
+      "breakpoints": true
     }
   ]
 }
\ No newline at end of file
diff --git a/packages/database/schema.ts b/packages/database/schema.ts
index 2db1a7fef8..7921cdda72 100644
--- a/packages/database/schema.ts
+++ b/packages/database/schema.ts
@@ -126,6 +126,24 @@ export const verificationTokens = mysqlTable("verification_tokens", {
   updated_at: timestamp("updated_at").notNull().defaultNow().onUpdateNow(),
 });
 
+export const otpCodes = mysqlTable(
+  "otp_codes",
+  {
+    id: nanoId("id").notNull().primaryKey().unique(),
+    identifier: varchar("identifier", { length: 255 }).notNull(),
+    code: varchar("code", { length: 6 }).notNull(),
+    expires: datetime("expires").notNull(),
+    attempts: int("attempts").notNull().default(0),
+    createdAt: timestamp("createdAt").notNull().defaultNow(),
+    updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
+  },
+  (table) => ({
+    identifierIndex: index("identifier_idx").on(table.identifier),
+    codeIndex: index("code_idx").on(table.code),
+    expiresIndex: index("expires_idx").on(table.expires),
+  })
+);
+
 export const organizations = mysqlTable(
   "organizations",
   {

From a081562325184ee74e316fdb40ce656efa196653 Mon Sep 17 00:00:00 2001
From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com>
Date: Mon, 4 Aug 2025 16:49:03 +0100
Subject: [PATCH 2/5] feat: Improved rate limiting messaging

---
 apps/web/app/(org)/login/form.tsx      | 28 +++++++++++++++++++----
 apps/web/app/(org)/verify-otp/form.tsx | 31 +++++++++++++++++++++-----
 apps/web/app/(org)/verify-otp/page.tsx |  6 ++---
 3 files changed, 53 insertions(+), 12 deletions(-)

diff --git a/apps/web/app/(org)/login/form.tsx b/apps/web/app/(org)/login/form.tsx
index 1b39b94346..1aa3fb8e14 100644
--- a/apps/web/app/(org)/login/form.tsx
+++ b/apps/web/app/(org)/login/form.tsx
@@ -16,7 +16,7 @@ import { LucideArrowUpRight } from "lucide-react";
 import { signIn } from "next-auth/react";
 import Image from "next/image";
 import Link from "next/link";
-import { useSearchParams } from "next/navigation";
+import { useSearchParams, useRouter } from "next/navigation";
 import { Suspense, useEffect, useState } from "react";
 import { toast } from "sonner";
 
@@ -27,6 +27,7 @@ const MotionButton = motion(Button);
 
 export function LoginForm() {
   const searchParams = useSearchParams();
+  const router = useRouter();
   const next = searchParams?.get("next");
   const [email, setEmail] = useState("");
   const [loading, setLoading] = useState(false);
@@ -35,6 +36,7 @@ export function LoginForm() {
   const [showOrgInput, setShowOrgInput] = useState(false);
   const [organizationId, setOrganizationId] = useState("");
   const [organizationName, setOrganizationName] = useState<string | null>(null);
+  const [lastEmailSentTime, setLastEmailSentTime] = useState<number | null>(null);
   const theme = Cookies.get("theme") || "light";
 
   useEffect(() => {
@@ -218,6 +220,17 @@ export function LoginForm() {
                       e.preventDefault();
                       if (!email) return;
 
+                      // Check if we're rate limited on the client side
+                      if (lastEmailSentTime) {
+                        const timeSinceLastRequest = Date.now() - lastEmailSentTime;
+                        const waitTime = 30000; // 30 seconds
+                        if (timeSinceLastRequest < waitTime) {
+                          const remainingSeconds = Math.ceil((waitTime - timeSinceLastRequest) / 1000);
+                          toast.error(`Please wait ${remainingSeconds} seconds before requesting a new code`);
+                          return;
+                        }
+                      }
+
                       setLoading(true);
                       trackEvent("auth_started", {
                         method: "email",
@@ -230,23 +243,30 @@ export function LoginForm() {
                       })
                         .then((res) => {
                           setLoading(false);
+                          
                           if (res?.ok && !res?.error) {
                             setEmailSent(true);
+                            setLastEmailSentTime(Date.now());
                             trackEvent("auth_email_sent", {
                               email_domain: email.split("@")[1],
                             });
                             const params = new URLSearchParams({
                               email,
                               ...(next && { next }),
+                              lastSent: Date.now().toString(),
                             });
-                            window.location.href = `/verify-otp?${params.toString()}`;
+                            router.push(`/verify-otp?${params.toString()}`);
                           } else {
-                            toast.error("Error sending email - try again?");
+                            // NextAuth always returns "EmailSignin" for all email provider errors
+                            // Since we already check rate limiting on the client side before sending,
+                            // if we get an error here, it's likely rate limiting from the server
+                            toast.error("Please wait 30 seconds before requesting a new code");
                           }
                         })
-                        .catch(() => {
+                        .catch((error) => {
                           setEmailSent(false);
                           setLoading(false);
+                          // Catch block is rarely triggered with NextAuth
                           toast.error("Error sending email - try again?");
                         });
                     }}
diff --git a/apps/web/app/(org)/verify-otp/form.tsx b/apps/web/app/(org)/verify-otp/form.tsx
index 02404116ad..758abdd409 100644
--- a/apps/web/app/(org)/verify-otp/form.tsx
+++ b/apps/web/app/(org)/verify-otp/form.tsx
@@ -10,10 +10,13 @@ import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { verifyOTPAction } from "./actions";
 
-export function VerifyOTPForm({ email, next }: { email: string; next?: string }) {
+export function VerifyOTPForm({ email, next, lastSent }: { email: string; next?: string; lastSent?: string }) {
   const [code, setCode] = useState(["", "", "", "", "", ""]);
   const [loading, setLoading] = useState(false);
   const [resending, setResending] = useState(false);
+  const [lastResendTime, setLastResendTime] = useState<number | null>(
+    lastSent ? parseInt(lastSent) : null
+  );
   const inputRefs = useRef<(HTMLInputElement | null)[]>([]);
 
   useEffect(() => {
@@ -85,15 +88,33 @@ export function VerifyOTPForm({ email, next }: { email: string; next?: string })
   };
 
   const handleResend = async () => {
+    // Check client-side rate limiting
+    if (lastResendTime) {
+      const timeSinceLastRequest = Date.now() - lastResendTime;
+      const waitTime = 30000; // 30 seconds
+      if (timeSinceLastRequest < waitTime) {
+        const remainingSeconds = Math.ceil((waitTime - timeSinceLastRequest) / 1000);
+        toast.error(`Please wait ${remainingSeconds} seconds before requesting a new code`);
+        return;
+      }
+    }
+
     setResending(true);
     try {
-      await signIn("email", {
+      const result = await signIn("email", {
         email,
         redirect: false,
       });
-      toast.success("A new code has been sent to your email!");
-      setCode(["", "", "", "", "", ""]);
-      inputRefs.current[0]?.focus();
+      
+      if (result?.ok && !result?.error) {
+        toast.success("A new code has been sent to your email!");
+        setCode(["", "", "", "", "", ""]);
+        inputRefs.current[0]?.focus();
+        setLastResendTime(Date.now());
+      } else {
+        // NextAuth returns generic "EmailSignin" error for all email errors
+        toast.error("Please wait 30 seconds before requesting a new code");
+      }
     } catch (error) {
       toast.error("Failed to resend code. Please try again.");
     } finally {
diff --git a/apps/web/app/(org)/verify-otp/page.tsx b/apps/web/app/(org)/verify-otp/page.tsx
index 31fe339b11..ef64dd7e8e 100644
--- a/apps/web/app/(org)/verify-otp/page.tsx
+++ b/apps/web/app/(org)/verify-otp/page.tsx
@@ -10,7 +10,7 @@ export const metadata = {
 export default async function VerifyOTPPage({
   searchParams,
 }: {
-  searchParams: { email?: string; next?: string };
+  searchParams: { email?: string; next?: string; lastSent?: string };
 }) {
   const session = await getSession();
 
@@ -24,8 +24,8 @@ export default async function VerifyOTPPage({
 
   return (
     <div className="flex h-screen w-full items-center justify-center">
-      <Suspense fallback={<div>Loading...</div>}>
-        <VerifyOTPForm email={searchParams.email} next={searchParams.next} />
+      <Suspense fallback={null}>
+        <VerifyOTPForm email={searchParams.email} next={searchParams.next} lastSent={searchParams.lastSent} />
       </Suspense>
     </div>
   );

From ae79a179ff1e1b95193491a1ec1eabe5b73418af Mon Sep 17 00:00:00 2001
From: Brendan Allan <brendonovich@outlook.com>
Date: Wed, 20 Aug 2025 17:42:48 +0800
Subject: [PATCH 3/5] remove credentials provider and use tanstack query

---
 apps/web/app/(org)/login/form.tsx         |  894 +++++++++---------
 apps/web/app/(org)/verify-otp/actions.ts  |   22 -
 apps/web/app/(org)/verify-otp/form.tsx    |  434 +++++----
 packages/database/auth/auth-options.tsx   |  433 ++++-----
 packages/database/auth/drizzle-adapter.ts |  477 +++++-----
 packages/database/auth/otp.ts             |  122 ---
 packages/database/schema.ts               | 1040 ++++++++++-----------
 7 files changed, 1637 insertions(+), 1785 deletions(-)
 delete mode 100644 apps/web/app/(org)/verify-otp/actions.ts
 delete mode 100644 packages/database/auth/otp.ts

diff --git a/apps/web/app/(org)/login/form.tsx b/apps/web/app/(org)/login/form.tsx
index 415ba2b23a..b160b43a9a 100644
--- a/apps/web/app/(org)/login/form.tsx
+++ b/apps/web/app/(org)/login/form.tsx
@@ -5,9 +5,9 @@ import { trackEvent } from "@/app/utils/analytics";
 import { NODE_ENV } from "@cap/env";
 import { Button, Input, LogoBadge } from "@cap/ui";
 import {
-  faArrowLeft,
-  faEnvelope,
-  faExclamationCircle,
+	faArrowLeft,
+	faEnvelope,
+	faExclamationCircle,
 } from "@fortawesome/free-solid-svg-icons";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { AnimatePresence, motion } from "framer-motion";
@@ -26,418 +26,428 @@ const MotionLink = motion(Link);
 const MotionButton = motion(Button);
 
 export function LoginForm() {
-  const searchParams = useSearchParams();
-  const router = useRouter();
-  const next = searchParams?.get("next");
-  const [email, setEmail] = useState("");
-  const [loading, setLoading] = useState(false);
-  const [emailSent, setEmailSent] = useState(false);
-  const [oauthError, setOauthError] = useState(false);
-  const [showOrgInput, setShowOrgInput] = useState(false);
-  const [organizationId, setOrganizationId] = useState("");
-  const [organizationName, setOrganizationName] = useState<string | null>(null);
-  const [lastEmailSentTime, setLastEmailSentTime] = useState<number | null>(null);
-  const theme = Cookies.get("theme") || "light";
+	const searchParams = useSearchParams();
+	const router = useRouter();
+	const next = searchParams?.get("next");
+	const [email, setEmail] = useState("");
+	const [loading, setLoading] = useState(false);
+	const [emailSent, setEmailSent] = useState(false);
+	const [oauthError, setOauthError] = useState(false);
+	const [showOrgInput, setShowOrgInput] = useState(false);
+	const [organizationId, setOrganizationId] = useState("");
+	const [organizationName, setOrganizationName] = useState<string | null>(null);
+	const [lastEmailSentTime, setLastEmailSentTime] = useState<number | null>(
+		null,
+	);
+	const theme = Cookies.get("theme") || "light";
 
-  useEffect(() => {
-    theme === "dark"
-      ? (document.body.className = "dark")
-      : (document.body.className = "light");
-    //remove the dark mode when we leave the dashboard
-    return () => {
-      document.body.className = "light";
-    };
-  }, [theme]);
+	useEffect(() => {
+		theme === "dark"
+			? (document.body.className = "dark")
+			: (document.body.className = "light");
+		//remove the dark mode when we leave the dashboard
+		return () => {
+			document.body.className = "light";
+		};
+	}, [theme]);
 
-  useEffect(() => {
-    const error = searchParams?.get("error");
-    const errorDesc = searchParams?.get("error_description");
+	useEffect(() => {
+		const error = searchParams?.get("error");
+		const errorDesc = searchParams?.get("error_description");
 
-    const handleErrors = () => {
-      if (error === "OAuthAccountNotLinked" && !errorDesc) {
-        setOauthError(true);
-        return toast.error(
-          "This email is already associated with a different sign-in method"
-        );
-      } else if (
-        error === "profile_not_allowed_outside_organization" &&
-        !errorDesc
-      ) {
-        return toast.error(
-          "Your email domain is not authorized for SSO access. Please use your work email or contact your administrator."
-        );
-      } else if (error && errorDesc) {
-        return toast.error(errorDesc);
-      }
-    };
-    handleErrors();
-  }, [searchParams]);
+		const handleErrors = () => {
+			if (error === "OAuthAccountNotLinked" && !errorDesc) {
+				setOauthError(true);
+				return toast.error(
+					"This email is already associated with a different sign-in method",
+				);
+			} else if (
+				error === "profile_not_allowed_outside_organization" &&
+				!errorDesc
+			) {
+				return toast.error(
+					"Your email domain is not authorized for SSO access. Please use your work email or contact your administrator.",
+				);
+			} else if (error && errorDesc) {
+				return toast.error(errorDesc);
+			}
+		};
+		handleErrors();
+	}, [searchParams]);
 
-  useEffect(() => {
-    const pendingPriceId = localStorage.getItem("pendingPriceId");
-    const pendingQuantity = localStorage.getItem("pendingQuantity") ?? "1";
-    if (emailSent && pendingPriceId) {
-      localStorage.removeItem("pendingPriceId");
-      localStorage.removeItem("pendingQuantity");
+	useEffect(() => {
+		const pendingPriceId = localStorage.getItem("pendingPriceId");
+		const pendingQuantity = localStorage.getItem("pendingQuantity") ?? "1";
+		if (emailSent && pendingPriceId) {
+			localStorage.removeItem("pendingPriceId");
+			localStorage.removeItem("pendingQuantity");
 
-      // Wait a bit to ensure the user is created
-      setTimeout(async () => {
-        const response = await fetch(`/api/settings/billing/subscribe`, {
-          method: "POST",
-          headers: {
-            "Content-Type": "application/json",
-          },
-          body: JSON.stringify({
-            priceId: pendingPriceId,
-            quantity: parseInt(pendingQuantity),
-          }),
-        });
-        const data = await response.json();
+			// Wait a bit to ensure the user is created
+			setTimeout(async () => {
+				const response = await fetch(`/api/settings/billing/subscribe`, {
+					method: "POST",
+					headers: {
+						"Content-Type": "application/json",
+					},
+					body: JSON.stringify({
+						priceId: pendingPriceId,
+						quantity: parseInt(pendingQuantity),
+					}),
+				});
+				const data = await response.json();
 
-        console.log(data);
+				console.log(data);
 
-        if (data.url) {
-          window.location.href = data.url;
-        }
-      }, 2000);
-    }
-  }, [emailSent]);
+				if (data.url) {
+					window.location.href = data.url;
+				}
+			}, 2000);
+		}
+	}, [emailSent]);
 
-  const handleGoogleSignIn = () => {
-    trackEvent("auth_started", { method: "google", is_signup: true });
-    signIn("google", {
-      ...(next && next.length > 0 ? { callbackUrl: next } : {}),
-    });
-  };
+	const handleGoogleSignIn = () => {
+		trackEvent("auth_started", { method: "google", is_signup: true });
+		signIn("google", {
+			...(next && next.length > 0 ? { callbackUrl: next } : {}),
+		});
+	};
 
-  const handleOrganizationLookup = async (e: React.FormEvent) => {
-    e.preventDefault();
-    if (!organizationId) {
-      toast.error("Please enter an organization ID");
-      return;
-    }
+	const handleOrganizationLookup = async (e: React.FormEvent) => {
+		e.preventDefault();
+		if (!organizationId) {
+			toast.error("Please enter an organization ID");
+			return;
+		}
 
-    try {
-      const data = await getOrganizationSSOData(organizationId);
-      setOrganizationName(data.name);
+		try {
+			const data = await getOrganizationSSOData(organizationId);
+			setOrganizationName(data.name);
 
-      signIn("workos", undefined, {
-        organization: data.organizationId,
-        connection: data.connectionId,
-      });
-    } catch (error) {
-      console.error("Lookup Error:", error);
-      toast.error("Organization not found or SSO not configured");
-    }
-  };
+			signIn("workos", undefined, {
+				organization: data.organizationId,
+				connection: data.connectionId,
+			});
+		} catch (error) {
+			console.error("Lookup Error:", error);
+			toast.error("Organization not found or SSO not configured");
+		}
+	};
 
-  return (
-    <motion.div
-      layout
-      transition={{
-        layout: { duration: 0.3, ease: "easeInOut" },
-        height: { duration: 0.3, ease: "easeInOut" },
-      }}
-      className="overflow-hidden relative w-[calc(100%-5%)] p-[28px] max-w-[432px] bg-gray-3 border border-gray-5 rounded-2xl"
-    >
-      <motion.div
-        layout="position"
-        key="back-button"
-        initial={{ opacity: 0, display: "none" }}
-        animate={{
-          opacity: showOrgInput ? 1 : 0,
-          display: showOrgInput ? "flex" : "none",
-          transition: { duration: 0.1, delay: 0.2 },
-        }}
-        onClick={() => setShowOrgInput(false)}
-        className="absolute overflow-hidden top-5 rounded-full left-5 z-20 hover:bg-gray-1 gap-2 items-center py-1.5 px-3 text-gray-12 bg-transparent border border-gray-4 transition-colors duration-300 cursor-pointer"
-      >
-        <FontAwesomeIcon className="w-2" icon={faArrowLeft} />
-        <motion.p layout="position" className="text-xs text-inherit">
-          Back
-        </motion.p>
-      </motion.div>
-      <MotionLink layout="position" className="flex mx-auto size-fit" href="/">
-        <MotionLogoBadge layout="position" className="w-[72px] h-[72px]" />
-      </MotionLink>
-      <motion.div
-        layout="position"
-        className="flex flex-col justify-center items-center my-7 text-left"
-      >
-        <motion.h1
-          key="title"
-          layout="position"
-          className="text-2xl font-semibold text-gray-12"
-        >
-          Sign in to Cap
-        </motion.h1>
-        <motion.p
-          key="subtitle"
-          layout="position"
-          className="text-[16px] text-gray-10"
-        >
-          Beautiful screen recordings, owned by you.
-        </motion.p>
-      </motion.div>
-      <motion.div layout="position" className="flex flex-col space-y-3">
-        <Suspense
-          fallback={
-            <>
-              <Button disabled={true} variant="primary" />
-              <Button disabled={true} variant="destructive" />
-              <div className="mx-auto w-3/4 h-5 rounded-lg bg-gray-1" />
-            </>
-          }
-        >
-          <motion.div layout className="flex flex-col space-y-3">
-            <AnimatePresence mode="wait" initial={false}>
-              <motion.div
-                key={showOrgInput ? "sso-wrapper" : "email-wrapper"}
-                layout
-                initial={{ height: 0, opacity: 0 }}
-                animate={{ height: "auto", opacity: 1 }}
-                exit={{ height: 0, opacity: 0 }}
-                transition={{
-                  duration: 0.25,
-                  ease: "easeInOut",
-                  opacity: { delay: 0.05 },
-                }}
-                className="px-1"
-              >
-                {showOrgInput ? (
-                  <motion.div
-                    key="sso"
-                    layout
-                    className="min-w-fit"
-                    initial={{ opacity: 0, y: 10 }}
-                    animate={{ opacity: 1, y: 0, transition: { delay: 0.1 } }}
-                    exit={{ opacity: 0, y: -10, transition: { duration: 0.1 } }}
-                    transition={{ duration: 0.2, ease: "easeInOut" }}
-                  >
-                    <LoginWithSSO
-                      handleOrganizationLookup={handleOrganizationLookup}
-                      organizationId={organizationId}
-                      setOrganizationId={setOrganizationId}
-                      organizationName={organizationName}
-                    />
-                  </motion.div>
-                ) : (
-                  <motion.form
-                    key="email"
-                    layout
-                    initial={{ opacity: 0, y: 10 }}
-                    animate={{
-                      opacity: 1,
-                      y: 0,
-                      transition: { duration: 0.1 },
-                    }}
-                    exit={{
-                      opacity: 0,
-                      y: -10,
-                      transition: { duration: 0.15 },
-                    }}
-                    transition={{
-                      duration: 0.2,
-                      ease: "easeInOut",
-                      opacity: { delay: 0.05 },
-                    }}
-                    onSubmit={async (e) => {
-                      e.preventDefault();
-                      if (!email) return;
+	return (
+		<motion.div
+			layout
+			transition={{
+				layout: { duration: 0.3, ease: "easeInOut" },
+				height: { duration: 0.3, ease: "easeInOut" },
+			}}
+			className="overflow-hidden relative w-[calc(100%-5%)] p-[28px] max-w-[432px] bg-gray-3 border border-gray-5 rounded-2xl"
+		>
+			<motion.div
+				layout="position"
+				key="back-button"
+				initial={{ opacity: 0, display: "none" }}
+				animate={{
+					opacity: showOrgInput ? 1 : 0,
+					display: showOrgInput ? "flex" : "none",
+					transition: { duration: 0.1, delay: 0.2 },
+				}}
+				onClick={() => setShowOrgInput(false)}
+				className="absolute overflow-hidden top-5 rounded-full left-5 z-20 hover:bg-gray-1 gap-2 items-center py-1.5 px-3 text-gray-12 bg-transparent border border-gray-4 transition-colors duration-300 cursor-pointer"
+			>
+				<FontAwesomeIcon className="w-2" icon={faArrowLeft} />
+				<motion.p layout="position" className="text-xs text-inherit">
+					Back
+				</motion.p>
+			</motion.div>
+			<MotionLink layout="position" className="flex mx-auto size-fit" href="/">
+				<MotionLogoBadge layout="position" className="w-[72px] h-[72px]" />
+			</MotionLink>
+			<motion.div
+				layout="position"
+				className="flex flex-col justify-center items-center my-7 text-left"
+			>
+				<motion.h1
+					key="title"
+					layout="position"
+					className="text-2xl font-semibold text-gray-12"
+				>
+					Sign in to Cap
+				</motion.h1>
+				<motion.p
+					key="subtitle"
+					layout="position"
+					className="text-[16px] text-gray-10"
+				>
+					Beautiful screen recordings, owned by you.
+				</motion.p>
+			</motion.div>
+			<motion.div layout="position" className="flex flex-col space-y-3">
+				<Suspense
+					fallback={
+						<>
+							<Button disabled={true} variant="primary" />
+							<Button disabled={true} variant="destructive" />
+							<div className="mx-auto w-3/4 h-5 rounded-lg bg-gray-1" />
+						</>
+					}
+				>
+					<motion.div layout className="flex flex-col space-y-3">
+						<AnimatePresence mode="wait" initial={false}>
+							<motion.div
+								key={showOrgInput ? "sso-wrapper" : "email-wrapper"}
+								layout
+								initial={{ height: 0, opacity: 0 }}
+								animate={{ height: "auto", opacity: 1 }}
+								exit={{ height: 0, opacity: 0 }}
+								transition={{
+									duration: 0.25,
+									ease: "easeInOut",
+									opacity: { delay: 0.05 },
+								}}
+								className="px-1"
+							>
+								{showOrgInput ? (
+									<motion.div
+										key="sso"
+										layout
+										className="min-w-fit"
+										initial={{ opacity: 0, y: 10 }}
+										animate={{ opacity: 1, y: 0, transition: { delay: 0.1 } }}
+										exit={{ opacity: 0, y: -10, transition: { duration: 0.1 } }}
+										transition={{ duration: 0.2, ease: "easeInOut" }}
+									>
+										<LoginWithSSO
+											handleOrganizationLookup={handleOrganizationLookup}
+											organizationId={organizationId}
+											setOrganizationId={setOrganizationId}
+											organizationName={organizationName}
+										/>
+									</motion.div>
+								) : (
+									<motion.form
+										key="email"
+										layout
+										initial={{ opacity: 0, y: 10 }}
+										animate={{
+											opacity: 1,
+											y: 0,
+											transition: { duration: 0.1 },
+										}}
+										exit={{
+											opacity: 0,
+											y: -10,
+											transition: { duration: 0.15 },
+										}}
+										transition={{
+											duration: 0.2,
+											ease: "easeInOut",
+											opacity: { delay: 0.05 },
+										}}
+										onSubmit={async (e) => {
+											e.preventDefault();
+											if (!email) return;
 
-                      // Check if we're rate limited on the client side
-                      if (lastEmailSentTime) {
-                        const timeSinceLastRequest = Date.now() - lastEmailSentTime;
-                        const waitTime = 30000; // 30 seconds
-                        if (timeSinceLastRequest < waitTime) {
-                          const remainingSeconds = Math.ceil((waitTime - timeSinceLastRequest) / 1000);
-                          toast.error(`Please wait ${remainingSeconds} seconds before requesting a new code`);
-                          return;
-                        }
-                      }
+											console.log({ lastEmailSentTime });
+											// Check if we're rate limited on the client side
+											if (lastEmailSentTime) {
+												const timeSinceLastRequest =
+													Date.now() - lastEmailSentTime;
+												const waitTime = 30000; // 30 seconds
+												if (timeSinceLastRequest < waitTime) {
+													const remainingSeconds = Math.ceil(
+														(waitTime - timeSinceLastRequest) / 1000,
+													);
+													toast.error(
+														`Please wait ${remainingSeconds} seconds before requesting a new code`,
+													);
+													return;
+												}
+											}
 
-                      setLoading(true);
-                      trackEvent("auth_started", {
-                        method: "email",
-                        is_signup: !oauthError,
-                      });
-                      signIn("email", {
-                        email,
-                        redirect: false,
-                        ...(next && next.length > 0
-                          ? { callbackUrl: next }
-                          : {}),
-                      })
-                        .then((res) => {
-                          setLoading(false);
-                          
-                          if (res?.ok && !res?.error) {
-                            setEmailSent(true);
-                            setLastEmailSentTime(Date.now());
-                            trackEvent("auth_email_sent", {
-                              email_domain: email.split("@")[1],
-                            });
-                            const params = new URLSearchParams({
-                              email,
-                              ...(next && { next }),
-                              lastSent: Date.now().toString(),
-                            });
-                            router.push(`/verify-otp?${params.toString()}`);
-                          } else {
-                            // NextAuth always returns "EmailSignin" for all email provider errors
-                            // Since we already check rate limiting on the client side before sending,
-                            // if we get an error here, it's likely rate limiting from the server
-                            toast.error("Please wait 30 seconds before requesting a new code");
-                          }
-                        })
-                        .catch((error) => {
-                          setEmailSent(false);
-                          setLoading(false);
-                          // Catch block is rarely triggered with NextAuth
-                          toast.error("Error sending email - try again?");
-                        });
-                    }}
-                    className="flex flex-col space-y-3"
-                  >
-                    <NormalLogin
-                      setShowOrgInput={setShowOrgInput}
-                      email={email}
-                      emailSent={emailSent}
-                      setEmail={setEmail}
-                      loading={loading}
-                      oauthError={oauthError}
-                      handleGoogleSignIn={handleGoogleSignIn}
-                    />
-                  </motion.form>
-                )}
-              </motion.div>
-            </AnimatePresence>
-            <motion.p
-              layout="position"
-              className="pt-3 text-xs text-center text-gray-9"
-            >
-              By typing your email and clicking continue, you acknowledge that
-              you have both read and agree to Cap's{" "}
-              <Link
-                href="/terms"
-                target="_blank"
-                className="text-xs font-semibold text-gray-12 hover:text-blue-300"
-              >
-                Terms of Service
-              </Link>{" "}
-              and{" "}
-              <Link
-                href="/privacy"
-                target="_blank"
-                className="text-xs font-semibold text-gray-12 hover:text-blue-300"
-              >
-                Privacy Policy
-              </Link>
-              .
-            </motion.p>
-          </motion.div>
-          {emailSent && (
-            <motion.button
-              layout
-              className="pt-3 mx-auto text-sm underline text-gray-10 hover:text-gray-8"
-              onClick={() => {
-                setEmailSent(false);
-                setEmail("");
-                setLoading(false);
-              }}
-            >
-              Click to restart sign in process
-            </motion.button>
-          )}
-        </Suspense>
-      </motion.div>
-    </motion.div>
-  );
+											setLoading(true);
+											trackEvent("auth_started", {
+												method: "email",
+												is_signup: !oauthError,
+											});
+											signIn("email", {
+												email,
+												redirect: false,
+												...(next && next.length > 0
+													? { callbackUrl: next }
+													: {}),
+											})
+												.then((res) => {
+													setLoading(false);
+
+													if (res?.ok && !res?.error) {
+														setEmailSent(true);
+														setLastEmailSentTime(Date.now());
+														trackEvent("auth_email_sent", {
+															email_domain: email.split("@")[1],
+														});
+														const params = new URLSearchParams({
+															email,
+															...(next && { next }),
+															lastSent: Date.now().toString(),
+														});
+														router.push(`/verify-otp?${params.toString()}`);
+													} else {
+														// NextAuth always returns "EmailSignin" for all email provider errors
+														// Since we already check rate limiting on the client side before sending,
+														// if we get an error here, it's likely rate limiting from the server
+														toast.error(
+															"Please wait 30 seconds before requesting a new code",
+														);
+													}
+												})
+												.catch((error) => {
+													setEmailSent(false);
+													setLoading(false);
+													// Catch block is rarely triggered with NextAuth
+													toast.error("Error sending email - try again?");
+												});
+										}}
+										className="flex flex-col space-y-3"
+									>
+										<NormalLogin
+											setShowOrgInput={setShowOrgInput}
+											email={email}
+											emailSent={emailSent}
+											setEmail={setEmail}
+											loading={loading}
+											oauthError={oauthError}
+											handleGoogleSignIn={handleGoogleSignIn}
+										/>
+									</motion.form>
+								)}
+							</motion.div>
+						</AnimatePresence>
+						<motion.p
+							layout="position"
+							className="pt-3 text-xs text-center text-gray-9"
+						>
+							By typing your email and clicking continue, you acknowledge that
+							you have both read and agree to Cap's{" "}
+							<Link
+								href="/terms"
+								target="_blank"
+								className="text-xs font-semibold text-gray-12 hover:text-blue-300"
+							>
+								Terms of Service
+							</Link>{" "}
+							and{" "}
+							<Link
+								href="/privacy"
+								target="_blank"
+								className="text-xs font-semibold text-gray-12 hover:text-blue-300"
+							>
+								Privacy Policy
+							</Link>
+							.
+						</motion.p>
+					</motion.div>
+					{emailSent && (
+						<motion.button
+							layout
+							className="pt-3 mx-auto text-sm underline text-gray-10 hover:text-gray-8"
+							onClick={() => {
+								setEmailSent(false);
+								setEmail("");
+								setLoading(false);
+							}}
+						>
+							Click to restart sign in process
+						</motion.button>
+					)}
+				</Suspense>
+			</motion.div>
+		</motion.div>
+	);
 }
 
 const LoginWithSSO = ({
-  handleOrganizationLookup,
-  organizationId,
-  setOrganizationId,
-  organizationName,
+	handleOrganizationLookup,
+	organizationId,
+	setOrganizationId,
+	organizationName,
 }: {
-  handleOrganizationLookup: (e: React.FormEvent) => void;
-  organizationId: string;
-  setOrganizationId: (organizationId: string) => void;
-  organizationName: string | null;
+	handleOrganizationLookup: (e: React.FormEvent) => void;
+	organizationId: string;
+	setOrganizationId: (organizationId: string) => void;
+	organizationName: string | null;
 }) => {
-  return (
-    <motion.form
-      layout
-      onSubmit={handleOrganizationLookup}
-      className="relative space-y-2"
-    >
-      <MotionInput
-        id="organizationId"
-        placeholder="Enter your Organization ID..."
-        value={organizationId}
-        onChange={(e) => setOrganizationId(e.target.value)}
-        className="w-full max-w-full"
-      />
-      {organizationName && (
-        <p className="text-sm text-gray-1">Signing in to: {organizationName}</p>
-      )}
-      <div>
-        <Button type="submit" variant="dark" className="w-full max-w-full">
-          Continue with SSO
-        </Button>
-      </div>
-    </motion.form>
-  );
+	return (
+		<motion.form
+			layout
+			onSubmit={handleOrganizationLookup}
+			className="relative space-y-2"
+		>
+			<MotionInput
+				id="organizationId"
+				placeholder="Enter your Organization ID..."
+				value={organizationId}
+				onChange={(e) => setOrganizationId(e.target.value)}
+				className="w-full max-w-full"
+			/>
+			{organizationName && (
+				<p className="text-sm text-gray-1">Signing in to: {organizationName}</p>
+			)}
+			<div>
+				<Button type="submit" variant="dark" className="w-full max-w-full">
+					Continue with SSO
+				</Button>
+			</div>
+		</motion.form>
+	);
 };
 
 const NormalLogin = ({
-  setShowOrgInput,
-  email,
-  emailSent,
-  setEmail,
-  loading,
-  oauthError,
-  handleGoogleSignIn,
+	setShowOrgInput,
+	email,
+	emailSent,
+	setEmail,
+	loading,
+	oauthError,
+	handleGoogleSignIn,
 }: {
-  setShowOrgInput: (show: boolean) => void;
-  email: string;
-  emailSent: boolean;
-  setEmail: (email: string) => void;
-  loading: boolean;
-  oauthError: boolean;
-  handleGoogleSignIn: () => void;
+	setShowOrgInput: (show: boolean) => void;
+	email: string;
+	emailSent: boolean;
+	setEmail: (email: string) => void;
+	loading: boolean;
+	oauthError: boolean;
+	handleGoogleSignIn: () => void;
 }) => {
-  return (
-    <motion.div>
-      <motion.div layout className="flex flex-col space-y-3">
-        <MotionInput
-          id="email"
-          name="email"
-          autoFocus
-          type="email"
-          placeholder={emailSent ? "" : "tim@apple.com"}
-          autoComplete="email"
-          required
-          value={email}
-          disabled={emailSent || loading}
-          onChange={(e) => {
-            setEmail(e.target.value);
-          }}
-        />
-        <MotionButton
-          variant="primary"
-          type="submit"
-          disabled={loading || emailSent}
-          icon={<FontAwesomeIcon className="mr-1 size-4" icon={faEnvelope} />}
-        >
-          {emailSent
-            ? NODE_ENV === "development"
-              ? "Email sent to your terminal"
-              : "Email sent to your inbox"
-            : "Login with email"}
-        </MotionButton>
-        {/* {NODE_ENV === "development" && (
+	return (
+		<motion.div>
+			<motion.div layout className="flex flex-col space-y-3">
+				<MotionInput
+					id="email"
+					name="email"
+					autoFocus
+					type="email"
+					placeholder={emailSent ? "" : "tim@apple.com"}
+					autoComplete="email"
+					required
+					value={email}
+					disabled={emailSent || loading}
+					onChange={(e) => {
+						setEmail(e.target.value);
+					}}
+				/>
+				<MotionButton
+					variant="primary"
+					type="submit"
+					disabled={loading || emailSent}
+					icon={<FontAwesomeIcon className="mr-1 size-4" icon={faEnvelope} />}
+				>
+					{emailSent
+						? NODE_ENV === "development"
+							? "Email sent to your terminal"
+							: "Email sent to your inbox"
+						: "Login with email"}
+				</MotionButton>
+				{/* {NODE_ENV === "development" && (
                   <div className="flex justify-center items-center px-6 py-3 mt-3 bg-red-600 rounded-xl">
                     <p className="text-lg text-white">
                       <span className="font-medium text-white">
@@ -447,56 +457,56 @@ const NormalLogin = ({
                     </p>
                   </div>
                 )} */}
-      </motion.div>
-      <div className="flex gap-4 items-center my-4">
-        <span className="flex-1 h-px bg-gray-5" />
-        <p className="text-sm text-center text-gray-10">OR</p>
-        <span className="flex-1 h-px bg-gray-5" />
-      </div>
-      <motion.div
-        layout
-        className="flex flex-col gap-3 justify-center items-center"
-      >
-        {!oauthError && (
-          <>
-            <MotionButton
-              variant="gray"
-              type="button"
-              className="flex gap-2 justify-center items-center w-full text-sm"
-              onClick={handleGoogleSignIn}
-              disabled={loading}
-            >
-              <Image src="/google.svg" alt="Google" width={16} height={16} />
-              Login with Google
-            </MotionButton>
-          </>
-        )}
+			</motion.div>
+			<div className="flex gap-4 items-center my-4">
+				<span className="flex-1 h-px bg-gray-5" />
+				<p className="text-sm text-center text-gray-10">OR</p>
+				<span className="flex-1 h-px bg-gray-5" />
+			</div>
+			<motion.div
+				layout
+				className="flex flex-col gap-3 justify-center items-center"
+			>
+				{!oauthError && (
+					<>
+						<MotionButton
+							variant="gray"
+							type="button"
+							className="flex gap-2 justify-center items-center w-full text-sm"
+							onClick={handleGoogleSignIn}
+							disabled={loading}
+						>
+							<Image src="/google.svg" alt="Google" width={16} height={16} />
+							Login with Google
+						</MotionButton>
+					</>
+				)}
 
-        {oauthError && (
-          <div className="flex gap-3 items-center p-3 bg-red-400 rounded-xl border border-red-600">
-            <FontAwesomeIcon
-              className="text-gray-50 size-8"
-              icon={faExclamationCircle}
-            />
-            <p className="text-xs leading-5 text-gray-50">
-              It looks like you've previously used this email to sign up via
-              email login. Please enter your email below to receive a sign in
-              link.
-            </p>
-          </div>
-        )}
-        <MotionButton
-          variant="gray"
-          type="button"
-          className="w-full"
-          layout
-          onClick={() => setShowOrgInput(true)}
-          disabled={loading}
-        >
-          <LucideArrowUpRight size={20} />
-          Login with SAML SSO
-        </MotionButton>
-      </motion.div>
-    </motion.div>
-  );
+				{oauthError && (
+					<div className="flex gap-3 items-center p-3 bg-red-400 rounded-xl border border-red-600">
+						<FontAwesomeIcon
+							className="text-gray-50 size-8"
+							icon={faExclamationCircle}
+						/>
+						<p className="text-xs leading-5 text-gray-50">
+							It looks like you've previously used this email to sign up via
+							email login. Please enter your email below to receive a sign in
+							link.
+						</p>
+					</div>
+				)}
+				<MotionButton
+					variant="gray"
+					type="button"
+					className="w-full"
+					layout
+					onClick={() => setShowOrgInput(true)}
+					disabled={loading}
+				>
+					<LucideArrowUpRight size={20} />
+					Login with SAML SSO
+				</MotionButton>
+			</motion.div>
+		</motion.div>
+	);
 };
diff --git a/apps/web/app/(org)/verify-otp/actions.ts b/apps/web/app/(org)/verify-otp/actions.ts
deleted file mode 100644
index fef7266fb8..0000000000
--- a/apps/web/app/(org)/verify-otp/actions.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-"use server";
-
-import { validateOTP } from "@cap/database/auth/otp";
-
-export async function verifyOTPAction(email: string, code: string) {
-  try {
-    if (!email || !code) {
-      return { success: false, error: "Email and code are required" };
-    }
-
-    const result = await validateOTP(email, code);
-
-    if (result.valid) {
-      return { success: true };
-    } else {
-      return { success: false, error: result.error || "Invalid code" };
-    }
-  } catch (error) {
-    console.error("OTP verification error:", error);
-    return { success: false, error: "An error occurred during verification" };
-  }
-}
\ No newline at end of file
diff --git a/apps/web/app/(org)/verify-otp/form.tsx b/apps/web/app/(org)/verify-otp/form.tsx
index 758abdd409..a86fe06510 100644
--- a/apps/web/app/(org)/verify-otp/form.tsx
+++ b/apps/web/app/(org)/verify-otp/form.tsx
@@ -8,206 +8,234 @@ import Link from "next/link";
 import { toast } from "sonner";
 import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { verifyOTPAction } from "./actions";
-
-export function VerifyOTPForm({ email, next, lastSent }: { email: string; next?: string; lastSent?: string }) {
-  const [code, setCode] = useState(["", "", "", "", "", ""]);
-  const [loading, setLoading] = useState(false);
-  const [resending, setResending] = useState(false);
-  const [lastResendTime, setLastResendTime] = useState<number | null>(
-    lastSent ? parseInt(lastSent) : null
-  );
-  const inputRefs = useRef<(HTMLInputElement | null)[]>([]);
-
-  useEffect(() => {
-    inputRefs.current[0]?.focus();
-  }, []);
-
-  const handleChange = (index: number, value: string) => {
-    if (value.length > 1) {
-      const pastedCode = value.slice(0, 6).split("");
-      const newCode = [...code];
-      pastedCode.forEach((digit, i) => {
-        if (index + i < 6) {
-          newCode[index + i] = digit;
-        }
-      });
-      setCode(newCode);
-      
-      const nextEmptyIndex = newCode.findIndex((digit) => digit === "");
-      if (nextEmptyIndex !== -1) {
-        inputRefs.current[nextEmptyIndex]?.focus();
-      } else {
-        inputRefs.current[5]?.focus();
-      }
-      return;
-    }
-
-    const newCode = [...code];
-    newCode[index] = value;
-    setCode(newCode);
-
-    if (value && index < 5) {
-      inputRefs.current[index + 1]?.focus();
-    }
-  };
-
-  const handleKeyDown = (index: number, e: React.KeyboardEvent<HTMLInputElement>) => {
-    if (e.key === "Backspace" && !code[index] && index > 0) {
-      inputRefs.current[index - 1]?.focus();
-    }
-  };
-
-  const handleVerify = async () => {
-    const otpCode = code.join("");
-    if (otpCode.length !== 6) {
-      toast.error("Please enter a complete 6-digit code");
-      return;
-    }
-
-    setLoading(true);
-    try {
-      const result = await verifyOTPAction(email, otpCode);
-
-      if (result.success) {
-        await signIn("otp", {
-          email,
-          redirect: true,
-          callbackUrl: next || "/dashboard",
-        });
-      } else {
-        toast.error(result.error || "Invalid code. Please try again.");
-        setCode(["", "", "", "", "", ""]);
-        inputRefs.current[0]?.focus();
-      }
-    } catch (error) {
-      toast.error("An error occurred. Please try again.");
-    } finally {
-      setLoading(false);
-    }
-  };
-
-  const handleResend = async () => {
-    // Check client-side rate limiting
-    if (lastResendTime) {
-      const timeSinceLastRequest = Date.now() - lastResendTime;
-      const waitTime = 30000; // 30 seconds
-      if (timeSinceLastRequest < waitTime) {
-        const remainingSeconds = Math.ceil((waitTime - timeSinceLastRequest) / 1000);
-        toast.error(`Please wait ${remainingSeconds} seconds before requesting a new code`);
-        return;
-      }
-    }
-
-    setResending(true);
-    try {
-      const result = await signIn("email", {
-        email,
-        redirect: false,
-      });
-      
-      if (result?.ok && !result?.error) {
-        toast.success("A new code has been sent to your email!");
-        setCode(["", "", "", "", "", ""]);
-        inputRefs.current[0]?.focus();
-        setLastResendTime(Date.now());
-      } else {
-        // NextAuth returns generic "EmailSignin" error for all email errors
-        toast.error("Please wait 30 seconds before requesting a new code");
-      }
-    } catch (error) {
-      toast.error("Failed to resend code. Please try again.");
-    } finally {
-      setResending(false);
-    }
-  };
-
-  return (
-    <motion.div
-      initial={{ opacity: 0, y: 20 }}
-      animate={{ opacity: 1, y: 0 }}
-      className="relative w-[calc(100%-5%)] p-[28px] max-w-[432px] bg-gray-3 border border-gray-5 rounded-2xl"
-    >
-      <Link
-        href="/login"
-        className="absolute top-5 left-5 z-20 flex gap-2 items-center py-1.5 px-3 text-gray-12 bg-transparent border border-gray-4 rounded-full hover:bg-gray-1 transition-colors duration-300"
-      >
-        <FontAwesomeIcon className="w-2" icon={faArrowLeft} />
-        <p className="text-xs">Back</p>
-      </Link>
-
-      <Link className="flex mx-auto size-fit" href="/">
-        <LogoBadge className="w-[72px] h-[72px]" />
-      </Link>
-
-      <div className="flex flex-col justify-center items-center my-7 text-center">
-        <h1 className="text-2xl font-semibold text-gray-12">Enter verification code</h1>
-        <p className="text-[16px] text-gray-10 mt-2">
-          We sent a 6-digit code to {email}
-        </p>
-      </div>
-
-      <div className="flex justify-center gap-2 mb-6">
-        {code.map((digit, index) => (
-          <input
-            key={index}
-            ref={(el) => (inputRefs.current[index] = el)}
-            type="text"
-            inputMode="numeric"
-            pattern="[0-9]*"
-            maxLength={1}
-            value={digit}
-            onChange={(e) => handleChange(index, e.target.value.replace(/\D/g, ""))}
-            onKeyDown={(e) => handleKeyDown(index, e)}
-            onPaste={(e) => {
-              e.preventDefault();
-              const pastedData = e.clipboardData.getData("text").replace(/\D/g, "");
-              handleChange(0, pastedData);
-            }}
-            className="w-12 h-14 text-center text-xl font-semibold bg-gray-1 border border-gray-5 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
-            disabled={loading}
-          />
-        ))}
-      </div>
-
-      <Button
-        variant="primary"
-        className="w-full"
-        onClick={handleVerify}
-        disabled={loading || code.some((digit) => !digit)}
-      >
-        {loading ? "Verifying..." : "Verify Code"}
-      </Button>
-
-      <div className="mt-4 text-center">
-        <button
-          onClick={handleResend}
-          disabled={resending}
-          className="text-sm text-gray-10 hover:text-gray-12 underline transition-colors"
-        >
-          {resending ? "Sending..." : "Didn't receive the code? Resend"}
-        </button>
-      </div>
-
-      <p className="mt-6 text-xs text-center text-gray-9">
-        By verifying your email, you acknowledge that you have both read and agree to Cap's{" "}
-        <Link
-          href="/terms"
-          target="_blank"
-          className="text-xs font-semibold text-gray-12 hover:text-blue-300"
-        >
-          Terms of Service
-        </Link>{" "}
-        and{" "}
-        <Link
-          href="/privacy"
-          target="_blank"
-          className="text-xs font-semibold text-gray-12 hover:text-blue-300"
-        >
-          Privacy Policy
-        </Link>
-        .
-      </p>
-    </motion.div>
-  );
-}
\ No newline at end of file
+import { useRouter } from "next/navigation";
+import { useMutation } from "@tanstack/react-query";
+
+export function VerifyOTPForm({
+	email,
+	next,
+	lastSent,
+}: {
+	email: string;
+	next?: string;
+	lastSent?: string;
+}) {
+	const [code, setCode] = useState(["", "", "", "", "", ""]);
+	const [lastResendTime, setLastResendTime] = useState<number | null>(
+		lastSent ? parseInt(lastSent) : null,
+	);
+	const inputRefs = useRef<(HTMLInputElement | null)[]>([]);
+	const router = useRouter();
+
+	useEffect(() => {
+		inputRefs.current[0]?.focus();
+	}, []);
+
+	const handleChange = (index: number, value: string) => {
+		if (value.length > 1) {
+			const pastedCode = value.slice(0, 6).split("");
+			const newCode = [...code];
+			pastedCode.forEach((digit, i) => {
+				if (index + i < 6) {
+					newCode[index + i] = digit;
+				}
+			});
+			setCode(newCode);
+
+			const nextEmptyIndex = newCode.findIndex((digit) => digit === "");
+			if (nextEmptyIndex !== -1) {
+				inputRefs.current[nextEmptyIndex]?.focus();
+			} else {
+				inputRefs.current[5]?.focus();
+			}
+
+			if (index + value.length >= 5) handleVerify.mutate();
+		} else {
+			const newCode = [...code];
+			newCode[index] = value;
+			setCode(newCode);
+
+			if (value && index < 5) {
+				inputRefs.current[index + 1]?.focus();
+			}
+		}
+	};
+
+	const handleKeyDown = (
+		index: number,
+		e: React.KeyboardEvent<HTMLInputElement>,
+	) => {
+		if (e.key === "Backspace" && !code[index] && index > 0) {
+			inputRefs.current[index - 1]?.focus();
+		}
+	};
+
+	const handleVerify = useMutation({
+		mutationFn: async () => {
+			const otpCode = code.join("");
+			if (otpCode.length !== 6) throw "Please enter a complete 6-digit code";
+
+			// shoutout https://github.com/buoyad/Tally/pull/14
+			const res = await fetch(
+				`/api/auth/callback/email?email=${encodeURIComponent(email)}&token=${encodeURIComponent(otpCode)}&callbackUrl=${encodeURIComponent("/login-success")}`,
+			);
+
+			if (!res.url.includes("/login-success")) {
+				setCode(["", "", "", "", "", ""]);
+				inputRefs.current[0]?.focus();
+				throw "Invalid code. Please try again.";
+			}
+		},
+		onSuccess: () => {
+			router.replace(next || "/dashboard");
+		},
+		onError: (e) => {
+			if (typeof e === "string") {
+				toast.error(e);
+			} else {
+				toast.error("An error occurred. Please try again.");
+			}
+		},
+	});
+
+	const handleResend = useMutation({
+		mutationFn: async () => {
+			// Check client-side rate limiting
+			if (lastResendTime) {
+				const timeSinceLastRequest = Date.now() - lastResendTime;
+				const waitTime = 30000; // 30 seconds
+				if (timeSinceLastRequest < waitTime) {
+					const remainingSeconds = Math.ceil(
+						(waitTime - timeSinceLastRequest) / 1000,
+					);
+
+					throw `Please wait ${remainingSeconds} seconds before requesting a new code`;
+				}
+			}
+
+			const result = await signIn("email", {
+				email,
+				redirect: false,
+			});
+
+			if (result?.error) {
+				// NextAuth returns generic "EmailSignin" error for all email errors
+				throw "Please wait 30 seconds before requesting a new code";
+			}
+		},
+		onSuccess: () => {
+			toast.success("A new code has been sent to your email!");
+			setCode(["", "", "", "", "", ""]);
+			inputRefs.current[0]?.focus();
+			setLastResendTime(Date.now());
+		},
+		onError: (e) => {
+			if (typeof e === "string") {
+				toast.error(e);
+			} else {
+				toast.error("An error occurred. Please try again.");
+			}
+		},
+	});
+
+	const isVerifying = handleVerify.isPending || handleVerify.isSuccess;
+
+	return (
+		<motion.div
+			initial={{ opacity: 0, y: 20 }}
+			animate={{ opacity: 1, y: 0 }}
+			className="relative w-[calc(100%-5%)] p-[28px] max-w-[432px] bg-gray-3 border border-gray-5 rounded-2xl"
+		>
+			<Link
+				href="/login"
+				className="absolute top-5 left-5 z-20 flex gap-2 items-center py-1.5 px-3 text-gray-12 bg-transparent border border-gray-4 rounded-full hover:bg-gray-1 transition-colors duration-300"
+			>
+				<FontAwesomeIcon className="w-2" icon={faArrowLeft} />
+				<p className="text-xs">Back</p>
+			</Link>
+
+			<Link className="flex mx-auto size-fit" href="/">
+				<LogoBadge className="w-[72px] h-[72px]" />
+			</Link>
+
+			<div className="flex flex-col justify-center items-center my-7 text-center">
+				<h1 className="text-2xl font-semibold text-gray-12">
+					Enter verification code
+				</h1>
+				<p className="text-[16px] text-gray-10 mt-2">
+					We sent a 6-digit code to {email}
+				</p>
+			</div>
+
+			<div className="flex justify-center gap-2 mb-6">
+				{code.map((digit, index) => (
+					<input
+						key={index}
+						ref={(el) => (inputRefs.current[index] = el)}
+						type="text"
+						inputMode="numeric"
+						pattern="[0-9]*"
+						maxLength={1}
+						value={digit}
+						onChange={(e) =>
+							handleChange(index, e.target.value.replace(/\D/g, ""))
+						}
+						onKeyDown={(e) => handleKeyDown(index, e)}
+						onPaste={(e) => {
+							e.preventDefault();
+							const pastedData = e.clipboardData
+								.getData("text")
+								.replace(/\D/g, "");
+							handleChange(0, pastedData);
+						}}
+						className="w-12 h-14 text-center text-xl font-semibold bg-gray-1 border border-gray-5 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
+						disabled={handleVerify.isPending || handleVerify.isSuccess}
+					/>
+				))}
+			</div>
+
+			<Button
+				variant="primary"
+				className="w-full"
+				onClick={() => handleVerify.mutate()}
+				disabled={code.some((digit) => !digit) || isVerifying}
+			>
+				{isVerifying ? "Verifying..." : "Verify Code"}
+			</Button>
+
+			<div className="mt-4 text-center">
+				<button
+					type="button"
+					onClick={() => handleResend.mutate()}
+					disabled={handleResend.isPending}
+					className="text-sm text-gray-10 hover:text-gray-12 underline transition-colors"
+				>
+					{handleResend.isPending
+						? "Sending..."
+						: "Didn't receive the code? Resend"}
+				</button>
+			</div>
+
+			<p className="mt-6 text-xs text-center text-gray-9">
+				By verifying your email, you acknowledge that you have both read and
+				agree to Cap's{" "}
+				<Link
+					href="/terms"
+					target="_blank"
+					className="text-xs font-semibold text-gray-12 hover:text-blue-300"
+				>
+					Terms of Service
+				</Link>{" "}
+				and{" "}
+				<Link
+					href="/privacy"
+					target="_blank"
+					className="text-xs font-semibold text-gray-12 hover:text-blue-300"
+				>
+					Privacy Policy
+				</Link>
+				.
+			</p>
+		</motion.div>
+	);
+}
diff --git a/packages/database/auth/auth-options.tsx b/packages/database/auth/auth-options.tsx
index 2546cd56cc..846b175143 100644
--- a/packages/database/auth/auth-options.tsx
+++ b/packages/database/auth/auth-options.tsx
@@ -21,237 +21,214 @@ import { LoginLink } from "../emails/login-link";
 import { generateOTP } from "./otp";
 
 export const config = {
-  maxDuration: 120,
+	maxDuration: 120,
 };
 
 export const authOptions = (): NextAuthOptions => {
-  let _adapter: Adapter | undefined;
-  let _providers: Provider[] | undefined;
-
-  return {
-    get adapter() {
-      if (_adapter) return _adapter;
-      _adapter = DrizzleAdapter(db());
-      return _adapter;
-    },
-    debug: true,
-    session: {
-      strategy: "jwt",
-    },
-    get secret() {
-      return serverEnv().NEXTAUTH_SECRET;
-    },
-    pages: {
-      signIn: "/login",
-    },
-    get providers() {
-      if (_providers) return _providers;
-      _providers = [
-        CredentialsProvider({
-          id: "otp",
-          name: "OTP",
-          credentials: {
-            email: { label: "Email", type: "email" },
-          },
-          async authorize(credentials) {
-            if (!credentials?.email) return null;
-
-            const [user] = await db()
-              .select()
-              .from(users)
-              .where(eq(users.email, credentials.email))
-              .limit(1);
-
-            if (user) {
-              return {
-                id: user.id,
-                email: user.email,
-                name: user.name,
-                image: user.image,
-              };
-            }
-
-            return null;
-          },
-        }),
-        GoogleProvider({
-          clientId: serverEnv().GOOGLE_CLIENT_ID!,
-          clientSecret: serverEnv().GOOGLE_CLIENT_SECRET!,
-          authorization: {
-            params: {
-              scope: [
-                "https://www.googleapis.com/auth/userinfo.email",
-                "https://www.googleapis.com/auth/userinfo.profile",
-              ].join(" "),
-              prompt: "select_account",
-            },
-          },
-        }),
-        WorkOSProvider({
-          clientId: serverEnv().WORKOS_CLIENT_ID as string,
-          clientSecret: serverEnv().WORKOS_API_KEY as string,
-          profile(profile) {
-            return {
-              id: profile.id,
-              name: profile.first_name
-                ? `${profile.first_name} ${profile.last_name || ""}`
-                : profile.email?.split("@")[0] || profile.id,
-              email: profile.email,
-              image: profile.profile_picture_url,
-            };
-          },
-        }),
-        EmailProvider({
-          async generateVerificationToken() {
-            return crypto.randomUUID();
-          },
-          async sendVerificationRequest({ identifier, url, token }) {
-            console.log("sendVerificationRequest");
-            
-            const otpCode = await generateOTP(identifier);
-            
-            if (!serverEnv().RESEND_API_KEY) {
-              console.log("\n");
-              console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
-              console.log("🔐 VERIFICATION CODE (Development Mode)");
-              console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
-              console.log(`📧 Email: ${identifier}`);
-              console.log(`🔢 Code: ${otpCode}`);
-              console.log(`⏱️  Expires in: 10 minutes`);
-              console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
-              console.log("\n");
-            } else {
-              console.log({ identifier, otpCode });
-              const { OTPEmail } = await import("../emails/otp-email");
-              const email = OTPEmail({ code: otpCode, email: identifier });
-              console.log({ email });
-              await sendEmail({
-                email: identifier,
-                subject: `Your Cap Verification Code`,
-                react: email,
-              });
-            }
-          },
-        }),
-      ];
-
-      return _providers;
-    },
-    cookies: {
-      sessionToken: {
-        name: `next-auth.session-token`,
-        options: {
-          httpOnly: true,
-          sameSite: "none",
-          path: "/",
-          secure: true,
-        },
-      },
-    },
-    events: {
-      async signIn({ user, account, isNewUser }) {
-        const [dbUser] = await db()
-          .select()
-          .from(users)
-          .where(eq(users.id, user.id))
-          .limit(1);
-
-        const needsOrganizationSetup =
-          isNewUser ||
-          !dbUser?.activeOrganizationId ||
-          dbUser.activeOrganizationId === "";
-
-        if (needsOrganizationSetup) {
-          const dubId = cookies().get("dub_id")?.value;
-          const dubPartnerData = cookies().get("dub_partner_data")?.value;
-
-          if (dubId && isNewUser) {
-            try {
-              console.log("Attempting to track lead with Dub...");
-              const trackResult = await dub().track.lead({
-                clickId: dubId,
-                eventName: "Sign Up",
-                externalId: user.id,
-                customerName: user.name || undefined,
-                customerEmail: user.email || undefined,
-                customerAvatar: user.image || undefined,
-              });
-
-              console.log("Dub tracking successful:", trackResult);
-
-              cookies().delete("dub_id");
-              if (dubPartnerData) {
-                cookies().delete("dub_partner_data");
-              }
-            } catch (error) {
-              console.error("Failed to track lead with Dub:", error);
-              console.error("Error details:", JSON.stringify(error, null, 2));
-            }
-          } else if (!isNewUser) {
-            console.log(
-              "Guest checkout user signing in for the first time - setting up organization"
-            );
-          }
-
-          const organizationId = nanoId();
-
-          await db().insert(organizations).values({
-            id: organizationId,
-            name: "My Organization",
-            ownerId: user.id,
-          });
-
-          await db().insert(organizationMembers).values({
-            id: nanoId(),
-            userId: user.id,
-            organizationId: organizationId,
-            role: "owner",
-          });
-
-          await db()
-            .update(users)
-            .set({ activeOrganizationId: organizationId })
-            .where(eq(users.id, user.id));
-        }
-      },
-    },
-    callbacks: {
-      async session({ token, session }) {
-        if (!session.user) return session;
-
-        if (token) {
-          session.user.id = token.id;
-          session.user.name = token.name;
-          session.user.email = token.email;
-          session.user.image = token.picture;
-        }
-
-        return session;
-      },
-      async jwt({ token, user }) {
-        const [dbUser] = await db()
-          .select()
-          .from(users)
-          .where(eq(users.email, token.email || ""))
-          .limit(1);
-
-        if (!dbUser) {
-          if (user) {
-            token.id = user?.id;
-          }
-          return token;
-        }
-
-        return {
-          id: dbUser.id,
-          name: dbUser.name,
-          lastName: dbUser.lastName,
-          email: dbUser.email,
-          picture: dbUser.image,
-        };
-      },
-    },
-  };
+	let _adapter: Adapter | undefined;
+	let _providers: Provider[] | undefined;
+
+	return {
+		get adapter() {
+			if (_adapter) return _adapter;
+			_adapter = DrizzleAdapter(db());
+			return _adapter;
+		},
+		debug: true,
+		session: {
+			strategy: "jwt",
+		},
+		get secret() {
+			return serverEnv().NEXTAUTH_SECRET;
+		},
+		pages: {
+			signIn: "/login",
+		},
+		get providers() {
+			if (_providers) return _providers;
+			_providers = [
+				GoogleProvider({
+					clientId: serverEnv().GOOGLE_CLIENT_ID!,
+					clientSecret: serverEnv().GOOGLE_CLIENT_SECRET!,
+					authorization: {
+						params: {
+							scope: [
+								"https://www.googleapis.com/auth/userinfo.email",
+								"https://www.googleapis.com/auth/userinfo.profile",
+							].join(" "),
+							prompt: "select_account",
+						},
+					},
+				}),
+				WorkOSProvider({
+					clientId: serverEnv().WORKOS_CLIENT_ID as string,
+					clientSecret: serverEnv().WORKOS_API_KEY as string,
+					profile(profile) {
+						return {
+							id: profile.id,
+							name: profile.first_name
+								? `${profile.first_name} ${profile.last_name || ""}`
+								: profile.email?.split("@")[0] || profile.id,
+							email: profile.email,
+							image: profile.profile_picture_url,
+						};
+					},
+				}),
+				EmailProvider({
+					async generateVerificationToken() {
+						return crypto.randomInt(100000, 1000000).toString();
+					},
+					async sendVerificationRequest({ identifier, token }) {
+						console.log("sendVerificationRequest");
+
+						if (!serverEnv().RESEND_API_KEY) {
+							console.log("\n");
+							console.log(
+								"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━",
+							);
+							console.log("🔐 VERIFICATION CODE (Development Mode)");
+							console.log(
+								"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━",
+							);
+							console.log(`📧 Email: ${identifier}`);
+							console.log(`🔢 Code: ${token}`);
+							console.log(`⏱️  Expires in: 10 minutes`);
+							console.log(
+								"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━",
+							);
+							console.log("\n");
+						} else {
+							console.log({ identifier, token });
+							const { OTPEmail } = await import("../emails/otp-email");
+							const email = OTPEmail({ code: token, email: identifier });
+							console.log({ email });
+							await sendEmail({
+								email: identifier,
+								subject: `Your Cap Verification Code`,
+								react: email,
+							});
+						}
+					},
+				}),
+			];
+
+			return _providers;
+		},
+		cookies: {
+			sessionToken: {
+				name: `next-auth.session-token`,
+				options: {
+					httpOnly: true,
+					sameSite: "none",
+					path: "/",
+					secure: true,
+				},
+			},
+		},
+		events: {
+			async signIn({ user, account, isNewUser }) {
+				const [dbUser] = await db()
+					.select()
+					.from(users)
+					.where(eq(users.id, user.id))
+					.limit(1);
+
+				const needsOrganizationSetup =
+					isNewUser ||
+					!dbUser?.activeOrganizationId ||
+					dbUser.activeOrganizationId === "";
+
+				if (needsOrganizationSetup) {
+					const dubId = cookies().get("dub_id")?.value;
+					const dubPartnerData = cookies().get("dub_partner_data")?.value;
+
+					if (dubId && isNewUser) {
+						try {
+							console.log("Attempting to track lead with Dub...");
+							const trackResult = await dub().track.lead({
+								clickId: dubId,
+								eventName: "Sign Up",
+								externalId: user.id,
+								customerName: user.name || undefined,
+								customerEmail: user.email || undefined,
+								customerAvatar: user.image || undefined,
+							});
+
+							console.log("Dub tracking successful:", trackResult);
+
+							cookies().delete("dub_id");
+							if (dubPartnerData) {
+								cookies().delete("dub_partner_data");
+							}
+						} catch (error) {
+							console.error("Failed to track lead with Dub:", error);
+							console.error("Error details:", JSON.stringify(error, null, 2));
+						}
+					} else if (!isNewUser) {
+						console.log(
+							"Guest checkout user signing in for the first time - setting up organization",
+						);
+					}
+
+					const organizationId = nanoId();
+
+					await db().insert(organizations).values({
+						id: organizationId,
+						name: "My Organization",
+						ownerId: user.id,
+					});
+
+					await db().insert(organizationMembers).values({
+						id: nanoId(),
+						userId: user.id,
+						organizationId: organizationId,
+						role: "owner",
+					});
+
+					await db()
+						.update(users)
+						.set({ activeOrganizationId: organizationId })
+						.where(eq(users.id, user.id));
+				}
+			},
+		},
+		callbacks: {
+			async session({ token, session }) {
+				if (!session.user) return session;
+
+				if (token) {
+					session.user.id = token.id;
+					session.user.name = token.name;
+					session.user.email = token.email;
+					session.user.image = token.picture;
+				}
+
+				return session;
+			},
+			async jwt({ token, user }) {
+				const [dbUser] = await db()
+					.select()
+					.from(users)
+					.where(eq(users.email, token.email || ""))
+					.limit(1);
+
+				if (!dbUser) {
+					if (user) {
+						token.id = user?.id;
+					}
+					return token;
+				}
+
+				return {
+					id: dbUser.id,
+					name: dbUser.name,
+					lastName: dbUser.lastName,
+					email: dbUser.email,
+					picture: dbUser.image,
+				};
+			},
+		},
+	};
 };
 
 export const getServerSession = () => _getServerSession(authOptions());
diff --git a/packages/database/auth/drizzle-adapter.ts b/packages/database/auth/drizzle-adapter.ts
index 749a4df4ce..694a0f45c5 100644
--- a/packages/database/auth/drizzle-adapter.ts
+++ b/packages/database/auth/drizzle-adapter.ts
@@ -6,250 +6,249 @@ import type { PlanetScaleDatabase } from "drizzle-orm/planetscale-serverless";
 import { stripe, STRIPE_AVAILABLE } from "@cap/utils";
 
 export function DrizzleAdapter(db: PlanetScaleDatabase): Adapter {
-  return {
-    async createUser(userData: any) {
-      await db.insert(users).values({
-        id: nanoId(),
-        email: userData.email,
-        emailVerified: userData.emailVerified,
-        name: userData.name,
-        image: userData.image,
-        activeOrganizationId: "",
-      });
-      const rows = await db
-        .select()
-        .from(users)
-        .where(eq(users.email, userData.email))
-        .limit(1);
-      const row = rows[0];
-      if (!row) throw new Error("User not found");
+	return {
+		async createUser(userData: any) {
+			await db.insert(users).values({
+				id: nanoId(),
+				email: userData.email,
+				emailVerified: userData.emailVerified,
+				name: userData.name,
+				image: userData.image,
+				activeOrganizationId: "",
+			});
+			const rows = await db
+				.select()
+				.from(users)
+				.where(eq(users.email, userData.email))
+				.limit(1);
+			const row = rows[0];
+			if (!row) throw new Error("User not found");
 
-      if (STRIPE_AVAILABLE()) {
-        const customer = await stripe().customers.create({
-          email: userData.email,
-          metadata: {
-            userId: nanoId(),
-          },
-        });
+			if (STRIPE_AVAILABLE()) {
+				const customer = await stripe().customers.create({
+					email: userData.email,
+					metadata: {
+						userId: nanoId(),
+					},
+				});
 
-        await db
-          .update(users)
-          .set({
-            stripeCustomerId: customer.id,
-          })
-          .where(eq(users.id, row.id));
-      }
+				await db
+					.update(users)
+					.set({
+						stripeCustomerId: customer.id,
+					})
+					.where(eq(users.id, row.id));
+			}
 
-      return row;
-    },
-    async getUser(id) {
-      const rows = await db
-        .select()
-        .from(users)
-        .where(eq(users.id, id))
-        .limit(1);
-      const row = rows[0];
-      return row ?? null;
-    },
-    async getUserByEmail(email) {
-      const rows = await db
-        .select()
-        .from(users)
-        .where(eq(users.email, email))
-        .limit(1)
-        .catch((e) => {
-          console.log(e);
-          throw e;
-        });
-      const row = rows[0];
-      return row ?? null;
-    },
-    async getUserByAccount({ providerAccountId, provider }) {
-      const rows = await db
-        .select()
-        .from(users)
-        .innerJoin(accounts, eq(users.id, accounts.userId))
-        .where(
-          and(
-            eq(accounts.providerAccountId, providerAccountId),
-            eq(accounts.provider, provider)
-          )
-        )
-        .limit(1);
-      const row = rows[0];
-      return row?.users ?? null;
-    },
-    async updateUser({ id, ...userData }) {
-      if (!id) throw new Error("User not found");
-      await db.update(users).set(userData).where(eq(users.id, id));
-      const rows = await db
-        .select()
-        .from(users)
-        .where(eq(users.id, id))
-        .limit(1);
-      const row = rows[0];
-      if (!row) throw new Error("User not found");
-      return row;
-    },
-    async deleteUser(userId) {
-      await db.delete(users).where(eq(users.id, userId));
-    },
-    async linkAccount(account: any) {
-      await db.insert(accounts).values({
-        id: nanoId(),
-        userId: account.userId,
-        type: account.type,
-        provider: account.provider,
-        providerAccountId: account.providerAccountId,
-        access_token: account.access_token,
-        expires_in: account.expires_in as number,
-        id_token: account.id_token,
-        refresh_token: account.refresh_token,
-        refresh_token_expires_in: account.refresh_token_expires_in as number,
-        scope: account.scope,
-        token_type: account.token_type,
-      });
-    },
-    async unlinkAccount({ providerAccountId, provider }: any) {
-      await db
-        .delete(accounts)
-        .where(
-          and(
-            eq(accounts.providerAccountId, providerAccountId),
-            eq(accounts.provider, provider)
-          )
-        );
-    },
-    async createSession(data) {
-      await db.insert(sessions).values({
-        id: nanoId(),
-        expires: data.expires,
-        sessionToken: data.sessionToken,
-        userId: data.userId,
-      });
-      const rows = await db
-        .select()
-        .from(sessions)
-        .where(eq(sessions.sessionToken, data.sessionToken))
-        .limit(1);
-      const row = rows[0];
-      if (!row) throw new Error("User not found");
-      return row;
-    },
-    async getSessionAndUser(sessionToken) {
-      const rows = await db
-        .select({
-          user: users,
-          session: {
-            id: sessions.id,
-            userId: sessions.userId,
-            sessionToken: sessions.sessionToken,
-            expires: sessions.expires,
-          },
-        })
-        .from(sessions)
-        .innerJoin(users, eq(users.id, sessions.userId))
-        .where(eq(sessions.sessionToken, sessionToken))
-        .limit(1);
-      const row = rows[0];
-      if (!row) return null;
-      const { user, session } = row;
-      return {
-        user,
-        session: {
-          id: session.id,
-          userId: session.userId,
-          sessionToken: session.sessionToken,
-          expires: session.expires,
-        },
-      };
-    },
-    async updateSession(session) {
-      await db
-        .update(sessions)
-        .set(session)
-        .where(eq(sessions.sessionToken, session.sessionToken));
-      const rows = await db
-        .select()
-        .from(sessions)
-        .where(eq(sessions.sessionToken, session.sessionToken))
-        .limit(1);
-      const row = rows[0];
-      if (!row) throw new Error("Coding bug: updated session not found");
-      return row;
-    },
-    async deleteSession(sessionToken) {
-      await db.delete(sessions).where(eq(sessions.sessionToken, sessionToken));
-    },
-    async createVerificationToken(verificationToken) {
-      console.log({ verificationToken });
-      // First, check if a token for the given identifier already exists
-      const existingTokens = await db
-        .select()
-        .from(verificationTokens)
-        .where(eq(verificationTokens.identifier, verificationToken.identifier))
-        .limit(1);
+			return row;
+		},
+		async getUser(id) {
+			const rows = await db
+				.select()
+				.from(users)
+				.where(eq(users.id, id))
+				.limit(1);
+			const row = rows[0];
+			return row ?? null;
+		},
+		async getUserByEmail(email) {
+			const rows = await db
+				.select()
+				.from(users)
+				.where(eq(users.email, email))
+				.limit(1)
+				.catch((e) => {
+					console.log(e);
+					throw e;
+				});
+			const row = rows[0];
+			return row ?? null;
+		},
+		async getUserByAccount({ providerAccountId, provider }) {
+			const rows = await db
+				.select()
+				.from(users)
+				.innerJoin(accounts, eq(users.id, accounts.userId))
+				.where(
+					and(
+						eq(accounts.providerAccountId, providerAccountId),
+						eq(accounts.provider, provider)
+					)
+				)
+				.limit(1);
+			const row = rows[0];
+			return row?.users ?? null;
+		},
+		async updateUser({ id, ...userData }) {
+			if (!id) throw new Error("User not found");
+			await db.update(users).set(userData).where(eq(users.id, id));
+			const rows = await db
+				.select()
+				.from(users)
+				.where(eq(users.id, id))
+				.limit(1);
+			const row = rows[0];
+			if (!row) throw new Error("User not found");
+			return row;
+		},
+		async deleteUser(userId) {
+			await db.delete(users).where(eq(users.id, userId));
+		},
+		async linkAccount(account: any) {
+			await db.insert(accounts).values({
+				id: nanoId(),
+				userId: account.userId,
+				type: account.type,
+				provider: account.provider,
+				providerAccountId: account.providerAccountId,
+				access_token: account.access_token,
+				expires_in: account.expires_in as number,
+				id_token: account.id_token,
+				refresh_token: account.refresh_token,
+				refresh_token_expires_in: account.refresh_token_expires_in as number,
+				scope: account.scope,
+				token_type: account.token_type,
+			});
+		},
+		async unlinkAccount({ providerAccountId, provider }: any) {
+			await db
+				.delete(accounts)
+				.where(
+					and(
+						eq(accounts.providerAccountId, providerAccountId),
+						eq(accounts.provider, provider)
+					)
+				);
+		},
+		async createSession(data) {
+			await db.insert(sessions).values({
+				id: nanoId(),
+				expires: data.expires,
+				sessionToken: data.sessionToken,
+				userId: data.userId,
+			});
+			const rows = await db
+				.select()
+				.from(sessions)
+				.where(eq(sessions.sessionToken, data.sessionToken))
+				.limit(1);
+			const row = rows[0];
+			if (!row) throw new Error("User not found");
+			return row;
+		},
+		async getSessionAndUser(sessionToken) {
+			const rows = await db
+				.select({
+					user: users,
+					session: {
+						id: sessions.id,
+						userId: sessions.userId,
+						sessionToken: sessions.sessionToken,
+						expires: sessions.expires,
+					},
+				})
+				.from(sessions)
+				.innerJoin(users, eq(users.id, sessions.userId))
+				.where(eq(sessions.sessionToken, sessionToken))
+				.limit(1);
+			const row = rows[0];
+			if (!row) return null;
+			const { user, session } = row;
+			return {
+				user,
+				session: {
+					id: session.id,
+					userId: session.userId,
+					sessionToken: session.sessionToken,
+					expires: session.expires,
+				},
+			};
+		},
+		async updateSession(session) {
+			await db
+				.update(sessions)
+				.set(session)
+				.where(eq(sessions.sessionToken, session.sessionToken));
+			const rows = await db
+				.select()
+				.from(sessions)
+				.where(eq(sessions.sessionToken, session.sessionToken))
+				.limit(1);
+			const row = rows[0];
+			if (!row) throw new Error("Coding bug: updated session not found");
+			return row;
+		},
+		async deleteSession(sessionToken) {
+			await db.delete(sessions).where(eq(sessions.sessionToken, sessionToken));
+		},
+		async createVerificationToken(verificationToken) {
+			// First, check if a token for the given identifier already exists
+			const existingTokens = await db
+				.select()
+				.from(verificationTokens)
+				.where(eq(verificationTokens.identifier, verificationToken.identifier))
+				.limit(1);
 
-      // If a token already exists, you can return the existing token
-      // or handle it based on your business logic
-      if (existingTokens.length > 0) {
-        // For example, updating the existing token:
-        await db
-          .update(verificationTokens)
-          .set({
-            token: verificationToken.token,
-            expires: verificationToken.expires,
-            // you may update other fields as necessary
-          })
-          .where(
-            eq(verificationTokens.identifier, verificationToken.identifier)
-          );
+			// If a token already exists, you can return the existing token
+			// or handle it based on your business logic
+			if (existingTokens.length > 0) {
+				// For example, updating the existing token:
+				await db
+					.update(verificationTokens)
+					.set({
+						token: verificationToken.token,
+						expires: verificationToken.expires,
+						// you may update other fields as necessary
+					})
+					.where(
+						eq(verificationTokens.identifier, verificationToken.identifier)
+					);
 
-        // Return the updated token
-        return await db
-          .select()
-          .from(verificationTokens)
-          .where(
-            eq(verificationTokens.identifier, verificationToken.identifier)
-          )
-          .limit(1)
-          .then((rows) => rows[0]);
-      }
+				// Return the updated token
+				return await db
+					.select()
+					.from(verificationTokens)
+					.where(
+						eq(verificationTokens.identifier, verificationToken.identifier)
+					)
+					.limit(1)
+					.then((rows) => rows[0]);
+			}
 
-      // If the token does not exist, proceed to create a new one
-      await db.insert(verificationTokens).values({
-        expires: verificationToken.expires,
-        identifier: verificationToken.identifier,
-        token: verificationToken.token,
-      });
+			// If the token does not exist, proceed to create a new one
+			await db.insert(verificationTokens).values({
+				expires: verificationToken.expires,
+				identifier: verificationToken.identifier,
+				token: verificationToken.token,
+			});
 
-      // Retrieve and return the newly created token
-      const rows = await db
-        .select()
-        .from(verificationTokens)
-        .where(eq(verificationTokens.token, verificationToken.token))
-        .limit(1);
-      const row = rows[0];
-      if (!row) throw new Error("Error: inserted verification token not found");
-      return row;
-    },
-    async useVerificationToken({ identifier, token }) {
-      const rows = await db
-        .select()
-        .from(verificationTokens)
-        .where(eq(verificationTokens.token, token))
-        .limit(1);
-      const row = rows[0];
-      if (!row) return null;
-      await db
-        .delete(verificationTokens)
-        .where(
-          and(
-            eq(verificationTokens.token, token),
-            eq(verificationTokens.identifier, identifier)
-          )
-        );
-      return row;
-    },
-  };
+			// Retrieve and return the newly created token
+			const rows = await db
+				.select()
+				.from(verificationTokens)
+				.where(eq(verificationTokens.token, verificationToken.token))
+				.limit(1);
+			const row = rows[0];
+			if (!row) throw new Error("Error: inserted verification token not found");
+			return row;
+		},
+		async useVerificationToken({ identifier, token }) {
+			const rows = await db
+				.select()
+				.from(verificationTokens)
+				.where(eq(verificationTokens.token, token))
+				.limit(1);
+			const row = rows[0];
+			if (!row) return null;
+			await db
+				.delete(verificationTokens)
+				.where(
+					and(
+						eq(verificationTokens.token, token),
+						eq(verificationTokens.identifier, identifier)
+					)
+				);
+			return row;
+		},
+	};
 }
diff --git a/packages/database/auth/otp.ts b/packages/database/auth/otp.ts
deleted file mode 100644
index 604e3e0a25..0000000000
--- a/packages/database/auth/otp.ts
+++ /dev/null
@@ -1,122 +0,0 @@
-import { db } from "../";
-import { otpCodes } from "../schema";
-import { eq, and, gt, gte, sql } from "drizzle-orm";
-import { nanoId } from "../helpers";
-import crypto from "crypto";
-
-const OTP_EXPIRY_MINUTES = 10;
-const MAX_ATTEMPTS = 3;
-const MIN_TIME_BETWEEN_REQUESTS_MS = 30000;
-
-export async function generateOTP(identifier: string): Promise<string> {
-  const recentOTP = await db()
-    .select()
-    .from(otpCodes)
-    .where(
-      and(
-        eq(otpCodes.identifier, identifier),
-        gte(otpCodes.createdAt, new Date(Date.now() - MIN_TIME_BETWEEN_REQUESTS_MS))
-      )
-    )
-    .limit(1);
-
-  if (recentOTP.length > 0) {
-    throw new Error("Please wait before requesting a new code");
-  }
-
-  const code = crypto.randomInt(100000, 1000000).toString();
-  
-  const expires = new Date();
-  expires.setMinutes(expires.getMinutes() + OTP_EXPIRY_MINUTES);
-
-  await db().delete(otpCodes).where(eq(otpCodes.identifier, identifier));
-
-  await db().insert(otpCodes).values({
-    id: nanoId(),
-    identifier,
-    code,
-    expires,
-    attempts: 0,
-  });
-
-  return code;
-}
-
-export async function validateOTP(
-  identifier: string,
-  code: string
-): Promise<{ valid: boolean; error?: string }> {
-  if (!code.match(/^\d{6}$/)) {
-    return { valid: false, error: "Invalid code format" };
-  }
-  const otpRecord = await db()
-    .select()
-    .from(otpCodes)
-    .where(
-      and(
-        eq(otpCodes.identifier, identifier),
-        eq(otpCodes.code, code),
-        gt(otpCodes.expires, new Date())
-      )
-    )
-    .limit(1);
-
-  if (otpRecord.length === 0) {
-    const expiredRecord = await db()
-      .select()
-      .from(otpCodes)
-      .where(
-        and(
-          eq(otpCodes.identifier, identifier),
-          eq(otpCodes.code, code)
-        )
-      )
-      .limit(1);
-
-    if (expiredRecord.length > 0) {
-      return { valid: false, error: "Code has expired" };
-    }
-
-    const activeRecord = await db()
-      .select()
-      .from(otpCodes)
-      .where(
-        and(
-          eq(otpCodes.identifier, identifier),
-          gt(otpCodes.expires, new Date())
-        )
-      )
-      .limit(1);
-
-    if (activeRecord.length > 0) {
-      const record = activeRecord[0];
-      
-      if (record.attempts >= MAX_ATTEMPTS) {
-        return { valid: false, error: "Too many attempts. Please request a new code." };
-      }
-
-      await db()
-        .update(otpCodes)
-        .set({ attempts: record.attempts + 1 })
-        .where(eq(otpCodes.id, record.id));
-
-      return { valid: false, error: "Invalid code" };
-    }
-
-    return { valid: false, error: "No active code found. Please request a new one." };
-  }
-
-  const record = otpRecord[0];
-
-  if (record.attempts >= MAX_ATTEMPTS) {
-    return { valid: false, error: "Too many attempts. Please request a new code." };
-  }
-
-  await db().delete(otpCodes).where(eq(otpCodes.id, record.id));
-
-  return { valid: true };
-}
-
-export async function cleanupExpiredOTPs(): Promise<void> {
-  await db().delete(otpCodes).where(gt(new Date(), otpCodes.expires));
-}
\ No newline at end of file
diff --git a/packages/database/schema.ts b/packages/database/schema.ts
index e4f2237fcc..2228a2bbdc 100644
--- a/packages/database/schema.ts
+++ b/packages/database/schema.ts
@@ -1,16 +1,16 @@
 import {
-  customType,
-  datetime,
-  int,
-  json,
-  mysqlTable,
-  text,
-  timestamp,
-  index,
-  boolean,
-  uniqueIndex,
-  varchar,
-  float,
+	customType,
+	datetime,
+	int,
+	json,
+	mysqlTable,
+	text,
+	timestamp,
+	index,
+	boolean,
+	uniqueIndex,
+	varchar,
+	float,
 } from "drizzle-orm/mysql-core";
 import { relations } from "drizzle-orm/relations";
 import { Folder } from "@cap/web-domain";
@@ -18,631 +18,613 @@ import { nanoIdLength } from "./helpers";
 import { VideoMetadata } from "./types";
 
 const nanoId = customType<{ data: string; notNull: true }>({
-  dataType() {
-    return `varchar(${nanoIdLength})`;
-  },
+	dataType() {
+		return `varchar(${nanoIdLength})`;
+	},
 });
 
 const nanoIdNullable = customType<{ data: string; notNull: false }>({
-  dataType() {
-    return `varchar(${nanoIdLength})`;
-  },
+	dataType() {
+		return `varchar(${nanoIdLength})`;
+	},
 });
 
 // Add a custom type for encrypted strings
 const encryptedText = customType<{ data: string; notNull: true }>({
-  dataType() {
-    return "text";
-  },
+	dataType() {
+		return "text";
+	},
 });
 
 const encryptedTextNullable = customType<{ data: string; notNull: false }>({
-  dataType() {
-    return "text";
-  },
+	dataType() {
+		return "text";
+	},
 });
 
 export const users = mysqlTable(
-  "users",
-  {
-    id: nanoId("id").notNull().primaryKey().unique(),
-    name: varchar("name", { length: 255 }),
-    lastName: varchar("lastName", { length: 255 }),
-    email: varchar("email", { length: 255 }).unique().notNull(),
-    emailVerified: timestamp("emailVerified"),
-    image: varchar("image", { length: 255 }),
-    stripeCustomerId: varchar("stripeCustomerId", { length: 255 }),
-    stripeSubscriptionId: varchar("stripeSubscriptionId", {
-      length: 255,
-    }),
-    thirdPartyStripeSubscriptionId: varchar("thirdPartyStripeSubscriptionId", {
-      length: 255,
-    }),
-    stripeSubscriptionStatus: varchar("stripeSubscriptionStatus", {
-      length: 255,
-    }),
-    stripeSubscriptionPriceId: varchar("stripeSubscriptionPriceId", {
-      length: 255,
-    }),
-    preferences: json("preferences")
-      .$type<{
-        notifications: {
-          pauseComments: boolean;
-          pauseReplies: boolean;
-          pauseViews: boolean;
-          pauseReactions: boolean;
-        };
-      } | null>()
-      .default(null),
-    activeOrganizationId: nanoId("activeOrganizationId"),
-    created_at: timestamp("created_at").notNull().defaultNow(),
-    updated_at: timestamp("updated_at").notNull().defaultNow().onUpdateNow(),
-    onboarding_completed_at: timestamp("onboarding_completed_at"),
-    customBucket: nanoIdNullable("customBucket"),
-    inviteQuota: int("inviteQuota").notNull().default(1),
-  },
-  (table) => ({
-    emailIndex: uniqueIndex("email_idx").on(table.email),
-  })
+	"users",
+	{
+		id: nanoId("id").notNull().primaryKey().unique(),
+		name: varchar("name", { length: 255 }),
+		lastName: varchar("lastName", { length: 255 }),
+		email: varchar("email", { length: 255 }).unique().notNull(),
+		emailVerified: timestamp("emailVerified"),
+		image: varchar("image", { length: 255 }),
+		stripeCustomerId: varchar("stripeCustomerId", { length: 255 }),
+		stripeSubscriptionId: varchar("stripeSubscriptionId", {
+			length: 255,
+		}),
+		thirdPartyStripeSubscriptionId: varchar("thirdPartyStripeSubscriptionId", {
+			length: 255,
+		}),
+		stripeSubscriptionStatus: varchar("stripeSubscriptionStatus", {
+			length: 255,
+		}),
+		stripeSubscriptionPriceId: varchar("stripeSubscriptionPriceId", {
+			length: 255,
+		}),
+		preferences: json("preferences")
+			.$type<{
+				notifications: {
+					pauseComments: boolean;
+					pauseReplies: boolean;
+					pauseViews: boolean;
+					pauseReactions: boolean;
+				};
+			} | null>()
+			.default(null),
+		activeOrganizationId: nanoId("activeOrganizationId"),
+		created_at: timestamp("created_at").notNull().defaultNow(),
+		updated_at: timestamp("updated_at").notNull().defaultNow().onUpdateNow(),
+		onboarding_completed_at: timestamp("onboarding_completed_at"),
+		customBucket: nanoIdNullable("customBucket"),
+		inviteQuota: int("inviteQuota").notNull().default(1),
+	},
+	(table) => ({
+		emailIndex: uniqueIndex("email_idx").on(table.email),
+	})
 );
 
 export const accounts = mysqlTable(
-  "accounts",
-  {
-    id: nanoId("id").notNull().primaryKey().unique(),
-    userId: nanoId("userId").notNull(),
-    type: varchar("type", { length: 255 }).notNull(),
-    provider: varchar("provider", { length: 255 }).notNull(),
-    providerAccountId: varchar("providerAccountId", { length: 255 }).notNull(),
-    access_token: text("access_token"),
-    expires_in: int("expires_in"),
-    id_token: text("id_token"),
-    refresh_token: text("refresh_token"),
-    refresh_token_expires_in: int("refresh_token_expires_in"),
-    scope: varchar("scope", { length: 255 }),
-    token_type: varchar("token_type", { length: 255 }),
-    createdAt: timestamp("createdAt").defaultNow().notNull(),
-    updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
-    tempColumn: text("tempColumn"),
-  },
-  (table) => ({
-    userIdIndex: index("user_id_idx").on(table.userId),
-    providerAccountIdIndex: index("provider_account_id_idx").on(
-      table.providerAccountId
-    ),
-  })
+	"accounts",
+	{
+		id: nanoId("id").notNull().primaryKey().unique(),
+		userId: nanoId("userId").notNull(),
+		type: varchar("type", { length: 255 }).notNull(),
+		provider: varchar("provider", { length: 255 }).notNull(),
+		providerAccountId: varchar("providerAccountId", { length: 255 }).notNull(),
+		access_token: text("access_token"),
+		expires_in: int("expires_in"),
+		id_token: text("id_token"),
+		refresh_token: text("refresh_token"),
+		refresh_token_expires_in: int("refresh_token_expires_in"),
+		scope: varchar("scope", { length: 255 }),
+		token_type: varchar("token_type", { length: 255 }),
+		createdAt: timestamp("createdAt").defaultNow().notNull(),
+		updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
+		tempColumn: text("tempColumn"),
+	},
+	(table) => ({
+		userIdIndex: index("user_id_idx").on(table.userId),
+		providerAccountIdIndex: index("provider_account_id_idx").on(
+			table.providerAccountId
+		),
+	})
 );
 
 export const sessions = mysqlTable(
-  "sessions",
-  {
-    id: nanoId("id").notNull().primaryKey().unique(),
-    sessionToken: varchar("sessionToken", { length: 255 }).unique().notNull(),
-    userId: nanoId("userId").notNull(),
-    expires: datetime("expires").notNull(),
-    created_at: timestamp("created_at").notNull().defaultNow(),
-    updated_at: timestamp("updated_at").notNull().defaultNow().onUpdateNow(),
-  },
-  (table) => ({
-    sessionTokenIndex: uniqueIndex("session_token_idx").on(table.sessionToken),
-    userIdIndex: index("user_id_idx").on(table.userId),
-  })
+	"sessions",
+	{
+		id: nanoId("id").notNull().primaryKey().unique(),
+		sessionToken: varchar("sessionToken", { length: 255 }).unique().notNull(),
+		userId: nanoId("userId").notNull(),
+		expires: datetime("expires").notNull(),
+		created_at: timestamp("created_at").notNull().defaultNow(),
+		updated_at: timestamp("updated_at").notNull().defaultNow().onUpdateNow(),
+	},
+	(table) => ({
+		sessionTokenIndex: uniqueIndex("session_token_idx").on(table.sessionToken),
+		userIdIndex: index("user_id_idx").on(table.userId),
+	})
 );
 
 export const verificationTokens = mysqlTable("verification_tokens", {
-  identifier: varchar("identifier", { length: 255 }).primaryKey().notNull(),
-  token: varchar("token", { length: 255 }).unique().notNull(),
-  expires: datetime("expires").notNull(),
-  created_at: timestamp("created_at").notNull().defaultNow(),
-  updated_at: timestamp("updated_at").notNull().defaultNow().onUpdateNow(),
+	identifier: varchar("identifier", { length: 255 }).primaryKey().notNull(),
+	token: varchar("token", { length: 255 }).unique().notNull(),
+	expires: datetime("expires").notNull(),
+	created_at: timestamp("created_at").notNull().defaultNow(),
+	updated_at: timestamp("updated_at").notNull().defaultNow().onUpdateNow(),
 });
 
-export const otpCodes = mysqlTable(
-  "otp_codes",
-  {
-    id: nanoId("id").notNull().primaryKey().unique(),
-    identifier: varchar("identifier", { length: 255 }).notNull(),
-    code: varchar("code", { length: 6 }).notNull(),
-    expires: datetime("expires").notNull(),
-    attempts: int("attempts").notNull().default(0),
-    createdAt: timestamp("createdAt").notNull().defaultNow(),
-    updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
-  },
-  (table) => ({
-    identifierIndex: index("identifier_idx").on(table.identifier),
-    codeIndex: index("code_idx").on(table.code),
-    expiresIndex: index("expires_idx").on(table.expires),
-  })
-);
-
 export const organizations = mysqlTable(
-  "organizations",
-  {
-    id: nanoId("id").notNull().primaryKey().unique(),
-    name: varchar("name", { length: 255 }).notNull(),
-    ownerId: nanoId("ownerId").notNull(),
-    metadata: json("metadata"),
-    allowedEmailDomain: varchar("allowedEmailDomain", { length: 255 }),
-    customDomain: varchar("customDomain", { length: 255 }),
-    domainVerified: timestamp("domainVerified"),
-    iconUrl: varchar("iconUrl", { length: 1024 }),
-    createdAt: timestamp("createdAt").notNull().defaultNow(),
-    updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
-    workosOrganizationId: varchar("workosOrganizationId", { length: 255 }),
-    workosConnectionId: varchar("workosConnectionId", { length: 255 }),
-  },
-  (table) => ({
-    ownerIdIndex: index("owner_id_idx").on(table.ownerId),
-    customDomainIndex: index("custom_domain_idx").on(table.customDomain),
-  })
+	"organizations",
+	{
+		id: nanoId("id").notNull().primaryKey().unique(),
+		name: varchar("name", { length: 255 }).notNull(),
+		ownerId: nanoId("ownerId").notNull(),
+		metadata: json("metadata"),
+		allowedEmailDomain: varchar("allowedEmailDomain", { length: 255 }),
+		customDomain: varchar("customDomain", { length: 255 }),
+		domainVerified: timestamp("domainVerified"),
+		iconUrl: varchar("iconUrl", { length: 1024 }),
+		createdAt: timestamp("createdAt").notNull().defaultNow(),
+		updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
+		workosOrganizationId: varchar("workosOrganizationId", { length: 255 }),
+		workosConnectionId: varchar("workosConnectionId", { length: 255 }),
+	},
+	(table) => ({
+		ownerIdIndex: index("owner_id_idx").on(table.ownerId),
+		customDomainIndex: index("custom_domain_idx").on(table.customDomain),
+	})
 );
 
 export const organizationMembers = mysqlTable(
-  "organization_members",
-  {
-    id: nanoId("id").notNull().primaryKey().unique(),
-    userId: nanoId("userId").notNull(),
-    organizationId: nanoId("organizationId").notNull(),
-    role: varchar("role", { length: 255 }).notNull(),
-    createdAt: timestamp("createdAt").notNull().defaultNow(),
-    updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
-  },
-  (table) => ({
-    userIdIndex: index("user_id_idx").on(table.userId),
-    organizationIdIndex: index("organization_id_idx").on(table.organizationId),
-    userIdOrganizationIdIndex: index("user_id_organization_id_idx").on(
-      table.userId,
-      table.organizationId
-    ),
-  })
+	"organization_members",
+	{
+		id: nanoId("id").notNull().primaryKey().unique(),
+		userId: nanoId("userId").notNull(),
+		organizationId: nanoId("organizationId").notNull(),
+		role: varchar("role", { length: 255 }).notNull(),
+		createdAt: timestamp("createdAt").notNull().defaultNow(),
+		updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
+	},
+	(table) => ({
+		userIdIndex: index("user_id_idx").on(table.userId),
+		organizationIdIndex: index("organization_id_idx").on(table.organizationId),
+		userIdOrganizationIdIndex: index("user_id_organization_id_idx").on(
+			table.userId,
+			table.organizationId
+		),
+	})
 );
 
 export const organizationInvites = mysqlTable(
-  "organization_invites",
-  {
-    id: nanoId("id").notNull().primaryKey().unique(),
-    organizationId: nanoId("organizationId").notNull(),
-    invitedEmail: varchar("invitedEmail", { length: 255 }).notNull(),
-    invitedByUserId: nanoId("invitedByUserId").notNull(),
-    role: varchar("role", { length: 255 }).notNull(),
-    status: varchar("status", { length: 255 }).notNull().default("pending"),
-    createdAt: timestamp("createdAt").notNull().defaultNow(),
-    updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
-    expiresAt: timestamp("expiresAt"),
-  },
-  (table) => ({
-    organizationIdIndex: index("organization_id_idx").on(table.organizationId),
-    invitedEmailIndex: index("invited_email_idx").on(table.invitedEmail),
-    invitedByUserIdIndex: index("invited_by_user_id_idx").on(
-      table.invitedByUserId
-    ),
-    statusIndex: index("status_idx").on(table.status),
-  })
+	"organization_invites",
+	{
+		id: nanoId("id").notNull().primaryKey().unique(),
+		organizationId: nanoId("organizationId").notNull(),
+		invitedEmail: varchar("invitedEmail", { length: 255 }).notNull(),
+		invitedByUserId: nanoId("invitedByUserId").notNull(),
+		role: varchar("role", { length: 255 }).notNull(),
+		status: varchar("status", { length: 255 }).notNull().default("pending"),
+		createdAt: timestamp("createdAt").notNull().defaultNow(),
+		updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
+		expiresAt: timestamp("expiresAt"),
+	},
+	(table) => ({
+		organizationIdIndex: index("organization_id_idx").on(table.organizationId),
+		invitedEmailIndex: index("invited_email_idx").on(table.invitedEmail),
+		invitedByUserIdIndex: index("invited_by_user_id_idx").on(
+			table.invitedByUserId
+		),
+		statusIndex: index("status_idx").on(table.status),
+	})
 );
 
 export const folders = mysqlTable(
-  "folders",
-  {
-    id: nanoId("id").notNull().primaryKey().unique().$type<Folder.FolderId>(),
-    name: varchar("name", { length: 255 }).notNull(),
-    color: varchar("color", {
-      length: 16,
-      enum: ["normal", "blue", "red", "yellow"],
-    })
-      .notNull()
-      .default("normal"),
-    organizationId: nanoId("organizationId").notNull(),
-    createdById: nanoId("createdById").notNull(),
-    parentId: nanoIdNullable("parentId").$type<Folder.FolderId | null>(),
-    spaceId: nanoIdNullable("spaceId"),
-    createdAt: timestamp("createdAt").notNull().defaultNow(),
-    updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
-  },
-  (table) => ({
-    organizationIdIndex: index("organization_id_idx").on(table.organizationId),
-    createdByIdIndex: index("created_by_id_idx").on(table.createdById),
-    parentIdIndex: index("parent_id_idx").on(table.parentId),
-    spaceIdIndex: index("space_id_idx").on(table.spaceId),
-  })
+	"folders",
+	{
+		id: nanoId("id").notNull().primaryKey().unique().$type<Folder.FolderId>(),
+		name: varchar("name", { length: 255 }).notNull(),
+		color: varchar("color", {
+			length: 16,
+			enum: ["normal", "blue", "red", "yellow"],
+		})
+			.notNull()
+			.default("normal"),
+		organizationId: nanoId("organizationId").notNull(),
+		createdById: nanoId("createdById").notNull(),
+		parentId: nanoIdNullable("parentId").$type<Folder.FolderId | null>(),
+		spaceId: nanoIdNullable("spaceId"),
+		createdAt: timestamp("createdAt").notNull().defaultNow(),
+		updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
+	},
+	(table) => ({
+		organizationIdIndex: index("organization_id_idx").on(table.organizationId),
+		createdByIdIndex: index("created_by_id_idx").on(table.createdById),
+		parentIdIndex: index("parent_id_idx").on(table.parentId),
+		spaceIdIndex: index("space_id_idx").on(table.spaceId),
+	})
 );
 
 export const videos = mysqlTable(
-  "videos",
-  {
-    id: nanoId("id").notNull().primaryKey().unique(),
-    ownerId: nanoId("ownerId").notNull(),
-    name: varchar("name", { length: 255 }).notNull().default("My Video"),
-    bucket: nanoIdNullable("bucket"),
-    metadata: json("metadata").$type<VideoMetadata>(),
-    public: boolean("public").notNull().default(true),
-    transcriptionStatus: varchar("transcriptionStatus", { length: 255 }).$type<
-      "PROCESSING" | "COMPLETE" | "ERROR"
-    >(),
-    source: json("source")
-      .$type<
-        { type: "MediaConvert" } | { type: "local" } | { type: "desktopMP4" }
-      >()
-      .notNull()
-      .default({ type: "MediaConvert" }),
-    folderId: nanoIdNullable("folderId"),
-    createdAt: timestamp("createdAt").notNull().defaultNow(),
-    updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
-    // PRIVATE
-    password: encryptedTextNullable("password"),
-    // LEGACY
-    xStreamInfo: text("xStreamInfo"),
-    isScreenshot: boolean("isScreenshot").notNull().default(false),
-    // DEPRECATED
-    awsRegion: varchar("awsRegion", { length: 255 }),
-    awsBucket: varchar("awsBucket", { length: 255 }),
-    videoStartTime: varchar("videoStartTime", { length: 255 }),
-    audioStartTime: varchar("audioStartTime", { length: 255 }),
-    jobId: varchar("jobId", { length: 255 }),
-    jobStatus: varchar("jobStatus", { length: 255 }),
-    skipProcessing: boolean("skipProcessing").notNull().default(false),
-  },
-  (table) => ({
-    idIndex: index("id_idx").on(table.id),
-    ownerIdIndex: index("owner_id_idx").on(table.ownerId),
-    publicIndex: index("is_public_idx").on(table.public),
-    folderIdIndex: index("folder_id_idx").on(table.folderId),
-  })
+	"videos",
+	{
+		id: nanoId("id").notNull().primaryKey().unique(),
+		ownerId: nanoId("ownerId").notNull(),
+		name: varchar("name", { length: 255 }).notNull().default("My Video"),
+		bucket: nanoIdNullable("bucket"),
+		metadata: json("metadata").$type<VideoMetadata>(),
+		public: boolean("public").notNull().default(true),
+		transcriptionStatus: varchar("transcriptionStatus", { length: 255 }).$type<
+			"PROCESSING" | "COMPLETE" | "ERROR"
+		>(),
+		source: json("source")
+			.$type<
+				{ type: "MediaConvert" } | { type: "local" } | { type: "desktopMP4" }
+			>()
+			.notNull()
+			.default({ type: "MediaConvert" }),
+		folderId: nanoIdNullable("folderId"),
+		createdAt: timestamp("createdAt").notNull().defaultNow(),
+		updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
+		// PRIVATE
+		password: encryptedTextNullable("password"),
+		// LEGACY
+		xStreamInfo: text("xStreamInfo"),
+		isScreenshot: boolean("isScreenshot").notNull().default(false),
+		// DEPRECATED
+		awsRegion: varchar("awsRegion", { length: 255 }),
+		awsBucket: varchar("awsBucket", { length: 255 }),
+		videoStartTime: varchar("videoStartTime", { length: 255 }),
+		audioStartTime: varchar("audioStartTime", { length: 255 }),
+		jobId: varchar("jobId", { length: 255 }),
+		jobStatus: varchar("jobStatus", { length: 255 }),
+		skipProcessing: boolean("skipProcessing").notNull().default(false),
+	},
+	(table) => ({
+		idIndex: index("id_idx").on(table.id),
+		ownerIdIndex: index("owner_id_idx").on(table.ownerId),
+		publicIndex: index("is_public_idx").on(table.public),
+		folderIdIndex: index("folder_id_idx").on(table.folderId),
+	})
 );
 
 export const sharedVideos = mysqlTable(
-  "shared_videos",
-  {
-    id: nanoId("id").notNull().primaryKey().unique(),
-    videoId: nanoId("videoId").notNull(),
-    organizationId: nanoId("organizationId").notNull(),
-    sharedByUserId: nanoId("sharedByUserId").notNull(),
-    sharedAt: timestamp("sharedAt").notNull().defaultNow(),
-  },
-  (table) => ({
-    videoIdIndex: index("video_id_idx").on(table.videoId),
-    organizationIdIndex: index("organization_id_idx").on(table.organizationId),
-    sharedByUserIdIndex: index("shared_by_user_id_idx").on(
-      table.sharedByUserId
-    ),
-    videoIdOrganizationIdIndex: index("video_id_organization_id_idx").on(
-      table.videoId,
-      table.organizationId
-    ),
-  })
+	"shared_videos",
+	{
+		id: nanoId("id").notNull().primaryKey().unique(),
+		videoId: nanoId("videoId").notNull(),
+		organizationId: nanoId("organizationId").notNull(),
+		sharedByUserId: nanoId("sharedByUserId").notNull(),
+		sharedAt: timestamp("sharedAt").notNull().defaultNow(),
+	},
+	(table) => ({
+		videoIdIndex: index("video_id_idx").on(table.videoId),
+		organizationIdIndex: index("organization_id_idx").on(table.organizationId),
+		sharedByUserIdIndex: index("shared_by_user_id_idx").on(
+			table.sharedByUserId
+		),
+		videoIdOrganizationIdIndex: index("video_id_organization_id_idx").on(
+			table.videoId,
+			table.organizationId
+		),
+	})
 );
 
 export const comments = mysqlTable(
-  "comments",
-  {
-    id: nanoId("id").notNull().primaryKey().unique(),
-    type: varchar("type", { length: 6, enum: ["emoji", "text"] }).notNull(),
-    content: text("content").notNull(),
-    timestamp: float("timestamp"),
-    authorId: nanoId("authorId").notNull(),
-    videoId: nanoId("videoId").notNull(),
-    createdAt: timestamp("createdAt").notNull().defaultNow(),
-    updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
-    parentCommentId: nanoId("parentCommentId"),
-  },
-  (table) => ({
-    videoIdIndex: index("video_id_idx").on(table.videoId),
-    authorIdIndex: index("author_id_idx").on(table.authorId),
-    parentCommentIdIndex: index("parent_comment_id_idx").on(
-      table.parentCommentId
-    ),
-  })
+	"comments",
+	{
+		id: nanoId("id").notNull().primaryKey().unique(),
+		type: varchar("type", { length: 6, enum: ["emoji", "text"] }).notNull(),
+		content: text("content").notNull(),
+		timestamp: float("timestamp"),
+		authorId: nanoId("authorId").notNull(),
+		videoId: nanoId("videoId").notNull(),
+		createdAt: timestamp("createdAt").notNull().defaultNow(),
+		updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
+		parentCommentId: nanoId("parentCommentId"),
+	},
+	(table) => ({
+		videoIdIndex: index("video_id_idx").on(table.videoId),
+		authorIdIndex: index("author_id_idx").on(table.authorId),
+		parentCommentIdIndex: index("parent_comment_id_idx").on(
+			table.parentCommentId
+		),
+	})
 );
 
 export const notifications = mysqlTable(
-  "notifications",
-  {
-    id: nanoId("id").notNull().primaryKey().unique(),
-    orgId: nanoId("orgId").notNull(),
-    recipientId: nanoId("recipientId").notNull(),
-    type: varchar("type", { length: 10 })
-      .notNull()
-      .$type<"view" | "comment" | "reply" | "reaction" /*| "mention"*/>(),
-    data: json("data")
-      .$type<{
-        videoId?: string;
-        authorId?: string;
-        comment?: {
-          id: string;
-          content: string;
-        };
-      }>()
-      .notNull(),
-    readAt: timestamp("readAt"),
-    createdAt: timestamp("createdAt").notNull().defaultNow(),
-  },
-  (table) => ({
-    recipientIdIndex: index("recipient_id_idx").on(table.recipientId),
-    orgIdIndex: index("org_id_idx").on(table.orgId),
-    typeIndex: index("type_idx").on(table.type),
-    readAtIndex: index("read_at_idx").on(table.readAt),
-    createdAtIndex: index("created_at_idx").on(table.createdAt),
-    recipientReadIndex: index("recipient_read_idx").on(
-      table.recipientId,
-      table.readAt
-    ),
-    recipientCreatedIndex: index("recipient_created_idx").on(
-      table.recipientId,
-      table.createdAt
-    ),
-  })
+	"notifications",
+	{
+		id: nanoId("id").notNull().primaryKey().unique(),
+		orgId: nanoId("orgId").notNull(),
+		recipientId: nanoId("recipientId").notNull(),
+		type: varchar("type", { length: 10 })
+			.notNull()
+			.$type<"view" | "comment" | "reply" | "reaction" /*| "mention"*/>(),
+		data: json("data")
+			.$type<{
+				videoId?: string;
+				authorId?: string;
+				comment?: {
+					id: string;
+					content: string;
+				};
+			}>()
+			.notNull(),
+		readAt: timestamp("readAt"),
+		createdAt: timestamp("createdAt").notNull().defaultNow(),
+	},
+	(table) => ({
+		recipientIdIndex: index("recipient_id_idx").on(table.recipientId),
+		orgIdIndex: index("org_id_idx").on(table.orgId),
+		typeIndex: index("type_idx").on(table.type),
+		readAtIndex: index("read_at_idx").on(table.readAt),
+		createdAtIndex: index("created_at_idx").on(table.createdAt),
+		recipientReadIndex: index("recipient_read_idx").on(
+			table.recipientId,
+			table.readAt
+		),
+		recipientCreatedIndex: index("recipient_created_idx").on(
+			table.recipientId,
+			table.createdAt
+		),
+	})
 );
 
 export const s3Buckets = mysqlTable("s3_buckets", {
-  id: nanoId("id").notNull().primaryKey().unique(),
-  ownerId: nanoId("ownerId").notNull(),
-  // Use encryptedText for sensitive fields
-  region: encryptedText("region").notNull(),
-  endpoint: encryptedTextNullable("endpoint"),
-  bucketName: encryptedText("bucketName").notNull(),
-  accessKeyId: encryptedText("accessKeyId").notNull(),
-  secretAccessKey: encryptedText("secretAccessKey").notNull(),
-  provider: text("provider").notNull().default("aws"),
+	id: nanoId("id").notNull().primaryKey().unique(),
+	ownerId: nanoId("ownerId").notNull(),
+	// Use encryptedText for sensitive fields
+	region: encryptedText("region").notNull(),
+	endpoint: encryptedTextNullable("endpoint"),
+	bucketName: encryptedText("bucketName").notNull(),
+	accessKeyId: encryptedText("accessKeyId").notNull(),
+	secretAccessKey: encryptedText("secretAccessKey").notNull(),
+	provider: text("provider").notNull().default("aws"),
 });
 
 export const notificationsRelations = relations(notifications, ({ one }) => ({
-  org: one(organizations, {
-    fields: [notifications.orgId],
-    references: [organizations.id],
-  }),
-  recipient: one(users, {
-    fields: [notifications.recipientId],
-    references: [users.id],
-  }),
+	org: one(organizations, {
+		fields: [notifications.orgId],
+		references: [organizations.id],
+	}),
+	recipient: one(users, {
+		fields: [notifications.recipientId],
+		references: [users.id],
+	}),
 }));
 
 export const authApiKeys = mysqlTable("auth_api_keys", {
-  id: varchar("id", { length: 36 }).notNull().primaryKey().unique(),
-  userId: nanoId("userId").notNull(),
-  createdAt: timestamp("createdAt").defaultNow().notNull(),
+	id: varchar("id", { length: 36 }).notNull().primaryKey().unique(),
+	userId: nanoId("userId").notNull(),
+	createdAt: timestamp("createdAt").defaultNow().notNull(),
 });
 
 export const commentsRelations = relations(comments, ({ one }) => ({
-  author: one(users, {
-    fields: [comments.authorId],
-    references: [users.id],
-  }),
-  video: one(videos, {
-    fields: [comments.videoId],
-    references: [videos.id],
-  }),
-  parentComment: one(comments, {
-    fields: [comments.parentCommentId],
-    references: [comments.id],
-  }),
+	author: one(users, {
+		fields: [comments.authorId],
+		references: [users.id],
+	}),
+	video: one(videos, {
+		fields: [comments.videoId],
+		references: [videos.id],
+	}),
+	parentComment: one(comments, {
+		fields: [comments.parentCommentId],
+		references: [comments.id],
+	}),
 }));
 
 // Define Relationships
 export const usersRelations = relations(users, ({ many, one }) => ({
-  accounts: many(accounts),
-  sessions: many(sessions),
-  organizationMembers: many(organizationMembers),
-  videos: many(videos),
-  sharedVideos: many(sharedVideos),
-  customBucket: one(s3Buckets),
-  spaces: many(spaces),
-  spaceMembers: many(spaceMembers),
+	accounts: many(accounts),
+	sessions: many(sessions),
+	organizationMembers: many(organizationMembers),
+	videos: many(videos),
+	sharedVideos: many(sharedVideos),
+	customBucket: one(s3Buckets),
+	spaces: many(spaces),
+	spaceMembers: many(spaceMembers),
 }));
 
 export const accountsRelations = relations(accounts, ({ one }) => ({
-  user: one(users, {
-    fields: [accounts.userId],
-    references: [users.id],
-  }),
+	user: one(users, {
+		fields: [accounts.userId],
+		references: [users.id],
+	}),
 }));
 
 export const s3BucketsRelations = relations(s3Buckets, ({ one }) => ({
-  owner: one(users, {
-    fields: [s3Buckets.ownerId],
-    references: [users.id],
-  }),
+	owner: one(users, {
+		fields: [s3Buckets.ownerId],
+		references: [users.id],
+	}),
 }));
 
 export const organizationsRelations = relations(
-  organizations,
-  ({ one, many }) => ({
-    owner: one(users, {
-      fields: [organizations.ownerId],
-      references: [users.id],
-    }),
-    organizationMembers: many(organizationMembers),
-    sharedVideos: many(sharedVideos),
-    organizationInvites: many(organizationInvites),
-    spaces: many(spaces),
-  })
+	organizations,
+	({ one, many }) => ({
+		owner: one(users, {
+			fields: [organizations.ownerId],
+			references: [users.id],
+		}),
+		organizationMembers: many(organizationMembers),
+		sharedVideos: many(sharedVideos),
+		organizationInvites: many(organizationInvites),
+		spaces: many(spaces),
+	})
 );
 
 export const sessionsRelations = relations(sessions, ({ one }) => ({
-  user: one(users, {
-    fields: [sessions.userId],
-    references: [users.id],
-  }),
+	user: one(users, {
+		fields: [sessions.userId],
+		references: [users.id],
+	}),
 }));
 
 export const verificationTokensRelations = relations(
-  verificationTokens,
-  ({}) => ({
-    // No relations defined
-  })
+	verificationTokens,
+	({ }) => ({
+		// No relations defined
+	})
 );
 
 export const organizationMembersRelations = relations(
-  organizationMembers,
-  ({ one }) => ({
-    user: one(users, {
-      fields: [organizationMembers.userId],
-      references: [users.id],
-    }),
-    organization: one(organizations, {
-      fields: [organizationMembers.organizationId],
-      references: [organizations.id],
-    }),
-  })
+	organizationMembers,
+	({ one }) => ({
+		user: one(users, {
+			fields: [organizationMembers.userId],
+			references: [users.id],
+		}),
+		organization: one(organizations, {
+			fields: [organizationMembers.organizationId],
+			references: [organizations.id],
+		}),
+	})
 );
 
 export const organizationInvitesRelations = relations(
-  organizationInvites,
-  ({ one }) => ({
-    organization: one(organizations, {
-      fields: [organizationInvites.organizationId],
-      references: [organizations.id],
-    }),
-    invitedByUser: one(users, {
-      fields: [organizationInvites.invitedByUserId],
-      references: [users.id],
-    }),
-  })
+	organizationInvites,
+	({ one }) => ({
+		organization: one(organizations, {
+			fields: [organizationInvites.organizationId],
+			references: [organizations.id],
+		}),
+		invitedByUser: one(users, {
+			fields: [organizationInvites.invitedByUserId],
+			references: [users.id],
+		}),
+	})
 );
 
 export const videosRelations = relations(videos, ({ one, many }) => ({
-  owner: one(users, {
-    fields: [videos.ownerId],
-    references: [users.id],
-  }),
-  sharedVideos: many(sharedVideos),
-  spaceVideos: many(spaceVideos),
-  folder: one(folders, {
-    fields: [videos.folderId],
-    references: [folders.id],
-  }),
+	owner: one(users, {
+		fields: [videos.ownerId],
+		references: [users.id],
+	}),
+	sharedVideos: many(sharedVideos),
+	spaceVideos: many(spaceVideos),
+	folder: one(folders, {
+		fields: [videos.folderId],
+		references: [folders.id],
+	}),
 }));
 
 export const sharedVideosRelations = relations(sharedVideos, ({ one }) => ({
-  video: one(videos, {
-    fields: [sharedVideos.videoId],
-    references: [videos.id],
-  }),
-  organization: one(organizations, {
-    fields: [sharedVideos.organizationId],
-    references: [organizations.id],
-  }),
-  sharedByUser: one(users, {
-    fields: [sharedVideos.sharedByUserId],
-    references: [users.id],
-  }),
+	video: one(videos, {
+		fields: [sharedVideos.videoId],
+		references: [videos.id],
+	}),
+	organization: one(organizations, {
+		fields: [sharedVideos.organizationId],
+		references: [organizations.id],
+	}),
+	sharedByUser: one(users, {
+		fields: [sharedVideos.sharedByUserId],
+		references: [users.id],
+	}),
 }));
 
 export const spaces = mysqlTable(
-  "spaces",
-  {
-    id: nanoId("id").notNull().primaryKey().unique(),
-    primary: boolean("primary").notNull().default(false),
-    name: varchar("name", { length: 255 }).notNull(),
-    organizationId: nanoId("organizationId").notNull(),
-    createdById: nanoId("createdById").notNull(),
-    iconUrl: varchar("iconUrl", { length: 255 }),
-    description: varchar("description", { length: 1000 }),
-    createdAt: timestamp("createdAt").notNull().defaultNow(),
-    updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
-    privacy: varchar("privacy", { length: 255, enum: ["Public", "Private"] })
-      .notNull()
-      .default("Private"),
-  },
-  (table) => ({
-    organizationIdIndex: index("organization_id_idx").on(table.organizationId),
-    createdByIdIndex: index("created_by_id_idx").on(table.createdById),
-  })
+	"spaces",
+	{
+		id: nanoId("id").notNull().primaryKey().unique(),
+		primary: boolean("primary").notNull().default(false),
+		name: varchar("name", { length: 255 }).notNull(),
+		organizationId: nanoId("organizationId").notNull(),
+		createdById: nanoId("createdById").notNull(),
+		iconUrl: varchar("iconUrl", { length: 255 }),
+		description: varchar("description", { length: 1000 }),
+		createdAt: timestamp("createdAt").notNull().defaultNow(),
+		updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
+		privacy: varchar("privacy", { length: 255, enum: ["Public", "Private"] })
+			.notNull()
+			.default("Private"),
+	},
+	(table) => ({
+		organizationIdIndex: index("organization_id_idx").on(table.organizationId),
+		createdByIdIndex: index("created_by_id_idx").on(table.createdById),
+	})
 );
 
 export const spaceMembers = mysqlTable(
-  "space_members",
-  {
-    id: nanoId("id").notNull().primaryKey().unique(),
-    spaceId: nanoId("spaceId").notNull(),
-    userId: nanoId("userId").notNull(),
-    role: varchar("role", { length: 255 }).notNull().default("member"),
-    createdAt: timestamp("createdAt").notNull().defaultNow(),
-    updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
-  },
-  (table) => ({
-    spaceIdIndex: index("space_id_idx").on(table.spaceId),
-    userIdIndex: index("user_id_idx").on(table.userId),
-    spaceIdUserIdIndex: index("space_id_user_id_idx").on(
-      table.spaceId,
-      table.userId
-    ),
-  })
+	"space_members",
+	{
+		id: nanoId("id").notNull().primaryKey().unique(),
+		spaceId: nanoId("spaceId").notNull(),
+		userId: nanoId("userId").notNull(),
+		role: varchar("role", { length: 255 }).notNull().default("member"),
+		createdAt: timestamp("createdAt").notNull().defaultNow(),
+		updatedAt: timestamp("updatedAt").notNull().defaultNow().onUpdateNow(),
+	},
+	(table) => ({
+		spaceIdIndex: index("space_id_idx").on(table.spaceId),
+		userIdIndex: index("user_id_idx").on(table.userId),
+		spaceIdUserIdIndex: index("space_id_user_id_idx").on(
+			table.spaceId,
+			table.userId
+		),
+	})
 );
 
 export const spaceVideos = mysqlTable(
-  "space_videos",
-  {
-    id: nanoId("id").notNull().primaryKey().unique(),
-    spaceId: nanoId("spaceId").notNull(),
-    folderId: nanoIdNullable("folderId"),
-    videoId: nanoId("videoId").notNull(),
-    addedById: nanoId("addedById").notNull(),
-    addedAt: timestamp("addedAt").notNull().defaultNow(),
-  },
-  (table) => ({
-    spaceIdIndex: index("space_id_idx").on(table.spaceId),
-    folderIdIndex: index("folder_id_idx").on(table.folderId),
-    videoIdIndex: index("video_id_idx").on(table.videoId),
-    addedByIdIndex: index("added_by_id_idx").on(table.addedById),
-    spaceIdVideoIdIndex: index("space_id_video_id_idx").on(
-      table.spaceId,
-      table.videoId
-    ),
-  })
+	"space_videos",
+	{
+		id: nanoId("id").notNull().primaryKey().unique(),
+		spaceId: nanoId("spaceId").notNull(),
+		folderId: nanoIdNullable("folderId"),
+		videoId: nanoId("videoId").notNull(),
+		addedById: nanoId("addedById").notNull(),
+		addedAt: timestamp("addedAt").notNull().defaultNow(),
+	},
+	(table) => ({
+		spaceIdIndex: index("space_id_idx").on(table.spaceId),
+		folderIdIndex: index("folder_id_idx").on(table.folderId),
+		videoIdIndex: index("video_id_idx").on(table.videoId),
+		addedByIdIndex: index("added_by_id_idx").on(table.addedById),
+		spaceIdVideoIdIndex: index("space_id_video_id_idx").on(
+			table.spaceId,
+			table.videoId
+		),
+	})
 );
 
 export const spacesRelations = relations(spaces, ({ one, many }) => ({
-  organization: one(organizations, {
-    fields: [spaces.organizationId],
-    references: [organizations.id],
-  }),
-  createdBy: one(users, {
-    fields: [spaces.createdById],
-    references: [users.id],
-  }),
-  spaceMembers: many(spaceMembers),
-  spaceVideos: many(spaceVideos),
+	organization: one(organizations, {
+		fields: [spaces.organizationId],
+		references: [organizations.id],
+	}),
+	createdBy: one(users, {
+		fields: [spaces.createdById],
+		references: [users.id],
+	}),
+	spaceMembers: many(spaceMembers),
+	spaceVideos: many(spaceVideos),
 }));
 
 export const spaceMembersRelations = relations(spaceMembers, ({ one }) => ({
-  space: one(spaces, {
-    fields: [spaceMembers.spaceId],
-    references: [spaces.id],
-  }),
-  user: one(users, {
-    fields: [spaceMembers.userId],
-    references: [users.id],
-  }),
+	space: one(spaces, {
+		fields: [spaceMembers.spaceId],
+		references: [spaces.id],
+	}),
+	user: one(users, {
+		fields: [spaceMembers.userId],
+		references: [users.id],
+	}),
 }));
 
 export const spaceVideosRelations = relations(spaceVideos, ({ one }) => ({
-  space: one(spaces, {
-    fields: [spaceVideos.spaceId],
-    references: [spaces.id],
-  }),
-  video: one(videos, {
-    fields: [spaceVideos.videoId],
-    references: [videos.id],
-  }),
-  addedBy: one(users, {
-    fields: [spaceVideos.addedById],
-    references: [users.id],
-  }),
+	space: one(spaces, {
+		fields: [spaceVideos.spaceId],
+		references: [spaces.id],
+	}),
+	video: one(videos, {
+		fields: [spaceVideos.videoId],
+		references: [videos.id],
+	}),
+	addedBy: one(users, {
+		fields: [spaceVideos.addedById],
+		references: [users.id],
+	}),
 }));
 
 export const foldersRelations = relations(folders, ({ one, many }) => ({
-  organization: one(organizations, {
-    fields: [folders.organizationId],
-    references: [organizations.id],
-  }),
-  createdBy: one(users, {
-    fields: [folders.createdById],
-    references: [users.id],
-  }),
-  parentFolder: one(folders, {
-    fields: [folders.parentId],
-    references: [folders.id],
-    relationName: "parentChild",
-  }),
-  childFolders: many(folders, { relationName: "parentChild" }),
-  videos: many(videos),
+	organization: one(organizations, {
+		fields: [folders.organizationId],
+		references: [organizations.id],
+	}),
+	createdBy: one(users, {
+		fields: [folders.createdById],
+		references: [users.id],
+	}),
+	parentFolder: one(folders, {
+		fields: [folders.parentId],
+		references: [folders.id],
+		relationName: "parentChild",
+	}),
+	childFolders: many(folders, { relationName: "parentChild" }),
+	videos: many(videos),
 }));

From f8bb64f5b7d45488be52f51ed54383edcb521532 Mon Sep 17 00:00:00 2001
From: Brendan Allan <brendonovich@outlook.com>
Date: Wed, 20 Aug 2025 17:59:34 +0800
Subject: [PATCH 4/5] formatting

---
 apps/web/app/(org)/login/form.tsx             |    4 +-
 apps/web/app/(org)/verify-otp/form.tsx        |   12 +-
 apps/web/app/(org)/verify-otp/page.tsx        |   44 +-
 packages/database/auth/auth-options.tsx       |    9 +-
 packages/database/auth/drizzle-adapter.ts     |   16 +-
 packages/database/emails/otp-email.tsx        |  114 +-
 .../migrations/meta/0007_snapshot.json        | 3604 ++++++++---------
 .../database/migrations/meta/_journal.json    |  122 +-
 packages/database/schema.ts                   |   55 +-
 9 files changed, 1913 insertions(+), 2067 deletions(-)

diff --git a/apps/web/app/(org)/login/form.tsx b/apps/web/app/(org)/login/form.tsx
index b5c000ceac..c7b595df8b 100644
--- a/apps/web/app/(org)/login/form.tsx
+++ b/apps/web/app/(org)/login/form.tsx
@@ -13,12 +13,12 @@ import Cookies from "js-cookie";
 import { LucideArrowUpRight } from "lucide-react";
 import Image from "next/image";
 import Link from "next/link";
-import { useSearchParams, useRouter } from "next/navigation";
+import { useRouter, useSearchParams } from "next/navigation";
+import { signIn } from "next-auth/react";
 import { Suspense, useEffect, useState } from "react";
 import { toast } from "sonner";
 import { getOrganizationSSOData } from "@/actions/organization/get-organization-sso-data";
 import { trackEvent } from "@/app/utils/analytics";
-import { signIn } from "next-auth/react";
 
 const MotionInput = motion(Input);
 const MotionLogoBadge = motion(LogoBadge);
diff --git a/apps/web/app/(org)/verify-otp/form.tsx b/apps/web/app/(org)/verify-otp/form.tsx
index a86fe06510..8ed33dcdfe 100644
--- a/apps/web/app/(org)/verify-otp/form.tsx
+++ b/apps/web/app/(org)/verify-otp/form.tsx
@@ -1,15 +1,15 @@
 "use client";
 
-import { useState, useRef, useEffect } from "react";
 import { Button, LogoBadge } from "@cap/ui";
-import { motion } from "framer-motion";
-import { signIn } from "next-auth/react";
-import Link from "next/link";
-import { toast } from "sonner";
 import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { useRouter } from "next/navigation";
 import { useMutation } from "@tanstack/react-query";
+import { motion } from "framer-motion";
+import Link from "next/link";
+import { useRouter } from "next/navigation";
+import { signIn } from "next-auth/react";
+import { useEffect, useRef, useState } from "react";
+import { toast } from "sonner";
 
 export function VerifyOTPForm({
 	email,
diff --git a/apps/web/app/(org)/verify-otp/page.tsx b/apps/web/app/(org)/verify-otp/page.tsx
index ef64dd7e8e..7ef664dc63 100644
--- a/apps/web/app/(org)/verify-otp/page.tsx
+++ b/apps/web/app/(org)/verify-otp/page.tsx
@@ -1,32 +1,36 @@
+import { getSession } from "@cap/database/auth/session";
+import { redirect } from "next/navigation";
 import { Suspense } from "react";
 import { VerifyOTPForm } from "./form";
-import { redirect } from "next/navigation";
-import { getSession } from "@cap/database/auth/session";
 
 export const metadata = {
-  title: "Verify Code | Cap",
+	title: "Verify Code | Cap",
 };
 
 export default async function VerifyOTPPage({
-  searchParams,
+	searchParams,
 }: {
-  searchParams: { email?: string; next?: string; lastSent?: string };
+	searchParams: { email?: string; next?: string; lastSent?: string };
 }) {
-  const session = await getSession();
+	const session = await getSession();
 
-  if (session?.user) {
-    redirect(searchParams.next || "/dashboard");
-  }
+	if (session?.user) {
+		redirect(searchParams.next || "/dashboard");
+	}
 
-  if (!searchParams.email) {
-    redirect("/login");
-  }
+	if (!searchParams.email) {
+		redirect("/login");
+	}
 
-  return (
-    <div className="flex h-screen w-full items-center justify-center">
-      <Suspense fallback={null}>
-        <VerifyOTPForm email={searchParams.email} next={searchParams.next} lastSent={searchParams.lastSent} />
-      </Suspense>
-    </div>
-  );
-}
\ No newline at end of file
+	return (
+		<div className="flex h-screen w-full items-center justify-center">
+			<Suspense fallback={null}>
+				<VerifyOTPForm
+					email={searchParams.email}
+					next={searchParams.next}
+					lastSent={searchParams.lastSent}
+				/>
+			</Suspense>
+		</div>
+	);
+}
diff --git a/packages/database/auth/auth-options.tsx b/packages/database/auth/auth-options.tsx
index 1ef6c30632..85e0961b2a 100644
--- a/packages/database/auth/auth-options.tsx
+++ b/packages/database/auth/auth-options.tsx
@@ -1,4 +1,5 @@
 import { serverEnv } from "@cap/env";
+import crypto from "crypto";
 import { eq } from "drizzle-orm";
 import { cookies } from "next/headers";
 import type { NextAuthOptions } from "next-auth";
@@ -6,15 +7,13 @@ import { getServerSession as _getServerSession } from "next-auth";
 import type { Adapter } from "next-auth/adapters";
 import EmailProvider from "next-auth/providers/email";
 import GoogleProvider from "next-auth/providers/google";
-import WorkOSProvider from "next-auth/providers/workos";
 import type { Provider } from "next-auth/providers/index";
-import { dub } from "../dub";
-import crypto from "crypto";
-
+import WorkOSProvider from "next-auth/providers/workos";
 import { db } from "../";
+import { dub } from "../dub";
 import { sendEmail } from "../emails/config";
-import { organizationMembers, organizations, users } from "../schema";
 import { nanoId } from "../helpers";
+import { organizationMembers, organizations, users } from "../schema";
 import { DrizzleAdapter } from "./drizzle-adapter";
 
 export const config = {
diff --git a/packages/database/auth/drizzle-adapter.ts b/packages/database/auth/drizzle-adapter.ts
index 917eb3892c..3d1b6902dc 100644
--- a/packages/database/auth/drizzle-adapter.ts
+++ b/packages/database/auth/drizzle-adapter.ts
@@ -72,8 +72,8 @@ export function DrizzleAdapter(db: PlanetScaleDatabase): Adapter {
 				.where(
 					and(
 						eq(accounts.providerAccountId, providerAccountId),
-						eq(accounts.provider, provider)
-					)
+						eq(accounts.provider, provider),
+					),
 				)
 				.limit(1);
 			const row = rows[0];
@@ -116,8 +116,8 @@ export function DrizzleAdapter(db: PlanetScaleDatabase): Adapter {
 				.where(
 					and(
 						eq(accounts.providerAccountId, providerAccountId),
-						eq(accounts.provider, provider)
-					)
+						eq(accounts.provider, provider),
+					),
 				);
 		},
 		async createSession(data) {
@@ -201,7 +201,7 @@ export function DrizzleAdapter(db: PlanetScaleDatabase): Adapter {
 						// you may update other fields as necessary
 					})
 					.where(
-						eq(verificationTokens.identifier, verificationToken.identifier)
+						eq(verificationTokens.identifier, verificationToken.identifier),
 					);
 
 				// Return the updated token
@@ -209,7 +209,7 @@ export function DrizzleAdapter(db: PlanetScaleDatabase): Adapter {
 					.select()
 					.from(verificationTokens)
 					.where(
-						eq(verificationTokens.identifier, verificationToken.identifier)
+						eq(verificationTokens.identifier, verificationToken.identifier),
 					)
 					.limit(1)
 					.then((rows) => rows[0]);
@@ -245,8 +245,8 @@ export function DrizzleAdapter(db: PlanetScaleDatabase): Adapter {
 				.where(
 					and(
 						eq(verificationTokens.token, token),
-						eq(verificationTokens.identifier, identifier)
-					)
+						eq(verificationTokens.identifier, identifier),
+					),
 				);
 			return row;
 		},
diff --git a/packages/database/emails/otp-email.tsx b/packages/database/emails/otp-email.tsx
index a548c12239..0d61262266 100644
--- a/packages/database/emails/otp-email.tsx
+++ b/packages/database/emails/otp-email.tsx
@@ -1,64 +1,66 @@
 import { CAP_LOGO_URL } from "@cap/utils";
 import {
-  Body,
-  Container,
-  Head,
-  Heading,
-  Html,
-  Img,
-  Preview,
-  Section,
-  Tailwind,
-  Text,
+	Body,
+	Container,
+	Head,
+	Heading,
+	Html,
+	Img,
+	Preview,
+	Section,
+	Tailwind,
+	Text,
 } from "@react-email/components";
 import Footer from "./components/Footer";
 
 export function OTPEmail({
-  email = "",
-  code = "",
+	email = "",
+	code = "",
 }: {
-  email: string;
-  code: string;
+	email: string;
+	code: string;
 }) {
-  return (
-    <Html>
-      <Head />
-      <Preview>Your Cap Verification Code: {code}</Preview>
-      <Tailwind>
-        <Body className="mx-auto my-auto bg-gray-1 font-sans">
-          <Container className="mx-auto my-10 max-w-[500px] rounded border border-solid border-gray-200 px-10 py-5">
-            <Section className="mt-8">
-              <Img
-                src={CAP_LOGO_URL}
-                width="40"
-                height="40"
-                alt="Cap"
-                className="mx-auto my-0"
-              />
-            </Section>
-            <Heading className="mx-0 my-7 p-0 text-center text-xl font-semibold text-black">
-              Your Verification Code
-            </Heading>
-            <Text className="text-sm leading-6 text-black">
-              Welcome to Cap!
-            </Text>
-            <Text className="text-sm leading-6 text-black">
-              Please use the following verification code to sign in to your account:
-            </Text>
-            <Section className="my-8 text-center">
-              <div className="rounded-lg bg-gray-100 px-8 py-6">
-                <Text className="m-0 text-3xl font-bold tracking-wider text-black">
-                  {code}
-                </Text>
-              </div>
-            </Section>
-            <Text className="text-sm leading-6 text-black">
-              This code will expire in 10 minutes. If you didn't request this code, you can safely ignore this email.
-            </Text>
-            <Footer email={email} />
-          </Container>
-        </Body>
-      </Tailwind>
-    </Html>
-  );
-}
\ No newline at end of file
+	return (
+		<Html>
+			<Head />
+			<Preview>Your Cap Verification Code: {code}</Preview>
+			<Tailwind>
+				<Body className="mx-auto my-auto bg-gray-1 font-sans">
+					<Container className="mx-auto my-10 max-w-[500px] rounded border border-solid border-gray-200 px-10 py-5">
+						<Section className="mt-8">
+							<Img
+								src={CAP_LOGO_URL}
+								width="40"
+								height="40"
+								alt="Cap"
+								className="mx-auto my-0"
+							/>
+						</Section>
+						<Heading className="mx-0 my-7 p-0 text-center text-xl font-semibold text-black">
+							Your Verification Code
+						</Heading>
+						<Text className="text-sm leading-6 text-black">
+							Welcome to Cap!
+						</Text>
+						<Text className="text-sm leading-6 text-black">
+							Please use the following verification code to sign in to your
+							account:
+						</Text>
+						<Section className="my-8 text-center">
+							<div className="rounded-lg bg-gray-100 px-8 py-6">
+								<Text className="m-0 text-3xl font-bold tracking-wider text-black">
+									{code}
+								</Text>
+							</div>
+						</Section>
+						<Text className="text-sm leading-6 text-black">
+							This code will expire in 10 minutes. If you didn't request this
+							code, you can safely ignore this email.
+						</Text>
+						<Footer email={email} />
+					</Container>
+				</Body>
+			</Tailwind>
+		</Html>
+	);
+}
diff --git a/packages/database/migrations/meta/0007_snapshot.json b/packages/database/migrations/meta/0007_snapshot.json
index c4fefccaa8..6e45d78285 100644
--- a/packages/database/migrations/meta/0007_snapshot.json
+++ b/packages/database/migrations/meta/0007_snapshot.json
@@ -1,1883 +1,1723 @@
 {
-  "version": "5",
-  "dialect": "mysql",
-  "id": "308bd25e-8d1d-4bc6-ba35-880bf4d18a6d",
-  "prevId": "140a5aa9-5b37-4435-baeb-5fd016ef5c6e",
-  "tables": {
-    "accounts": {
-      "name": "accounts",
-      "columns": {
-        "id": {
-          "name": "id",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "userId": {
-          "name": "userId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "type": {
-          "name": "type",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "provider": {
-          "name": "provider",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "providerAccountId": {
-          "name": "providerAccountId",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "access_token": {
-          "name": "access_token",
-          "type": "text",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "expires_in": {
-          "name": "expires_in",
-          "type": "int",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "id_token": {
-          "name": "id_token",
-          "type": "text",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "refresh_token": {
-          "name": "refresh_token",
-          "type": "text",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "refresh_token_expires_in": {
-          "name": "refresh_token_expires_in",
-          "type": "int",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "scope": {
-          "name": "scope",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "token_type": {
-          "name": "token_type",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "createdAt": {
-          "name": "createdAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "(now())"
-        },
-        "updatedAt": {
-          "name": "updatedAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "onUpdate": true,
-          "default": "(now())"
-        },
-        "tempColumn": {
-          "name": "tempColumn",
-          "type": "text",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        }
-      },
-      "indexes": {
-        "user_id_idx": {
-          "name": "user_id_idx",
-          "columns": [
-            "userId"
-          ],
-          "isUnique": false
-        },
-        "provider_account_id_idx": {
-          "name": "provider_account_id_idx",
-          "columns": [
-            "providerAccountId"
-          ],
-          "isUnique": false
-        }
-      },
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "accounts_id": {
-          "name": "accounts_id",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "accounts_id_unique": {
-          "name": "accounts_id_unique",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    },
-    "auth_api_keys": {
-      "name": "auth_api_keys",
-      "columns": {
-        "id": {
-          "name": "id",
-          "type": "varchar(36)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "userId": {
-          "name": "userId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "createdAt": {
-          "name": "createdAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "(now())"
-        }
-      },
-      "indexes": {},
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "auth_api_keys_id": {
-          "name": "auth_api_keys_id",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "auth_api_keys_id_unique": {
-          "name": "auth_api_keys_id_unique",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    },
-    "comments": {
-      "name": "comments",
-      "columns": {
-        "id": {
-          "name": "id",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "type": {
-          "name": "type",
-          "type": "varchar(6)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "content": {
-          "name": "content",
-          "type": "text",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "timestamp": {
-          "name": "timestamp",
-          "type": "float",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "authorId": {
-          "name": "authorId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "videoId": {
-          "name": "videoId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "createdAt": {
-          "name": "createdAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "(now())"
-        },
-        "updatedAt": {
-          "name": "updatedAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "onUpdate": true,
-          "default": "(now())"
-        },
-        "parentCommentId": {
-          "name": "parentCommentId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        }
-      },
-      "indexes": {
-        "video_id_idx": {
-          "name": "video_id_idx",
-          "columns": [
-            "videoId"
-          ],
-          "isUnique": false
-        },
-        "author_id_idx": {
-          "name": "author_id_idx",
-          "columns": [
-            "authorId"
-          ],
-          "isUnique": false
-        },
-        "parent_comment_id_idx": {
-          "name": "parent_comment_id_idx",
-          "columns": [
-            "parentCommentId"
-          ],
-          "isUnique": false
-        }
-      },
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "comments_id": {
-          "name": "comments_id",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "comments_id_unique": {
-          "name": "comments_id_unique",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    },
-    "folders": {
-      "name": "folders",
-      "columns": {
-        "id": {
-          "name": "id",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "name": {
-          "name": "name",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "color": {
-          "name": "color",
-          "type": "varchar(16)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "'normal'"
-        },
-        "organizationId": {
-          "name": "organizationId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "createdById": {
-          "name": "createdById",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "parentId": {
-          "name": "parentId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "spaceId": {
-          "name": "spaceId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "createdAt": {
-          "name": "createdAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "(now())"
-        },
-        "updatedAt": {
-          "name": "updatedAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "onUpdate": true,
-          "default": "(now())"
-        }
-      },
-      "indexes": {
-        "organization_id_idx": {
-          "name": "organization_id_idx",
-          "columns": [
-            "organizationId"
-          ],
-          "isUnique": false
-        },
-        "created_by_id_idx": {
-          "name": "created_by_id_idx",
-          "columns": [
-            "createdById"
-          ],
-          "isUnique": false
-        },
-        "parent_id_idx": {
-          "name": "parent_id_idx",
-          "columns": [
-            "parentId"
-          ],
-          "isUnique": false
-        },
-        "space_id_idx": {
-          "name": "space_id_idx",
-          "columns": [
-            "spaceId"
-          ],
-          "isUnique": false
-        }
-      },
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "folders_id": {
-          "name": "folders_id",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "folders_id_unique": {
-          "name": "folders_id_unique",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    },
-    "organization_invites": {
-      "name": "organization_invites",
-      "columns": {
-        "id": {
-          "name": "id",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "organizationId": {
-          "name": "organizationId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "invitedEmail": {
-          "name": "invitedEmail",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "invitedByUserId": {
-          "name": "invitedByUserId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "role": {
-          "name": "role",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "status": {
-          "name": "status",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "'pending'"
-        },
-        "createdAt": {
-          "name": "createdAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "(now())"
-        },
-        "updatedAt": {
-          "name": "updatedAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "onUpdate": true,
-          "default": "(now())"
-        },
-        "expiresAt": {
-          "name": "expiresAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        }
-      },
-      "indexes": {
-        "organization_id_idx": {
-          "name": "organization_id_idx",
-          "columns": [
-            "organizationId"
-          ],
-          "isUnique": false
-        },
-        "invited_email_idx": {
-          "name": "invited_email_idx",
-          "columns": [
-            "invitedEmail"
-          ],
-          "isUnique": false
-        },
-        "invited_by_user_id_idx": {
-          "name": "invited_by_user_id_idx",
-          "columns": [
-            "invitedByUserId"
-          ],
-          "isUnique": false
-        },
-        "status_idx": {
-          "name": "status_idx",
-          "columns": [
-            "status"
-          ],
-          "isUnique": false
-        }
-      },
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "organization_invites_id": {
-          "name": "organization_invites_id",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "organization_invites_id_unique": {
-          "name": "organization_invites_id_unique",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    },
-    "organization_members": {
-      "name": "organization_members",
-      "columns": {
-        "id": {
-          "name": "id",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "userId": {
-          "name": "userId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "organizationId": {
-          "name": "organizationId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "role": {
-          "name": "role",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "createdAt": {
-          "name": "createdAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "(now())"
-        },
-        "updatedAt": {
-          "name": "updatedAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "onUpdate": true,
-          "default": "(now())"
-        }
-      },
-      "indexes": {
-        "user_id_idx": {
-          "name": "user_id_idx",
-          "columns": [
-            "userId"
-          ],
-          "isUnique": false
-        },
-        "organization_id_idx": {
-          "name": "organization_id_idx",
-          "columns": [
-            "organizationId"
-          ],
-          "isUnique": false
-        },
-        "user_id_organization_id_idx": {
-          "name": "user_id_organization_id_idx",
-          "columns": [
-            "userId",
-            "organizationId"
-          ],
-          "isUnique": false
-        }
-      },
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "organization_members_id": {
-          "name": "organization_members_id",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "organization_members_id_unique": {
-          "name": "organization_members_id_unique",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    },
-    "organizations": {
-      "name": "organizations",
-      "columns": {
-        "id": {
-          "name": "id",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "name": {
-          "name": "name",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "ownerId": {
-          "name": "ownerId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "metadata": {
-          "name": "metadata",
-          "type": "json",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "allowedEmailDomain": {
-          "name": "allowedEmailDomain",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "customDomain": {
-          "name": "customDomain",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "domainVerified": {
-          "name": "domainVerified",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "iconUrl": {
-          "name": "iconUrl",
-          "type": "varchar(1024)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "createdAt": {
-          "name": "createdAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "(now())"
-        },
-        "updatedAt": {
-          "name": "updatedAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "onUpdate": true,
-          "default": "(now())"
-        },
-        "workosOrganizationId": {
-          "name": "workosOrganizationId",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "workosConnectionId": {
-          "name": "workosConnectionId",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        }
-      },
-      "indexes": {
-        "owner_id_idx": {
-          "name": "owner_id_idx",
-          "columns": [
-            "ownerId"
-          ],
-          "isUnique": false
-        },
-        "custom_domain_idx": {
-          "name": "custom_domain_idx",
-          "columns": [
-            "customDomain"
-          ],
-          "isUnique": false
-        }
-      },
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "organizations_id": {
-          "name": "organizations_id",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "organizations_id_unique": {
-          "name": "organizations_id_unique",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    },
-    "otp_codes": {
-      "name": "otp_codes",
-      "columns": {
-        "id": {
-          "name": "id",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "identifier": {
-          "name": "identifier",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "code": {
-          "name": "code",
-          "type": "varchar(6)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "expires": {
-          "name": "expires",
-          "type": "datetime",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "attempts": {
-          "name": "attempts",
-          "type": "int",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": 0
-        },
-        "createdAt": {
-          "name": "createdAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "(now())"
-        },
-        "updatedAt": {
-          "name": "updatedAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "onUpdate": true,
-          "default": "(now())"
-        }
-      },
-      "indexes": {
-        "identifier_idx": {
-          "name": "identifier_idx",
-          "columns": [
-            "identifier"
-          ],
-          "isUnique": false
-        },
-        "code_idx": {
-          "name": "code_idx",
-          "columns": [
-            "code"
-          ],
-          "isUnique": false
-        },
-        "expires_idx": {
-          "name": "expires_idx",
-          "columns": [
-            "expires"
-          ],
-          "isUnique": false
-        }
-      },
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "otp_codes_id": {
-          "name": "otp_codes_id",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "otp_codes_id_unique": {
-          "name": "otp_codes_id_unique",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    },
-    "s3_buckets": {
-      "name": "s3_buckets",
-      "columns": {
-        "id": {
-          "name": "id",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "ownerId": {
-          "name": "ownerId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "region": {
-          "name": "region",
-          "type": "text",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "endpoint": {
-          "name": "endpoint",
-          "type": "text",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "bucketName": {
-          "name": "bucketName",
-          "type": "text",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "accessKeyId": {
-          "name": "accessKeyId",
-          "type": "text",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "secretAccessKey": {
-          "name": "secretAccessKey",
-          "type": "text",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "provider": {
-          "name": "provider",
-          "type": "text",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "('aws')"
-        }
-      },
-      "indexes": {},
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "s3_buckets_id": {
-          "name": "s3_buckets_id",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "s3_buckets_id_unique": {
-          "name": "s3_buckets_id_unique",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    },
-    "sessions": {
-      "name": "sessions",
-      "columns": {
-        "id": {
-          "name": "id",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "sessionToken": {
-          "name": "sessionToken",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "userId": {
-          "name": "userId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "expires": {
-          "name": "expires",
-          "type": "datetime",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "created_at": {
-          "name": "created_at",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "(now())"
-        },
-        "updated_at": {
-          "name": "updated_at",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "onUpdate": true,
-          "default": "(now())"
-        }
-      },
-      "indexes": {
-        "session_token_idx": {
-          "name": "session_token_idx",
-          "columns": [
-            "sessionToken"
-          ],
-          "isUnique": true
-        },
-        "user_id_idx": {
-          "name": "user_id_idx",
-          "columns": [
-            "userId"
-          ],
-          "isUnique": false
-        }
-      },
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "sessions_id": {
-          "name": "sessions_id",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "sessions_id_unique": {
-          "name": "sessions_id_unique",
-          "columns": [
-            "id"
-          ]
-        },
-        "sessions_sessionToken_unique": {
-          "name": "sessions_sessionToken_unique",
-          "columns": [
-            "sessionToken"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    },
-    "shared_videos": {
-      "name": "shared_videos",
-      "columns": {
-        "id": {
-          "name": "id",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "videoId": {
-          "name": "videoId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "organizationId": {
-          "name": "organizationId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "sharedByUserId": {
-          "name": "sharedByUserId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "sharedAt": {
-          "name": "sharedAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "(now())"
-        }
-      },
-      "indexes": {
-        "video_id_idx": {
-          "name": "video_id_idx",
-          "columns": [
-            "videoId"
-          ],
-          "isUnique": false
-        },
-        "organization_id_idx": {
-          "name": "organization_id_idx",
-          "columns": [
-            "organizationId"
-          ],
-          "isUnique": false
-        },
-        "shared_by_user_id_idx": {
-          "name": "shared_by_user_id_idx",
-          "columns": [
-            "sharedByUserId"
-          ],
-          "isUnique": false
-        },
-        "video_id_organization_id_idx": {
-          "name": "video_id_organization_id_idx",
-          "columns": [
-            "videoId",
-            "organizationId"
-          ],
-          "isUnique": false
-        }
-      },
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "shared_videos_id": {
-          "name": "shared_videos_id",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "shared_videos_id_unique": {
-          "name": "shared_videos_id_unique",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    },
-    "space_members": {
-      "name": "space_members",
-      "columns": {
-        "id": {
-          "name": "id",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "spaceId": {
-          "name": "spaceId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "userId": {
-          "name": "userId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "role": {
-          "name": "role",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "'member'"
-        },
-        "createdAt": {
-          "name": "createdAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "(now())"
-        },
-        "updatedAt": {
-          "name": "updatedAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "onUpdate": true,
-          "default": "(now())"
-        }
-      },
-      "indexes": {
-        "space_id_idx": {
-          "name": "space_id_idx",
-          "columns": [
-            "spaceId"
-          ],
-          "isUnique": false
-        },
-        "user_id_idx": {
-          "name": "user_id_idx",
-          "columns": [
-            "userId"
-          ],
-          "isUnique": false
-        },
-        "space_id_user_id_idx": {
-          "name": "space_id_user_id_idx",
-          "columns": [
-            "spaceId",
-            "userId"
-          ],
-          "isUnique": false
-        }
-      },
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "space_members_id": {
-          "name": "space_members_id",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "space_members_id_unique": {
-          "name": "space_members_id_unique",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    },
-    "space_videos": {
-      "name": "space_videos",
-      "columns": {
-        "id": {
-          "name": "id",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "spaceId": {
-          "name": "spaceId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "folderId": {
-          "name": "folderId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "videoId": {
-          "name": "videoId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "addedById": {
-          "name": "addedById",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "addedAt": {
-          "name": "addedAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "(now())"
-        }
-      },
-      "indexes": {
-        "space_id_idx": {
-          "name": "space_id_idx",
-          "columns": [
-            "spaceId"
-          ],
-          "isUnique": false
-        },
-        "folder_id_idx": {
-          "name": "folder_id_idx",
-          "columns": [
-            "folderId"
-          ],
-          "isUnique": false
-        },
-        "video_id_idx": {
-          "name": "video_id_idx",
-          "columns": [
-            "videoId"
-          ],
-          "isUnique": false
-        },
-        "added_by_id_idx": {
-          "name": "added_by_id_idx",
-          "columns": [
-            "addedById"
-          ],
-          "isUnique": false
-        },
-        "space_id_video_id_idx": {
-          "name": "space_id_video_id_idx",
-          "columns": [
-            "spaceId",
-            "videoId"
-          ],
-          "isUnique": false
-        }
-      },
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "space_videos_id": {
-          "name": "space_videos_id",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "space_videos_id_unique": {
-          "name": "space_videos_id_unique",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    },
-    "spaces": {
-      "name": "spaces",
-      "columns": {
-        "id": {
-          "name": "id",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "primary": {
-          "name": "primary",
-          "type": "boolean",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": false
-        },
-        "name": {
-          "name": "name",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "organizationId": {
-          "name": "organizationId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "createdById": {
-          "name": "createdById",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "iconUrl": {
-          "name": "iconUrl",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "description": {
-          "name": "description",
-          "type": "varchar(1000)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "createdAt": {
-          "name": "createdAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "(now())"
-        },
-        "updatedAt": {
-          "name": "updatedAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "onUpdate": true,
-          "default": "(now())"
-        },
-        "privacy": {
-          "name": "privacy",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "'Private'"
-        }
-      },
-      "indexes": {
-        "organization_id_idx": {
-          "name": "organization_id_idx",
-          "columns": [
-            "organizationId"
-          ],
-          "isUnique": false
-        },
-        "created_by_id_idx": {
-          "name": "created_by_id_idx",
-          "columns": [
-            "createdById"
-          ],
-          "isUnique": false
-        }
-      },
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "spaces_id": {
-          "name": "spaces_id",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "spaces_id_unique": {
-          "name": "spaces_id_unique",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    },
-    "users": {
-      "name": "users",
-      "columns": {
-        "id": {
-          "name": "id",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "name": {
-          "name": "name",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "lastName": {
-          "name": "lastName",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "email": {
-          "name": "email",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "emailVerified": {
-          "name": "emailVerified",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "image": {
-          "name": "image",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "stripeCustomerId": {
-          "name": "stripeCustomerId",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "stripeSubscriptionId": {
-          "name": "stripeSubscriptionId",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "thirdPartyStripeSubscriptionId": {
-          "name": "thirdPartyStripeSubscriptionId",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "stripeSubscriptionStatus": {
-          "name": "stripeSubscriptionStatus",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "stripeSubscriptionPriceId": {
-          "name": "stripeSubscriptionPriceId",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "activeOrganizationId": {
-          "name": "activeOrganizationId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "created_at": {
-          "name": "created_at",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "(now())"
-        },
-        "updated_at": {
-          "name": "updated_at",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "onUpdate": true,
-          "default": "(now())"
-        },
-        "onboarding_completed_at": {
-          "name": "onboarding_completed_at",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "customBucket": {
-          "name": "customBucket",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "inviteQuota": {
-          "name": "inviteQuota",
-          "type": "int",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": 1
-        }
-      },
-      "indexes": {
-        "email_idx": {
-          "name": "email_idx",
-          "columns": [
-            "email"
-          ],
-          "isUnique": true
-        }
-      },
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "users_id": {
-          "name": "users_id",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "users_id_unique": {
-          "name": "users_id_unique",
-          "columns": [
-            "id"
-          ]
-        },
-        "users_email_unique": {
-          "name": "users_email_unique",
-          "columns": [
-            "email"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    },
-    "verification_tokens": {
-      "name": "verification_tokens",
-      "columns": {
-        "identifier": {
-          "name": "identifier",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "token": {
-          "name": "token",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "expires": {
-          "name": "expires",
-          "type": "datetime",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "created_at": {
-          "name": "created_at",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "(now())"
-        },
-        "updated_at": {
-          "name": "updated_at",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "onUpdate": true,
-          "default": "(now())"
-        }
-      },
-      "indexes": {},
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "verification_tokens_identifier": {
-          "name": "verification_tokens_identifier",
-          "columns": [
-            "identifier"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "verification_tokens_token_unique": {
-          "name": "verification_tokens_token_unique",
-          "columns": [
-            "token"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    },
-    "videos": {
-      "name": "videos",
-      "columns": {
-        "id": {
-          "name": "id",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "ownerId": {
-          "name": "ownerId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false
-        },
-        "name": {
-          "name": "name",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "'My Video'"
-        },
-        "awsRegion": {
-          "name": "awsRegion",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "awsBucket": {
-          "name": "awsBucket",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "bucket": {
-          "name": "bucket",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "metadata": {
-          "name": "metadata",
-          "type": "json",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "public": {
-          "name": "public",
-          "type": "boolean",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": true
-        },
-        "password": {
-          "name": "password",
-          "type": "text",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "videoStartTime": {
-          "name": "videoStartTime",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "audioStartTime": {
-          "name": "audioStartTime",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "xStreamInfo": {
-          "name": "xStreamInfo",
-          "type": "text",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "jobId": {
-          "name": "jobId",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "jobStatus": {
-          "name": "jobStatus",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "isScreenshot": {
-          "name": "isScreenshot",
-          "type": "boolean",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": false
-        },
-        "skipProcessing": {
-          "name": "skipProcessing",
-          "type": "boolean",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": false
-        },
-        "transcriptionStatus": {
-          "name": "transcriptionStatus",
-          "type": "varchar(255)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        },
-        "createdAt": {
-          "name": "createdAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "(now())"
-        },
-        "updatedAt": {
-          "name": "updatedAt",
-          "type": "timestamp",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "onUpdate": true,
-          "default": "(now())"
-        },
-        "source": {
-          "name": "source",
-          "type": "json",
-          "primaryKey": false,
-          "notNull": true,
-          "autoincrement": false,
-          "default": "('{\"type\":\"MediaConvert\"}')"
-        },
-        "folderId": {
-          "name": "folderId",
-          "type": "varchar(15)",
-          "primaryKey": false,
-          "notNull": false,
-          "autoincrement": false
-        }
-      },
-      "indexes": {
-        "id_idx": {
-          "name": "id_idx",
-          "columns": [
-            "id"
-          ],
-          "isUnique": false
-        },
-        "owner_id_idx": {
-          "name": "owner_id_idx",
-          "columns": [
-            "ownerId"
-          ],
-          "isUnique": false
-        },
-        "is_public_idx": {
-          "name": "is_public_idx",
-          "columns": [
-            "public"
-          ],
-          "isUnique": false
-        },
-        "folder_id_idx": {
-          "name": "folder_id_idx",
-          "columns": [
-            "folderId"
-          ],
-          "isUnique": false
-        }
-      },
-      "foreignKeys": {},
-      "compositePrimaryKeys": {
-        "videos_id": {
-          "name": "videos_id",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "uniqueConstraints": {
-        "videos_id_unique": {
-          "name": "videos_id_unique",
-          "columns": [
-            "id"
-          ]
-        }
-      },
-      "checkConstraint": {}
-    }
-  },
-  "views": {},
-  "_meta": {
-    "schemas": {},
-    "tables": {},
-    "columns": {}
-  },
-  "internal": {
-    "tables": {},
-    "indexes": {}
-  }
-}
\ No newline at end of file
+	"version": "5",
+	"dialect": "mysql",
+	"id": "308bd25e-8d1d-4bc6-ba35-880bf4d18a6d",
+	"prevId": "140a5aa9-5b37-4435-baeb-5fd016ef5c6e",
+	"tables": {
+		"accounts": {
+			"name": "accounts",
+			"columns": {
+				"id": {
+					"name": "id",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"userId": {
+					"name": "userId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"type": {
+					"name": "type",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"provider": {
+					"name": "provider",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"providerAccountId": {
+					"name": "providerAccountId",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"access_token": {
+					"name": "access_token",
+					"type": "text",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"expires_in": {
+					"name": "expires_in",
+					"type": "int",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"id_token": {
+					"name": "id_token",
+					"type": "text",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"refresh_token": {
+					"name": "refresh_token",
+					"type": "text",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"refresh_token_expires_in": {
+					"name": "refresh_token_expires_in",
+					"type": "int",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"scope": {
+					"name": "scope",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"token_type": {
+					"name": "token_type",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"createdAt": {
+					"name": "createdAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "(now())"
+				},
+				"updatedAt": {
+					"name": "updatedAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"onUpdate": true,
+					"default": "(now())"
+				},
+				"tempColumn": {
+					"name": "tempColumn",
+					"type": "text",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				}
+			},
+			"indexes": {
+				"user_id_idx": {
+					"name": "user_id_idx",
+					"columns": ["userId"],
+					"isUnique": false
+				},
+				"provider_account_id_idx": {
+					"name": "provider_account_id_idx",
+					"columns": ["providerAccountId"],
+					"isUnique": false
+				}
+			},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"accounts_id": {
+					"name": "accounts_id",
+					"columns": ["id"]
+				}
+			},
+			"uniqueConstraints": {
+				"accounts_id_unique": {
+					"name": "accounts_id_unique",
+					"columns": ["id"]
+				}
+			},
+			"checkConstraint": {}
+		},
+		"auth_api_keys": {
+			"name": "auth_api_keys",
+			"columns": {
+				"id": {
+					"name": "id",
+					"type": "varchar(36)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"userId": {
+					"name": "userId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"createdAt": {
+					"name": "createdAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "(now())"
+				}
+			},
+			"indexes": {},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"auth_api_keys_id": {
+					"name": "auth_api_keys_id",
+					"columns": ["id"]
+				}
+			},
+			"uniqueConstraints": {
+				"auth_api_keys_id_unique": {
+					"name": "auth_api_keys_id_unique",
+					"columns": ["id"]
+				}
+			},
+			"checkConstraint": {}
+		},
+		"comments": {
+			"name": "comments",
+			"columns": {
+				"id": {
+					"name": "id",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"type": {
+					"name": "type",
+					"type": "varchar(6)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"content": {
+					"name": "content",
+					"type": "text",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"timestamp": {
+					"name": "timestamp",
+					"type": "float",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"authorId": {
+					"name": "authorId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"videoId": {
+					"name": "videoId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"createdAt": {
+					"name": "createdAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "(now())"
+				},
+				"updatedAt": {
+					"name": "updatedAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"onUpdate": true,
+					"default": "(now())"
+				},
+				"parentCommentId": {
+					"name": "parentCommentId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				}
+			},
+			"indexes": {
+				"video_id_idx": {
+					"name": "video_id_idx",
+					"columns": ["videoId"],
+					"isUnique": false
+				},
+				"author_id_idx": {
+					"name": "author_id_idx",
+					"columns": ["authorId"],
+					"isUnique": false
+				},
+				"parent_comment_id_idx": {
+					"name": "parent_comment_id_idx",
+					"columns": ["parentCommentId"],
+					"isUnique": false
+				}
+			},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"comments_id": {
+					"name": "comments_id",
+					"columns": ["id"]
+				}
+			},
+			"uniqueConstraints": {
+				"comments_id_unique": {
+					"name": "comments_id_unique",
+					"columns": ["id"]
+				}
+			},
+			"checkConstraint": {}
+		},
+		"folders": {
+			"name": "folders",
+			"columns": {
+				"id": {
+					"name": "id",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"name": {
+					"name": "name",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"color": {
+					"name": "color",
+					"type": "varchar(16)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "'normal'"
+				},
+				"organizationId": {
+					"name": "organizationId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"createdById": {
+					"name": "createdById",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"parentId": {
+					"name": "parentId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"spaceId": {
+					"name": "spaceId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"createdAt": {
+					"name": "createdAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "(now())"
+				},
+				"updatedAt": {
+					"name": "updatedAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"onUpdate": true,
+					"default": "(now())"
+				}
+			},
+			"indexes": {
+				"organization_id_idx": {
+					"name": "organization_id_idx",
+					"columns": ["organizationId"],
+					"isUnique": false
+				},
+				"created_by_id_idx": {
+					"name": "created_by_id_idx",
+					"columns": ["createdById"],
+					"isUnique": false
+				},
+				"parent_id_idx": {
+					"name": "parent_id_idx",
+					"columns": ["parentId"],
+					"isUnique": false
+				},
+				"space_id_idx": {
+					"name": "space_id_idx",
+					"columns": ["spaceId"],
+					"isUnique": false
+				}
+			},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"folders_id": {
+					"name": "folders_id",
+					"columns": ["id"]
+				}
+			},
+			"uniqueConstraints": {
+				"folders_id_unique": {
+					"name": "folders_id_unique",
+					"columns": ["id"]
+				}
+			},
+			"checkConstraint": {}
+		},
+		"organization_invites": {
+			"name": "organization_invites",
+			"columns": {
+				"id": {
+					"name": "id",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"organizationId": {
+					"name": "organizationId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"invitedEmail": {
+					"name": "invitedEmail",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"invitedByUserId": {
+					"name": "invitedByUserId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"role": {
+					"name": "role",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"status": {
+					"name": "status",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "'pending'"
+				},
+				"createdAt": {
+					"name": "createdAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "(now())"
+				},
+				"updatedAt": {
+					"name": "updatedAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"onUpdate": true,
+					"default": "(now())"
+				},
+				"expiresAt": {
+					"name": "expiresAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				}
+			},
+			"indexes": {
+				"organization_id_idx": {
+					"name": "organization_id_idx",
+					"columns": ["organizationId"],
+					"isUnique": false
+				},
+				"invited_email_idx": {
+					"name": "invited_email_idx",
+					"columns": ["invitedEmail"],
+					"isUnique": false
+				},
+				"invited_by_user_id_idx": {
+					"name": "invited_by_user_id_idx",
+					"columns": ["invitedByUserId"],
+					"isUnique": false
+				},
+				"status_idx": {
+					"name": "status_idx",
+					"columns": ["status"],
+					"isUnique": false
+				}
+			},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"organization_invites_id": {
+					"name": "organization_invites_id",
+					"columns": ["id"]
+				}
+			},
+			"uniqueConstraints": {
+				"organization_invites_id_unique": {
+					"name": "organization_invites_id_unique",
+					"columns": ["id"]
+				}
+			},
+			"checkConstraint": {}
+		},
+		"organization_members": {
+			"name": "organization_members",
+			"columns": {
+				"id": {
+					"name": "id",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"userId": {
+					"name": "userId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"organizationId": {
+					"name": "organizationId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"role": {
+					"name": "role",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"createdAt": {
+					"name": "createdAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "(now())"
+				},
+				"updatedAt": {
+					"name": "updatedAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"onUpdate": true,
+					"default": "(now())"
+				}
+			},
+			"indexes": {
+				"user_id_idx": {
+					"name": "user_id_idx",
+					"columns": ["userId"],
+					"isUnique": false
+				},
+				"organization_id_idx": {
+					"name": "organization_id_idx",
+					"columns": ["organizationId"],
+					"isUnique": false
+				},
+				"user_id_organization_id_idx": {
+					"name": "user_id_organization_id_idx",
+					"columns": ["userId", "organizationId"],
+					"isUnique": false
+				}
+			},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"organization_members_id": {
+					"name": "organization_members_id",
+					"columns": ["id"]
+				}
+			},
+			"uniqueConstraints": {
+				"organization_members_id_unique": {
+					"name": "organization_members_id_unique",
+					"columns": ["id"]
+				}
+			},
+			"checkConstraint": {}
+		},
+		"organizations": {
+			"name": "organizations",
+			"columns": {
+				"id": {
+					"name": "id",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"name": {
+					"name": "name",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"ownerId": {
+					"name": "ownerId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"metadata": {
+					"name": "metadata",
+					"type": "json",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"allowedEmailDomain": {
+					"name": "allowedEmailDomain",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"customDomain": {
+					"name": "customDomain",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"domainVerified": {
+					"name": "domainVerified",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"iconUrl": {
+					"name": "iconUrl",
+					"type": "varchar(1024)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"createdAt": {
+					"name": "createdAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "(now())"
+				},
+				"updatedAt": {
+					"name": "updatedAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"onUpdate": true,
+					"default": "(now())"
+				},
+				"workosOrganizationId": {
+					"name": "workosOrganizationId",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"workosConnectionId": {
+					"name": "workosConnectionId",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				}
+			},
+			"indexes": {
+				"owner_id_idx": {
+					"name": "owner_id_idx",
+					"columns": ["ownerId"],
+					"isUnique": false
+				},
+				"custom_domain_idx": {
+					"name": "custom_domain_idx",
+					"columns": ["customDomain"],
+					"isUnique": false
+				}
+			},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"organizations_id": {
+					"name": "organizations_id",
+					"columns": ["id"]
+				}
+			},
+			"uniqueConstraints": {
+				"organizations_id_unique": {
+					"name": "organizations_id_unique",
+					"columns": ["id"]
+				}
+			},
+			"checkConstraint": {}
+		},
+		"otp_codes": {
+			"name": "otp_codes",
+			"columns": {
+				"id": {
+					"name": "id",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"identifier": {
+					"name": "identifier",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"code": {
+					"name": "code",
+					"type": "varchar(6)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"expires": {
+					"name": "expires",
+					"type": "datetime",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"attempts": {
+					"name": "attempts",
+					"type": "int",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": 0
+				},
+				"createdAt": {
+					"name": "createdAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "(now())"
+				},
+				"updatedAt": {
+					"name": "updatedAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"onUpdate": true,
+					"default": "(now())"
+				}
+			},
+			"indexes": {
+				"identifier_idx": {
+					"name": "identifier_idx",
+					"columns": ["identifier"],
+					"isUnique": false
+				},
+				"code_idx": {
+					"name": "code_idx",
+					"columns": ["code"],
+					"isUnique": false
+				},
+				"expires_idx": {
+					"name": "expires_idx",
+					"columns": ["expires"],
+					"isUnique": false
+				}
+			},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"otp_codes_id": {
+					"name": "otp_codes_id",
+					"columns": ["id"]
+				}
+			},
+			"uniqueConstraints": {
+				"otp_codes_id_unique": {
+					"name": "otp_codes_id_unique",
+					"columns": ["id"]
+				}
+			},
+			"checkConstraint": {}
+		},
+		"s3_buckets": {
+			"name": "s3_buckets",
+			"columns": {
+				"id": {
+					"name": "id",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"ownerId": {
+					"name": "ownerId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"region": {
+					"name": "region",
+					"type": "text",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"endpoint": {
+					"name": "endpoint",
+					"type": "text",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"bucketName": {
+					"name": "bucketName",
+					"type": "text",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"accessKeyId": {
+					"name": "accessKeyId",
+					"type": "text",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"secretAccessKey": {
+					"name": "secretAccessKey",
+					"type": "text",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"provider": {
+					"name": "provider",
+					"type": "text",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "('aws')"
+				}
+			},
+			"indexes": {},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"s3_buckets_id": {
+					"name": "s3_buckets_id",
+					"columns": ["id"]
+				}
+			},
+			"uniqueConstraints": {
+				"s3_buckets_id_unique": {
+					"name": "s3_buckets_id_unique",
+					"columns": ["id"]
+				}
+			},
+			"checkConstraint": {}
+		},
+		"sessions": {
+			"name": "sessions",
+			"columns": {
+				"id": {
+					"name": "id",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"sessionToken": {
+					"name": "sessionToken",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"userId": {
+					"name": "userId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"expires": {
+					"name": "expires",
+					"type": "datetime",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"created_at": {
+					"name": "created_at",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "(now())"
+				},
+				"updated_at": {
+					"name": "updated_at",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"onUpdate": true,
+					"default": "(now())"
+				}
+			},
+			"indexes": {
+				"session_token_idx": {
+					"name": "session_token_idx",
+					"columns": ["sessionToken"],
+					"isUnique": true
+				},
+				"user_id_idx": {
+					"name": "user_id_idx",
+					"columns": ["userId"],
+					"isUnique": false
+				}
+			},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"sessions_id": {
+					"name": "sessions_id",
+					"columns": ["id"]
+				}
+			},
+			"uniqueConstraints": {
+				"sessions_id_unique": {
+					"name": "sessions_id_unique",
+					"columns": ["id"]
+				},
+				"sessions_sessionToken_unique": {
+					"name": "sessions_sessionToken_unique",
+					"columns": ["sessionToken"]
+				}
+			},
+			"checkConstraint": {}
+		},
+		"shared_videos": {
+			"name": "shared_videos",
+			"columns": {
+				"id": {
+					"name": "id",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"videoId": {
+					"name": "videoId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"organizationId": {
+					"name": "organizationId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"sharedByUserId": {
+					"name": "sharedByUserId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"sharedAt": {
+					"name": "sharedAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "(now())"
+				}
+			},
+			"indexes": {
+				"video_id_idx": {
+					"name": "video_id_idx",
+					"columns": ["videoId"],
+					"isUnique": false
+				},
+				"organization_id_idx": {
+					"name": "organization_id_idx",
+					"columns": ["organizationId"],
+					"isUnique": false
+				},
+				"shared_by_user_id_idx": {
+					"name": "shared_by_user_id_idx",
+					"columns": ["sharedByUserId"],
+					"isUnique": false
+				},
+				"video_id_organization_id_idx": {
+					"name": "video_id_organization_id_idx",
+					"columns": ["videoId", "organizationId"],
+					"isUnique": false
+				}
+			},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"shared_videos_id": {
+					"name": "shared_videos_id",
+					"columns": ["id"]
+				}
+			},
+			"uniqueConstraints": {
+				"shared_videos_id_unique": {
+					"name": "shared_videos_id_unique",
+					"columns": ["id"]
+				}
+			},
+			"checkConstraint": {}
+		},
+		"space_members": {
+			"name": "space_members",
+			"columns": {
+				"id": {
+					"name": "id",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"spaceId": {
+					"name": "spaceId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"userId": {
+					"name": "userId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"role": {
+					"name": "role",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "'member'"
+				},
+				"createdAt": {
+					"name": "createdAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "(now())"
+				},
+				"updatedAt": {
+					"name": "updatedAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"onUpdate": true,
+					"default": "(now())"
+				}
+			},
+			"indexes": {
+				"space_id_idx": {
+					"name": "space_id_idx",
+					"columns": ["spaceId"],
+					"isUnique": false
+				},
+				"user_id_idx": {
+					"name": "user_id_idx",
+					"columns": ["userId"],
+					"isUnique": false
+				},
+				"space_id_user_id_idx": {
+					"name": "space_id_user_id_idx",
+					"columns": ["spaceId", "userId"],
+					"isUnique": false
+				}
+			},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"space_members_id": {
+					"name": "space_members_id",
+					"columns": ["id"]
+				}
+			},
+			"uniqueConstraints": {
+				"space_members_id_unique": {
+					"name": "space_members_id_unique",
+					"columns": ["id"]
+				}
+			},
+			"checkConstraint": {}
+		},
+		"space_videos": {
+			"name": "space_videos",
+			"columns": {
+				"id": {
+					"name": "id",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"spaceId": {
+					"name": "spaceId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"folderId": {
+					"name": "folderId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"videoId": {
+					"name": "videoId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"addedById": {
+					"name": "addedById",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"addedAt": {
+					"name": "addedAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "(now())"
+				}
+			},
+			"indexes": {
+				"space_id_idx": {
+					"name": "space_id_idx",
+					"columns": ["spaceId"],
+					"isUnique": false
+				},
+				"folder_id_idx": {
+					"name": "folder_id_idx",
+					"columns": ["folderId"],
+					"isUnique": false
+				},
+				"video_id_idx": {
+					"name": "video_id_idx",
+					"columns": ["videoId"],
+					"isUnique": false
+				},
+				"added_by_id_idx": {
+					"name": "added_by_id_idx",
+					"columns": ["addedById"],
+					"isUnique": false
+				},
+				"space_id_video_id_idx": {
+					"name": "space_id_video_id_idx",
+					"columns": ["spaceId", "videoId"],
+					"isUnique": false
+				}
+			},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"space_videos_id": {
+					"name": "space_videos_id",
+					"columns": ["id"]
+				}
+			},
+			"uniqueConstraints": {
+				"space_videos_id_unique": {
+					"name": "space_videos_id_unique",
+					"columns": ["id"]
+				}
+			},
+			"checkConstraint": {}
+		},
+		"spaces": {
+			"name": "spaces",
+			"columns": {
+				"id": {
+					"name": "id",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"primary": {
+					"name": "primary",
+					"type": "boolean",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": false
+				},
+				"name": {
+					"name": "name",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"organizationId": {
+					"name": "organizationId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"createdById": {
+					"name": "createdById",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"iconUrl": {
+					"name": "iconUrl",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"description": {
+					"name": "description",
+					"type": "varchar(1000)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"createdAt": {
+					"name": "createdAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "(now())"
+				},
+				"updatedAt": {
+					"name": "updatedAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"onUpdate": true,
+					"default": "(now())"
+				},
+				"privacy": {
+					"name": "privacy",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "'Private'"
+				}
+			},
+			"indexes": {
+				"organization_id_idx": {
+					"name": "organization_id_idx",
+					"columns": ["organizationId"],
+					"isUnique": false
+				},
+				"created_by_id_idx": {
+					"name": "created_by_id_idx",
+					"columns": ["createdById"],
+					"isUnique": false
+				}
+			},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"spaces_id": {
+					"name": "spaces_id",
+					"columns": ["id"]
+				}
+			},
+			"uniqueConstraints": {
+				"spaces_id_unique": {
+					"name": "spaces_id_unique",
+					"columns": ["id"]
+				}
+			},
+			"checkConstraint": {}
+		},
+		"users": {
+			"name": "users",
+			"columns": {
+				"id": {
+					"name": "id",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"name": {
+					"name": "name",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"lastName": {
+					"name": "lastName",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"email": {
+					"name": "email",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"emailVerified": {
+					"name": "emailVerified",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"image": {
+					"name": "image",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"stripeCustomerId": {
+					"name": "stripeCustomerId",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"stripeSubscriptionId": {
+					"name": "stripeSubscriptionId",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"thirdPartyStripeSubscriptionId": {
+					"name": "thirdPartyStripeSubscriptionId",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"stripeSubscriptionStatus": {
+					"name": "stripeSubscriptionStatus",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"stripeSubscriptionPriceId": {
+					"name": "stripeSubscriptionPriceId",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"activeOrganizationId": {
+					"name": "activeOrganizationId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"created_at": {
+					"name": "created_at",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "(now())"
+				},
+				"updated_at": {
+					"name": "updated_at",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"onUpdate": true,
+					"default": "(now())"
+				},
+				"onboarding_completed_at": {
+					"name": "onboarding_completed_at",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"customBucket": {
+					"name": "customBucket",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"inviteQuota": {
+					"name": "inviteQuota",
+					"type": "int",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": 1
+				}
+			},
+			"indexes": {
+				"email_idx": {
+					"name": "email_idx",
+					"columns": ["email"],
+					"isUnique": true
+				}
+			},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"users_id": {
+					"name": "users_id",
+					"columns": ["id"]
+				}
+			},
+			"uniqueConstraints": {
+				"users_id_unique": {
+					"name": "users_id_unique",
+					"columns": ["id"]
+				},
+				"users_email_unique": {
+					"name": "users_email_unique",
+					"columns": ["email"]
+				}
+			},
+			"checkConstraint": {}
+		},
+		"verification_tokens": {
+			"name": "verification_tokens",
+			"columns": {
+				"identifier": {
+					"name": "identifier",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"token": {
+					"name": "token",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"expires": {
+					"name": "expires",
+					"type": "datetime",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"created_at": {
+					"name": "created_at",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "(now())"
+				},
+				"updated_at": {
+					"name": "updated_at",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"onUpdate": true,
+					"default": "(now())"
+				}
+			},
+			"indexes": {},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"verification_tokens_identifier": {
+					"name": "verification_tokens_identifier",
+					"columns": ["identifier"]
+				}
+			},
+			"uniqueConstraints": {
+				"verification_tokens_token_unique": {
+					"name": "verification_tokens_token_unique",
+					"columns": ["token"]
+				}
+			},
+			"checkConstraint": {}
+		},
+		"videos": {
+			"name": "videos",
+			"columns": {
+				"id": {
+					"name": "id",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"ownerId": {
+					"name": "ownerId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false
+				},
+				"name": {
+					"name": "name",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "'My Video'"
+				},
+				"awsRegion": {
+					"name": "awsRegion",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"awsBucket": {
+					"name": "awsBucket",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"bucket": {
+					"name": "bucket",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"metadata": {
+					"name": "metadata",
+					"type": "json",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"public": {
+					"name": "public",
+					"type": "boolean",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": true
+				},
+				"password": {
+					"name": "password",
+					"type": "text",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"videoStartTime": {
+					"name": "videoStartTime",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"audioStartTime": {
+					"name": "audioStartTime",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"xStreamInfo": {
+					"name": "xStreamInfo",
+					"type": "text",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"jobId": {
+					"name": "jobId",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"jobStatus": {
+					"name": "jobStatus",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"isScreenshot": {
+					"name": "isScreenshot",
+					"type": "boolean",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": false
+				},
+				"skipProcessing": {
+					"name": "skipProcessing",
+					"type": "boolean",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": false
+				},
+				"transcriptionStatus": {
+					"name": "transcriptionStatus",
+					"type": "varchar(255)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				},
+				"createdAt": {
+					"name": "createdAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "(now())"
+				},
+				"updatedAt": {
+					"name": "updatedAt",
+					"type": "timestamp",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"onUpdate": true,
+					"default": "(now())"
+				},
+				"source": {
+					"name": "source",
+					"type": "json",
+					"primaryKey": false,
+					"notNull": true,
+					"autoincrement": false,
+					"default": "('{\"type\":\"MediaConvert\"}')"
+				},
+				"folderId": {
+					"name": "folderId",
+					"type": "varchar(15)",
+					"primaryKey": false,
+					"notNull": false,
+					"autoincrement": false
+				}
+			},
+			"indexes": {
+				"id_idx": {
+					"name": "id_idx",
+					"columns": ["id"],
+					"isUnique": false
+				},
+				"owner_id_idx": {
+					"name": "owner_id_idx",
+					"columns": ["ownerId"],
+					"isUnique": false
+				},
+				"is_public_idx": {
+					"name": "is_public_idx",
+					"columns": ["public"],
+					"isUnique": false
+				},
+				"folder_id_idx": {
+					"name": "folder_id_idx",
+					"columns": ["folderId"],
+					"isUnique": false
+				}
+			},
+			"foreignKeys": {},
+			"compositePrimaryKeys": {
+				"videos_id": {
+					"name": "videos_id",
+					"columns": ["id"]
+				}
+			},
+			"uniqueConstraints": {
+				"videos_id_unique": {
+					"name": "videos_id_unique",
+					"columns": ["id"]
+				}
+			},
+			"checkConstraint": {}
+		}
+	},
+	"views": {},
+	"_meta": {
+		"schemas": {},
+		"tables": {},
+		"columns": {}
+	},
+	"internal": {
+		"tables": {},
+		"indexes": {}
+	}
+}
diff --git a/packages/database/migrations/meta/_journal.json b/packages/database/migrations/meta/_journal.json
index 0b10325e8d..808fe48f79 100644
--- a/packages/database/migrations/meta/_journal.json
+++ b/packages/database/migrations/meta/_journal.json
@@ -1,62 +1,62 @@
 {
-  "version": "5",
-  "dialect": "mysql",
-  "entries": [
-    {
-      "idx": 0,
-      "version": "5",
-      "when": 1743020179593,
-      "tag": "0000_brown_sunfire",
-      "breakpoints": true
-    },
-    {
-      "idx": 1,
-      "version": "5",
-      "when": 1749268354138,
-      "tag": "0001_white_young_avengers",
-      "breakpoints": true
-    },
-    {
-      "idx": 2,
-      "version": "5",
-      "when": 1750935538683,
-      "tag": "0002_dusty_maginty",
-      "breakpoints": true
-    },
-    {
-      "idx": 3,
-      "version": "5",
-      "when": 1751274435418,
-      "tag": "0003_outstanding_kylun",
-      "breakpoints": true
-    },
-    {
-      "idx": 4,
-      "version": "5",
-      "when": 1751299325634,
-      "tag": "0004_optimal_eddie_brock",
-      "breakpoints": true
-    },
-    {
-      "idx": 5,
-      "version": "5",
-      "when": 1751979972128,
-      "tag": "0005_graceful_fenris",
-      "breakpoints": true
-    },
-    {
-      "idx": 6,
-      "version": "5",
-      "when": 1751982995648,
-      "tag": "0006_woozy_jamie_braddock",
-      "breakpoints": true
-    },
-    {
-      "idx": 7,
-      "version": "5",
-      "when": 1754314124918,
-      "tag": "0007_cheerful_rocket_raccoon",
-      "breakpoints": true
-    }
-  ]
-}
\ No newline at end of file
+	"version": "5",
+	"dialect": "mysql",
+	"entries": [
+		{
+			"idx": 0,
+			"version": "5",
+			"when": 1743020179593,
+			"tag": "0000_brown_sunfire",
+			"breakpoints": true
+		},
+		{
+			"idx": 1,
+			"version": "5",
+			"when": 1749268354138,
+			"tag": "0001_white_young_avengers",
+			"breakpoints": true
+		},
+		{
+			"idx": 2,
+			"version": "5",
+			"when": 1750935538683,
+			"tag": "0002_dusty_maginty",
+			"breakpoints": true
+		},
+		{
+			"idx": 3,
+			"version": "5",
+			"when": 1751274435418,
+			"tag": "0003_outstanding_kylun",
+			"breakpoints": true
+		},
+		{
+			"idx": 4,
+			"version": "5",
+			"when": 1751299325634,
+			"tag": "0004_optimal_eddie_brock",
+			"breakpoints": true
+		},
+		{
+			"idx": 5,
+			"version": "5",
+			"when": 1751979972128,
+			"tag": "0005_graceful_fenris",
+			"breakpoints": true
+		},
+		{
+			"idx": 6,
+			"version": "5",
+			"when": 1751982995648,
+			"tag": "0006_woozy_jamie_braddock",
+			"breakpoints": true
+		},
+		{
+			"idx": 7,
+			"version": "5",
+			"when": 1754314124918,
+			"tag": "0007_cheerful_rocket_raccoon",
+			"breakpoints": true
+		}
+	]
+}
diff --git a/packages/database/schema.ts b/packages/database/schema.ts
index a627a3f7cd..ba1f70f5d2 100644
--- a/packages/database/schema.ts
+++ b/packages/database/schema.ts
@@ -1,8 +1,8 @@
 import type { Folder } from "@cap/web-domain";
 import {
+	boolean,
 	customType,
 	datetime,
-	boolean,
 	float,
 	index,
 	int,
@@ -10,6 +10,7 @@ import {
 	mysqlTable,
 	text,
 	timestamp,
+	uniqueIndex,
 	varchar,
 } from "drizzle-orm/mysql-core";
 import { relations } from "drizzle-orm/relations";
@@ -125,7 +126,7 @@ export const sessions = mysqlTable(
 	(table) => ({
 		sessionTokenIndex: uniqueIndex("session_token_idx").on(table.sessionToken),
 		userIdIndex: index("user_id_idx").on(table.userId),
-	})
+	}),
 );
 
 export const verificationTokens = mysqlTable("verification_tokens", {
@@ -155,7 +156,7 @@ export const organizations = mysqlTable(
 	(table) => ({
 		ownerIdIndex: index("owner_id_idx").on(table.ownerId),
 		customDomainIndex: index("custom_domain_idx").on(table.customDomain),
-	})
+	}),
 );
 
 export const organizationMembers = mysqlTable(
@@ -173,9 +174,9 @@ export const organizationMembers = mysqlTable(
 		organizationIdIndex: index("organization_id_idx").on(table.organizationId),
 		userIdOrganizationIdIndex: index("user_id_organization_id_idx").on(
 			table.userId,
-			table.organizationId
+			table.organizationId,
 		),
-	})
+	}),
 );
 
 export const organizationInvites = mysqlTable(
@@ -195,10 +196,10 @@ export const organizationInvites = mysqlTable(
 		organizationIdIndex: index("organization_id_idx").on(table.organizationId),
 		invitedEmailIndex: index("invited_email_idx").on(table.invitedEmail),
 		invitedByUserIdIndex: index("invited_by_user_id_idx").on(
-			table.invitedByUserId
+			table.invitedByUserId,
 		),
 		statusIndex: index("status_idx").on(table.status),
-	})
+	}),
 );
 
 export const folders = mysqlTable(
@@ -224,7 +225,7 @@ export const folders = mysqlTable(
 		createdByIdIndex: index("created_by_id_idx").on(table.createdById),
 		parentIdIndex: index("parent_id_idx").on(table.parentId),
 		spaceIdIndex: index("space_id_idx").on(table.spaceId),
-	})
+	}),
 );
 
 export const videos = mysqlTable(
@@ -267,7 +268,7 @@ export const videos = mysqlTable(
 		ownerIdIndex: index("owner_id_idx").on(table.ownerId),
 		publicIndex: index("is_public_idx").on(table.public),
 		folderIdIndex: index("folder_id_idx").on(table.folderId),
-	})
+	}),
 );
 
 export const sharedVideos = mysqlTable(
@@ -283,13 +284,13 @@ export const sharedVideos = mysqlTable(
 		videoIdIndex: index("video_id_idx").on(table.videoId),
 		organizationIdIndex: index("organization_id_idx").on(table.organizationId),
 		sharedByUserIdIndex: index("shared_by_user_id_idx").on(
-			table.sharedByUserId
+			table.sharedByUserId,
 		),
 		videoIdOrganizationIdIndex: index("video_id_organization_id_idx").on(
 			table.videoId,
-			table.organizationId
+			table.organizationId,
 		),
-	})
+	}),
 );
 
 export const comments = mysqlTable(
@@ -309,9 +310,9 @@ export const comments = mysqlTable(
 		videoIdIndex: index("video_id_idx").on(table.videoId),
 		authorIdIndex: index("author_id_idx").on(table.authorId),
 		parentCommentIdIndex: index("parent_comment_id_idx").on(
-			table.parentCommentId
+			table.parentCommentId,
 		),
-	})
+	}),
 );
 
 export const notifications = mysqlTable(
@@ -344,13 +345,13 @@ export const notifications = mysqlTable(
 		createdAtIndex: index("created_at_idx").on(table.createdAt),
 		recipientReadIndex: index("recipient_read_idx").on(
 			table.recipientId,
-			table.readAt
+			table.readAt,
 		),
 		recipientCreatedIndex: index("recipient_created_idx").on(
 			table.recipientId,
-			table.createdAt
+			table.createdAt,
 		),
-	})
+	}),
 );
 
 export const s3Buckets = mysqlTable("s3_buckets", {
@@ -434,7 +435,7 @@ export const organizationsRelations = relations(
 		sharedVideos: many(sharedVideos),
 		organizationInvites: many(organizationInvites),
 		spaces: many(spaces),
-	})
+	}),
 );
 
 export const sessionsRelations = relations(sessions, ({ one }) => ({
@@ -446,9 +447,9 @@ export const sessionsRelations = relations(sessions, ({ one }) => ({
 
 export const verificationTokensRelations = relations(
 	verificationTokens,
-	({ }) => ({
+	({}) => ({
 		// No relations defined
-	})
+	}),
 );
 
 export const organizationMembersRelations = relations(
@@ -462,7 +463,7 @@ export const organizationMembersRelations = relations(
 			fields: [organizationMembers.organizationId],
 			references: [organizations.id],
 		}),
-	})
+	}),
 );
 
 export const organizationInvitesRelations = relations(
@@ -476,7 +477,7 @@ export const organizationInvitesRelations = relations(
 			fields: [organizationInvites.invitedByUserId],
 			references: [users.id],
 		}),
-	})
+	}),
 );
 
 export const videosRelations = relations(videos, ({ one, many }) => ({
@@ -526,7 +527,7 @@ export const spaces = mysqlTable(
 	(table) => ({
 		organizationIdIndex: index("organization_id_idx").on(table.organizationId),
 		createdByIdIndex: index("created_by_id_idx").on(table.createdById),
-	})
+	}),
 );
 
 export const spaceMembers = mysqlTable(
@@ -544,9 +545,9 @@ export const spaceMembers = mysqlTable(
 		userIdIndex: index("user_id_idx").on(table.userId),
 		spaceIdUserIdIndex: index("space_id_user_id_idx").on(
 			table.spaceId,
-			table.userId
+			table.userId,
 		),
-	})
+	}),
 );
 
 export const spaceVideos = mysqlTable(
@@ -566,9 +567,9 @@ export const spaceVideos = mysqlTable(
 		addedByIdIndex: index("added_by_id_idx").on(table.addedById),
 		spaceIdVideoIdIndex: index("space_id_video_id_idx").on(
 			table.spaceId,
-			table.videoId
+			table.videoId,
 		),
-	})
+	}),
 );
 
 export const spacesRelations = relations(spaces, ({ one, many }) => ({

From 8ec7bb76786aa59646d2253dbfb0c1dcdfb73870 Mon Sep 17 00:00:00 2001
From: Brendan Allan <brendonovich@outlook.com>
Date: Wed, 20 Aug 2025 18:10:06 +0800
Subject: [PATCH 5/5] cleanup

---
 apps/web/app/(org)/login/form.tsx | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/apps/web/app/(org)/login/form.tsx b/apps/web/app/(org)/login/form.tsx
index c7b595df8b..f29c4a60ab 100644
--- a/apps/web/app/(org)/login/form.tsx
+++ b/apps/web/app/(org)/login/form.tsx
@@ -96,8 +96,6 @@ export function LoginForm() {
 				});
 				const data = await response.json();
 
-				console.log(data);
-
 				if (data.url) {
 					window.location.href = data.url;
 				}
@@ -247,7 +245,6 @@ export function LoginForm() {
 											e.preventDefault();
 											if (!email) return;
 
-											console.log({ lastEmailSentTime });
 											// Check if we're rate limited on the client side
 											if (lastEmailSentTime) {
 												const timeSinceLastRequest =
