// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema datasource db { provider = "postgresql" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" //provider = "prisma-dbml-generator" } generator zod { provider = "zod-prisma" output = "./zod" imports = "./zod-utils" relationModel = "default" } generator json { provider = "prisma-json-types-generator" } enum PipelineTriggers { responseCreated responseUpdated responseFinished } model Webhook { id String @id @default(cuid()) name String? createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") url String environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade) environmentId String triggers PipelineTriggers[] surveyIds String[] } model Attribute { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") attributeClass AttributeClass @relation(fields: [attributeClassId], references: [id], onDelete: Cascade) attributeClassId String person Person @relation(fields: [personId], references: [id], onDelete: Cascade) personId String value String @@unique([attributeClassId, personId]) } enum AttributeType { code noCode automatic } model AttributeClass { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") name String description String? archived Boolean @default(false) type AttributeType environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade) environmentId String attributes Attribute[] attributeFilters SurveyAttributeFilter[] @@unique([name, environmentId]) } model Person { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade) environmentId String responses Response[] sessions Session[] attributes Attribute[] displays Display[] } model Response { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") finished Boolean @default(false) survey Survey @relation(fields: [surveyId], references: [id], onDelete: Cascade) surveyId String person Person? @relation(fields: [personId], references: [id], onDelete: Cascade) personId String? notes ResponseNote[] /// @zod.custom(imports.ZResponseData) /// [ResponseData] data Json @default("{}") /// @zod.custom(imports.ZResponseMeta) /// [ResponseMeta] meta Json @default("{}") tags TagsOnResponses[] /// @zod.custom(imports.ZResponsePersonAttributes) /// [ResponsePersonAttributes] personAttributes Json? } model ResponseNote { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") response Response @relation(fields: [responseId], references: [id], onDelete: Cascade) responseId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId String text String } model Tag { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") name String responses TagsOnResponses[] environmentId String environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade) @@unique([environmentId, name]) } model TagsOnResponses { responseId String response Response @relation(fields: [responseId], references: [id], onDelete: Cascade) tagId String tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade) @@id([responseId, tagId]) } enum SurveyStatus { draft inProgress paused completed archived } enum DisplayStatus { seen responded } model Display { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") survey Survey @relation(fields: [surveyId], references: [id], onDelete: Cascade) surveyId String person Person? @relation(fields: [personId], references: [id], onDelete: Cascade) personId String? status DisplayStatus @default(seen) } model SurveyTrigger { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") survey Survey @relation(fields: [surveyId], references: [id], onDelete: Cascade) surveyId String eventClass EventClass @relation(fields: [eventClassId], references: [id], onDelete: Cascade) eventClassId String @@unique([surveyId, eventClassId]) } enum SurveyAttributeFilterCondition { equals notEquals } model SurveyAttributeFilter { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") attributeClass AttributeClass @relation(fields: [attributeClassId], references: [id], onDelete: Cascade) attributeClassId String survey Survey @relation(fields: [surveyId], references: [id], onDelete: Cascade) surveyId String condition SurveyAttributeFilterCondition value String @@unique([surveyId, attributeClassId]) } enum SurveyType { email link mobile web } enum displayOptions { displayOnce displayMultiple respondMultiple } model Survey { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") name String redirectUrl String? type SurveyType @default(web) environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade) environmentId String status SurveyStatus @default(draft) /// @zod.custom(imports.ZSurveyQuestions) /// @zod.custom(imports.ZSurveyQuestions) /// [SurveyQuestions] questions Json @default("[]") /// @zod.custom(imports.ZSurveyThankYouCard) /// @zod.custom(imports.ZSurveyThankYouCard) /// [SurveyThankYouCard] thankYouCard Json @default("{\"enabled\": false}") responses Response[] displayOption displayOptions @default(displayOnce) recontactDays Int? triggers SurveyTrigger[] attributeFilters SurveyAttributeFilter[] displays Display[] autoClose Int? delay Int @default(0) autoComplete Int? closeOnDate DateTime? /// @zod.custom(imports.ZSurveyClosedMessage) /// [SurveyClosedMessage] surveyClosedMessage Json? } model Event { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") eventClass EventClass? @relation(fields: [eventClassId], references: [id]) eventClassId String? session Session @relation(fields: [sessionId], references: [id], onDelete: Cascade) sessionId String /// @zod.custom(imports.ZEventProperties) /// @zod.custom(imports.ZEventProperties) /// [EventProperties] properties Json @default("{}") } enum EventType { code noCode automatic } model EventClass { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") name String description String? type EventType events Event[] /// @zod.custom(imports.ZActionClassNoCodeConfig) /// [EventClassNoCodeConfig] noCodeConfig Json? environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade) environmentId String surveys SurveyTrigger[] @@unique([name, environmentId]) } model Session { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") expiresAt DateTime @default(now()) person Person @relation(fields: [personId], references: [id], onDelete: Cascade) personId String events Event[] } enum EnvironmentType { production development } model Environment { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") type EnvironmentType product Product @relation(fields: [productId], references: [id], onDelete: Cascade) productId String widgetSetupCompleted Boolean @default(false) surveys Survey[] people Person[] eventClasses EventClass[] attributeClasses AttributeClass[] apiKeys ApiKey[] webhooks Webhook[] tags Tag[] } enum WidgetPlacement { bottomLeft bottomRight topLeft topRight center } model Product { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") name String team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) teamId String environments Environment[] brandColor String @default("#64748b") highlightBorderColor String? recontactDays Int @default(7) formbricksSignature Boolean @default(true) placement WidgetPlacement @default(bottomRight) clickOutsideClose Boolean @default(true) darkOverlay Boolean @default(false) } enum Plan { free pro } model Team { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") name String memberships Membership[] products Product[] plan Plan @default(free) stripeCustomerId String? invites Invite[] } enum MembershipRole { owner admin editor developer viewer } model Membership { team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) teamId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId String accepted Boolean @default(false) role MembershipRole @@id([userId, teamId]) } model Invite { id String @id @default(uuid()) email String name String? team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) teamId String creator User @relation("inviteCreatedBy", fields: [creatorId], references: [id]) creatorId String acceptor User? @relation("inviteAcceptedBy", fields: [acceptorId], references: [id], onDelete: Cascade) acceptorId String? accepted Boolean @default(false) createdAt DateTime @default(now()) expiresAt DateTime role MembershipRole @default(admin) @@index([email, teamId], name: "email_teamId_unique") } model ApiKey { id String @id @unique @default(cuid()) createdAt DateTime @default(now()) lastUsedAt DateTime? label String? hashedKey String @unique() environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade) environmentId String } enum IdentityProvider { email github google } model Account { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") user User? @relation(fields: [userId], references: [id], onDelete: Cascade) userId String type String provider String providerAccountId String access_token String? @db.Text refresh_token String? @db.Text expires_at Int? token_type String? scope String? id_token String? @db.Text session_state String? @@unique([provider, providerAccountId]) } enum Role { project_manager engineer founder marketing_specialist other } enum Objective { increase_conversion improve_user_retention increase_user_adoption sharpen_marketing_messaging support_sales other } enum Intention { survey_user_segments survey_at_specific_point_in_user_journey enrich_customer_profiles collect_all_user_feedback_on_one_platform other } model User { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") name String? email String @unique emailVerified DateTime? @map(name: "email_verified") password String? onboardingCompleted Boolean @default(false) identityProvider IdentityProvider @default(email) identityProviderAccountId String? memberships Membership[] accounts Account[] responseNotes ResponseNote[] groupId String? invitesCreated Invite[] @relation("inviteCreatedBy") invitesAccepted Invite[] @relation("inviteAcceptedBy") role Role? objective Objective? /// @zod.custom(imports.ZUserNotificationSettings) /// @zod.custom(imports.ZUserNotificationSettings) /// [UserNotificationSettings] notificationSettings Json @default("{}") }