import { createId as cuid } from "@paralleldrive/cuid2"; import { relations, sql } from "drizzle-orm"; import { blob, integer, sqliteTable, text, uniqueIndex, } from "drizzle-orm/sqlite-core"; // Tables export const user = sqliteTable("user", { id: text("id") .$defaultFn(() => cuid()) .primaryKey(), name: text("name").notNull(), email: text("email").notNull().unique(), emailVerified: integer("emailVerified", { mode: "boolean" }) .notNull() .default(false), image: text("image"), createdAt: integer("createdAt", { mode: "timestamp" }) .notNull() .default(sql`CURRENT_TIMESTAMP`), updatedAt: integer("updatedAt", { mode: "timestamp" }) .notNull() .default(sql`CURRENT_TIMESTAMP`), username: text("username").unique(), role: text("role"), banned: integer("banned", { mode: "boolean" }), banReason: text("banReason"), banExpires: integer("banExpires", { mode: "timestamp" }), onboardingComplete: integer("onboardingComplete", { mode: "boolean" }) .notNull() .default(false), paymentsCustomerId: text("paymentsCustomerId"), locale: text("locale"), }); export const session = sqliteTable( "session", { id: text("id") .$defaultFn(() => cuid()) .primaryKey(), expiresAt: integer("expiresAt", { mode: "timestamp" }).notNull(), ipAddress: text("ipAddress"), userAgent: text("userAgent"), userId: text("userId") .notNull() .references(() => user.id, { onDelete: "cascade" }), impersonatedBy: text("impersonatedBy"), activeOrganizationId: text("activeOrganizationId"), token: text("token").notNull(), createdAt: integer("createdAt", { mode: "timestamp" }).notNull(), updatedAt: integer("updatedAt", { mode: "timestamp" }).notNull(), }, (table) => [uniqueIndex("session_token_idx").on(table.token)], ); export const account = sqliteTable("account", { id: text("id") .$defaultFn(() => cuid()) .primaryKey(), accountId: text("accountId").notNull(), providerId: text("providerId").notNull(), userId: text("userId") .notNull() .references(() => user.id, { onDelete: "cascade" }), accessToken: text("accessToken"), refreshToken: text("refreshToken"), idToken: text("idToken"), expiresAt: integer("expiresAt", { mode: "timestamp" }), password: text("password"), accessTokenExpiresAt: integer("accessTokenExpiresAt", { mode: "timestamp", }), refreshTokenExpiresAt: integer("refreshTokenExpiresAt", { mode: "timestamp", }), scope: text("scope"), createdAt: integer("createdAt", { mode: "timestamp" }).notNull(), updatedAt: integer("updatedAt", { mode: "timestamp" }).notNull(), }); export const verification = sqliteTable("verification", { id: text("id") .$defaultFn(() => cuid()) .primaryKey(), identifier: text("identifier").notNull(), value: text("value").notNull(), expiresAt: integer("expiresAt", { mode: "timestamp" }).notNull(), createdAt: integer("createdAt", { mode: "timestamp" }), updatedAt: integer("updatedAt", { mode: "timestamp" }), }); export const passkey = sqliteTable("passkey", { id: text("id") .$defaultFn(() => cuid()) .primaryKey(), name: text("name"), publicKey: text("publicKey").notNull(), userId: text("userId") .notNull() .references(() => user.id, { onDelete: "cascade" }), credentialID: text("credentialID").notNull(), counter: integer("counter").notNull(), deviceType: text("deviceType").notNull(), backedUp: integer("backedUp", { mode: "boolean" }).notNull(), transports: text("transports"), createdAt: integer("createdAt", { mode: "timestamp" }), }); export const twoFactor = sqliteTable("twoFactor", { id: text("id") .$defaultFn(() => cuid()) .primaryKey(), secret: text("secret").notNull(), backupCodes: text("backupCodes").notNull(), userId: text("userId") .notNull() .references(() => user.id, { onDelete: "cascade" }), }); export const organization = sqliteTable( "organization", { id: text("id") .$defaultFn(() => cuid()) .primaryKey(), name: text("name").notNull(), slug: text("slug"), logo: text("logo"), createdAt: integer("createdAt", { mode: "timestamp" }).notNull(), metadata: text("metadata"), paymentsCustomerId: text("paymentsCustomerId"), }, (table) => [uniqueIndex("organization_slug_idx").on(table.slug)], ); export const member = sqliteTable( "member", { id: text("id").primaryKey(), organizationId: text("organizationId") .notNull() .references(() => organization.id, { onDelete: "cascade" }), userId: text("userId") .notNull() .references(() => user.id, { onDelete: "cascade" }), role: text("role").notNull(), createdAt: integer("createdAt", { mode: "timestamp" }).notNull(), }, (table) => [ uniqueIndex("member_user_org_idx").on( table.userId, table.organizationId, ), ], ); export const invitation = sqliteTable("invitation", { id: text("id") .$defaultFn(() => cuid()) .primaryKey(), organizationId: text("organizationId") .notNull() .references(() => organization.id, { onDelete: "cascade" }), email: text("email").notNull(), role: text("role"), status: text("status").notNull(), expiresAt: integer("expiresAt", { mode: "timestamp" }).notNull(), inviterId: text("inviterId") .notNull() .references(() => user.id, { onDelete: "cascade" }), }); export const purchase = sqliteTable("purchase", { id: text("id") .$defaultFn(() => cuid()) .primaryKey(), organizationId: text("organizationId").references(() => organization.id, { onDelete: "cascade", }), userId: text("userId").references(() => user.id, { onDelete: "cascade", }), type: text({ enum: ["SUBSCRIPTION", "ONE_TIME"] }).notNull(), customerId: text("customerId").notNull(), subscriptionId: text("subscriptionId").unique(), productId: text("productId").notNull(), status: text("status"), createdAt: integer("createdAt", { mode: "timestamp" }) .notNull() .default(sql`CURRENT_TIMESTAMP`), updatedAt: integer("updatedAt", { mode: "timestamp" }).default( sql`CURRENT_TIMESTAMP`, ), }); export const aiChat = sqliteTable("aiChat", { id: text("id") .$defaultFn(() => cuid()) .primaryKey(), organizationId: text("organizationId").references(() => organization.id, { onDelete: "cascade", }), userId: text("userId").references(() => user.id, { onDelete: "cascade" }), title: text("title"), messages: blob("messages", { mode: "json" }), createdAt: integer("createdAt", { mode: "timestamp" }) .notNull() .default(sql`CURRENT_TIMESTAMP`), updatedAt: integer("updatedAt", { mode: "timestamp" }).default( sql`CURRENT_TIMESTAMP`, ), }); // Relations export const userRelations = relations(user, ({ many }) => ({ sessions: many(session), accounts: many(account), passkeys: many(passkey), invitations: many(invitation), purchases: many(purchase), memberships: many(member), aiChats: many(aiChat), twoFactors: many(twoFactor), })); export const organizationRelations = relations(organization, ({ many }) => ({ members: many(member), invitations: many(invitation), purchases: many(purchase), aiChats: many(aiChat), }));