mirror of
https://github.com/formbricks/formbricks.git
synced 2025-12-29 09:50:10 -06:00
612 lines
19 KiB
Plaintext
612 lines
19 KiB
Plaintext
// 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"
|
|
}
|
|
|
|
// generator dbml {
|
|
// 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
|
|
}
|
|
|
|
enum WebhookSource {
|
|
user
|
|
zapier
|
|
make
|
|
n8n
|
|
}
|
|
|
|
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
|
|
source WebhookSource @default(user)
|
|
environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade)
|
|
environmentId String
|
|
triggers PipelineTriggers[]
|
|
surveyIds String[]
|
|
|
|
@@index([environmentId])
|
|
}
|
|
|
|
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([personId, attributeClassId])
|
|
}
|
|
|
|
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])
|
|
@@index([environmentId, createdAt])
|
|
@@index([environmentId, archived])
|
|
}
|
|
|
|
model Person {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
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[]
|
|
attributes Attribute[]
|
|
displays Display[]
|
|
actions Action[]
|
|
|
|
@@unique([environmentId, userId])
|
|
@@index([environmentId])
|
|
}
|
|
|
|
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.ZResponseTtc)
|
|
/// [ResponseTtc]
|
|
ttc Json @default("{}")
|
|
/// @zod.custom(imports.ZResponseMeta)
|
|
/// [ResponseMeta]
|
|
meta Json @default("{}")
|
|
tags TagsOnResponses[]
|
|
/// @zod.custom(imports.ZResponsePersonAttributes)
|
|
/// [ResponsePersonAttributes]
|
|
personAttributes Json?
|
|
// singleUseId, used to prevent multiple responses
|
|
singleUseId String?
|
|
|
|
@@unique([surveyId, singleUseId])
|
|
@@index([surveyId, createdAt]) // to determine monthly response count
|
|
@@index([surveyId])
|
|
}
|
|
|
|
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
|
|
isResolved Boolean @default(false)
|
|
isEdited Boolean @default(false)
|
|
|
|
@@index([responseId])
|
|
}
|
|
|
|
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])
|
|
@@index([environmentId])
|
|
}
|
|
|
|
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])
|
|
@@index([responseId])
|
|
}
|
|
|
|
enum SurveyStatus {
|
|
draft
|
|
inProgress
|
|
paused
|
|
completed
|
|
}
|
|
|
|
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?
|
|
responseId String? @unique
|
|
status DisplayStatus?
|
|
|
|
@@index([surveyId])
|
|
@@index([personId])
|
|
}
|
|
|
|
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
|
|
actionClass ActionClass @relation(fields: [actionClassId], references: [id], onDelete: Cascade)
|
|
actionClassId String
|
|
|
|
@@unique([surveyId, actionClassId])
|
|
@@index([surveyId])
|
|
}
|
|
|
|
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])
|
|
@@index([surveyId])
|
|
@@index([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
|
|
creator User? @relation(fields: [createdBy], references: [id])
|
|
createdBy String?
|
|
status SurveyStatus @default(draft)
|
|
/// @zod.custom(imports.ZSurveyWelcomeCard)
|
|
/// [SurveyWelcomeCard]
|
|
welcomeCard Json @default("{\"enabled\": false}")
|
|
/// @zod.custom(imports.ZSurveyQuestions)
|
|
/// [SurveyQuestions]
|
|
questions Json @default("[]")
|
|
/// @zod.custom(imports.ZSurveyThankYouCard)
|
|
/// [SurveyThankYouCard]
|
|
thankYouCard Json @default("{\"enabled\": false}")
|
|
/// @zod.custom(imports.ZSurveyHiddenFields)
|
|
/// [SurveyHiddenFields]
|
|
hiddenFields Json @default("{\"enabled\": false}")
|
|
responses Response[]
|
|
displayOption displayOptions @default(displayOnce)
|
|
recontactDays Int?
|
|
triggers SurveyTrigger[]
|
|
/// @zod.custom(imports.ZSurveyInlineTriggers)
|
|
/// [SurveyInlineTriggers]
|
|
inlineTriggers Json?
|
|
attributeFilters SurveyAttributeFilter[]
|
|
displays Display[]
|
|
autoClose Int?
|
|
delay Int @default(0)
|
|
autoComplete Int?
|
|
closeOnDate DateTime?
|
|
/// @zod.custom(imports.ZSurveyClosedMessage)
|
|
/// [SurveyClosedMessage]
|
|
surveyClosedMessage Json?
|
|
|
|
segmentId String?
|
|
segment Segment? @relation(fields: [segmentId], references: [id])
|
|
|
|
/// @zod.custom(imports.ZSurveyProductOverwrites)
|
|
/// [SurveyProductOverwrites]
|
|
productOverwrites Json?
|
|
|
|
/// @zod.custom(imports.ZSurveyStyling)
|
|
/// [SurveyStyling]
|
|
styling Json?
|
|
|
|
/// @zod.custom(imports.ZSurveySingleUse)
|
|
/// [SurveySingleUse]
|
|
singleUse Json? @default("{\"enabled\": false, \"isEncrypted\": true}")
|
|
|
|
/// @zod.custom(imports.ZSurveyVerifyEmail)
|
|
/// [SurveyVerifyEmail]
|
|
verifyEmail Json?
|
|
pin String?
|
|
resultShareKey String? @unique
|
|
displayPercentage Int?
|
|
|
|
@@index([environmentId])
|
|
}
|
|
|
|
enum ActionType {
|
|
code
|
|
noCode
|
|
automatic
|
|
}
|
|
|
|
model ActionClass {
|
|
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 ActionType
|
|
/// @zod.custom(imports.ZActionClassNoCodeConfig)
|
|
/// [ActionClassNoCodeConfig]
|
|
noCodeConfig Json?
|
|
environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade)
|
|
environmentId String
|
|
surveys SurveyTrigger[]
|
|
actions Action[]
|
|
|
|
@@unique([name, environmentId])
|
|
}
|
|
|
|
model Action {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now()) @map(name: "created_at")
|
|
actionClass ActionClass @relation(fields: [actionClassId], references: [id], onDelete: Cascade)
|
|
actionClassId String
|
|
person Person @relation(fields: [personId], references: [id], onDelete: Cascade)
|
|
personId String
|
|
/// @zod.custom(imports.ZActionProperties)
|
|
/// @zod.custom(imports.ZActionProperties)
|
|
/// [ActionProperties]
|
|
properties Json @default("{}")
|
|
|
|
@@index([personId, actionClassId, createdAt])
|
|
@@index([actionClassId, createdAt])
|
|
@@index([personId])
|
|
}
|
|
|
|
enum EnvironmentType {
|
|
production
|
|
development
|
|
}
|
|
|
|
enum IntegrationType {
|
|
googleSheets
|
|
notion
|
|
airtable
|
|
}
|
|
|
|
model Integration {
|
|
id String @id @default(cuid())
|
|
type IntegrationType
|
|
environmentId String
|
|
/// @zod.custom(imports.ZIntegrationConfig)
|
|
/// [IntegrationConfig]
|
|
config Json
|
|
environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([type, environmentId])
|
|
@@index([environmentId])
|
|
}
|
|
|
|
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[]
|
|
actionClasses ActionClass[]
|
|
attributeClasses AttributeClass[]
|
|
apiKeys ApiKey[]
|
|
webhooks Webhook[]
|
|
tags Tag[]
|
|
segments Segment[]
|
|
integration Integration[]
|
|
|
|
@@index([productId])
|
|
}
|
|
|
|
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?
|
|
/// @zod.custom(imports.ZStyling)
|
|
/// [Styling]
|
|
styling Json? @default("{\"unifiedStyling\":true,\"allowStyleOverwrite\":true,\"brandColor\":{\"light\":\"#64748b\"}}")
|
|
recontactDays Int @default(7)
|
|
linkSurveyBranding Boolean @default(true) // Determines if the survey branding should be displayed in link surveys
|
|
inAppSurveyBranding Boolean @default(true) // Determines if the survey branding should be displayed in in-app surveys
|
|
placement WidgetPlacement @default(bottomRight)
|
|
clickOutsideClose Boolean @default(true)
|
|
darkOverlay Boolean @default(false)
|
|
|
|
@@unique([teamId, name])
|
|
@@index([teamId])
|
|
}
|
|
|
|
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[]
|
|
/// @zod.custom(imports.ZTeamBilling)
|
|
/// [TeamBilling]
|
|
billing Json @default("{\"stripeCustomerId\": null, \"features\": {\"inAppSurvey\": {\"status\": \"inactive\", \"unlimited\": false}, \"linkSurvey\": {\"status\": \"inactive\", \"unlimited\": false}, \"userTargeting\": {\"status\": \"inactive\", \"unlimited\": false}}}")
|
|
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])
|
|
@@index([userId])
|
|
@@index([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])
|
|
@@index([teamId])
|
|
}
|
|
|
|
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
|
|
|
|
@@index([environmentId])
|
|
}
|
|
|
|
enum IdentityProvider {
|
|
email
|
|
github
|
|
google
|
|
azuread
|
|
openid
|
|
}
|
|
|
|
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?
|
|
ext_expires_in Int?
|
|
token_type String?
|
|
scope String?
|
|
id_token String? @db.Text
|
|
session_state String?
|
|
|
|
@@unique([provider, providerAccountId])
|
|
@@index([userId])
|
|
}
|
|
|
|
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")
|
|
imageUrl String?
|
|
twoFactorSecret String?
|
|
twoFactorEnabled Boolean @default(false)
|
|
backupCodes String?
|
|
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("{}")
|
|
surveys Survey[]
|
|
|
|
@@index([email])
|
|
}
|
|
|
|
model ShortUrl {
|
|
id String @id // generate nanoId in service
|
|
createdAt DateTime @default(now()) @map(name: "created_at")
|
|
updatedAt DateTime @updatedAt @map(name: "updated_at")
|
|
url String @unique
|
|
}
|
|
|
|
model Segment {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now()) @map(name: "created_at")
|
|
updatedAt DateTime @updatedAt @map(name: "updated_at")
|
|
title String
|
|
description String?
|
|
isPrivate Boolean @default(true)
|
|
/// @zod.custom(imports.ZSegmentFilters)
|
|
/// [SegmentFilter]
|
|
filters Json @default("[]")
|
|
environmentId String
|
|
environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade)
|
|
surveys Survey[]
|
|
|
|
@@unique([environmentId, title])
|
|
@@index([environmentId])
|
|
}
|