datasource db { provider = "postgresql" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } model Organization { id String @id @default(cuid()) createdAt DateTime @default(now()) @db.Timestamptz updatedAt DateTime @updatedAt @db.Timestamptz memberships Membership[] phoneNumbers PhoneNumber[] subscriptions Subscription[] // many subscriptions to keep a history } model Subscription { createdAt DateTime @default(now()) @db.Timestamptz updatedAt DateTime @updatedAt @db.Timestamptz paddleSubscriptionId Int @id @unique paddlePlanId Int paddleCheckoutId String status SubscriptionStatus updateUrl String cancelUrl String currency String unitPrice Float nextBillDate DateTime @db.Date lastEventTime DateTime @db.Timestamp cancellationEffectiveDate DateTime? @db.Date organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) organizationId String } enum SubscriptionStatus { active trialing // not used past_due paused // not used deleted } model Membership { id String @id @default(cuid()) role MembershipRole organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) organizationId String user User? @relation(fields: [userId], references: [id], onDelete: Cascade) userId String? // When the user joins, we will clear out the email and set the user. invitedEmail String? invitationToken Token? @@unique([organizationId, invitedEmail]) } enum MembershipRole { OWNER USER } // The owners of the SaaS (you) can have a SUPERADMIN role to access all data enum GlobalRole { SUPERADMIN CUSTOMER } model User { id String @id @default(cuid()) createdAt DateTime @default(now()) @db.Timestamptz updatedAt DateTime @updatedAt @db.Timestamptz fullName String email String @unique hashedPassword String? role GlobalRole @default(CUSTOMER) memberships Membership[] tokens Token[] sessions Session[] } model Session { id String @id @default(cuid()) createdAt DateTime @default(now()) @db.Timestamptz updatedAt DateTime @updatedAt @db.Timestamptz expiresAt DateTime? @db.Timestamptz data String user User? @relation(fields: [userId], references: [id], onDelete: Cascade) userId String? } model Token { id String @id @default(cuid()) createdAt DateTime @default(now()) @db.Timestamptz updatedAt DateTime @updatedAt @db.Timestamptz hashedToken String type TokenType expiresAt DateTime @db.Timestamptz sentTo String user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId String membership Membership @relation(fields: [membershipId], references: [id], onDelete: Cascade) membershipId String @unique @@unique([hashedToken, type]) } enum TokenType { RESET_PASSWORD INVITE_MEMBER } model Message { id String @id sentAt DateTime @db.Timestamptz content String from String to String direction Direction status MessageStatus phoneNumber PhoneNumber @relation(fields: [phoneNumberId], references: [id], onDelete: Cascade) phoneNumberId String } enum Direction { Inbound Outbound } enum MessageStatus { Queued Sending Sent Failed Delivered Undelivered Receiving Received Accepted Scheduled Read PartiallyDelivered Canceled Error } model PhoneCall { id String @id createdAt DateTime @default(now()) @db.Timestamptz from String to String status CallStatus direction Direction duration String phoneNumber PhoneNumber @relation(fields: [phoneNumberId], references: [id], onDelete: Cascade) phoneNumberId String } enum CallStatus { Queued Ringing InProgress Completed Busy Failed NoAnswer Canceled } model PhoneNumber { id String @id createdAt DateTime @default(now()) @db.Timestamptz number String isFetchingMessages Boolean? isFetchingCalls Boolean? messages Message[] phoneCalls PhoneCall[] organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) organizationId String @@unique([organizationId, id]) }