// 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") extensions = [pgvector(map: "vector")] } generator client { provider = "prisma-client-js" previewFeatures = ["postgresqlExtensions"] } generator json { provider = "prisma-json-types-generator" } enum PipelineTriggers { responseCreated responseUpdated responseFinished } enum WebhookSource { user zapier make n8n activepieces } /// Represents a webhook endpoint for receiving survey-related events. /// Webhooks can be configured to receive notifications about response creation, updates, and completion. /// /// @property id - Unique identifier for the webhook /// @property name - Optional display name for the webhook /// @property url - The endpoint URL where events will be sent /// @property source - Origin of the webhook (user, zapier, make, etc.) /// @property environment - Associated environment /// @property triggers - Types of events that trigger this webhook /// @property surveyIds - List of surveys this webhook is monitoring model Webhook { id String @id @default(cuid()) name String? createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @default(now()) @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]) } /// Represents an attribute value associated with a contact. /// Used to store custom properties and characteristics of contacts. /// /// @property id - Unique identifier for the attribute /// @property attributeKey - Reference to the attribute definition /// @property contact - The contact this attribute belongs to /// @property value - The actual value of the attribute model ContactAttribute { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") attributeKey ContactAttributeKey @relation(fields: [attributeKeyId], references: [id], onDelete: Cascade) attributeKeyId String contact Contact @relation(fields: [contactId], references: [id], onDelete: Cascade) contactId String value String @@unique([contactId, attributeKeyId]) @@index([attributeKeyId, value]) } enum ContactAttributeType { default custom } /// Defines the possible attributes that can be assigned to contacts. /// Acts as a schema for contact attributes within an environment. /// /// @property id - Unique identifier for the attribute key /// @property isUnique - Whether the attribute must have unique values across contacts /// @property key - The attribute identifier used in the system /// @property name - Display name for the attribute /// @property type - Whether this is a default or custom attribute /// @property environment - The environment this attribute belongs to model ContactAttributeKey { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") isUnique Boolean @default(false) key String name String? description String? type ContactAttributeType @default(custom) environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade) environmentId String attributes ContactAttribute[] attributeFilters SurveyAttributeFilter[] @@unique([key, environmentId]) @@index([environmentId, createdAt]) } /// Represents a person or user who can receive and respond to surveys. /// Contacts are environment-specific and can have multiple attributes and responses. /// /// @property id - Unique identifier for the contact /// @property environment - The environment this contact belongs to /// @property responses - Survey responses from this contact /// @property attributes - Custom attributes associated with this contact /// @property displays - Record of surveys shown to this contact model Contact { 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[] attributes ContactAttribute[] displays Display[] @@index([environmentId]) } /// Stores a user's response to a survey, including their answers and metadata. /// Each response is linked to a specific survey and optionally to a contact. /// /// @property id - Unique identifier for the response /// @property finished - Whether the survey was completed /// @property survey - The associated survey /// @property contact - The optional contact who provided the response /// @property data - JSON object containing the actual response data /// @property variables - Custom variables used in the response /// @property ttc - Time to completion metrics /// @property meta - Additional metadata about the response model Response { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @default(now()) @updatedAt @map(name: "updated_at") finished Boolean @default(false) survey Survey @relation(fields: [surveyId], references: [id], onDelete: Cascade) surveyId String contact Contact? @relation(fields: [contactId], references: [id], onDelete: Cascade) contactId String? endingId String? notes ResponseNote[] /// [ResponseData] data Json @default("{}") /// [ResponseVariables] variables Json @default("{}") /// [ResponseTtc] ttc Json @default("{}") /// [ResponseMeta] meta Json @default("{}") tags TagsOnResponses[] /// [ResponseContactAttributes] contactAttributes Json? // singleUseId, used to prevent multiple responses singleUseId String? language String? documents Document[] displayId String? @unique display Display? @relation(fields: [displayId], references: [id]) @@unique([surveyId, singleUseId]) @@index([createdAt]) @@index([surveyId, createdAt]) // to determine monthly response count @@index([contactId, createdAt]) // to determine monthly identified users (persons) @@index([surveyId]) } /// Represents notes or comments added to survey responses by team members. /// Used for internal communication and response analysis. /// /// @property id - Unique identifier for the note /// @property response - The associated survey response /// @property user - The team member who created the note /// @property text - Content of the note /// @property isResolved - Whether the note has been marked as resolved /// @property isEdited - Whether the note has been modified 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]) } /// Represents a label that can be applied to survey responses. /// Used for categorizing and organizing responses within an environment. /// /// @property id - Unique identifier for the tag /// @property name - Display name of the tag /// @property responses - Survey responses tagged with this label /// @property environment - The environment this tag belongs to 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]) } /// Junction table linking tags to responses. /// Enables many-to-many relationship between tags and responses. /// /// @property response - The tagged response /// @property tag - The tag applied to the response 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 scheduled inProgress paused completed } enum DisplayStatus { seen responded } /// Records when a survey is shown to a user. /// Tracks survey display history and response status. /// /// @property id - Unique identifier for the display event /// @property survey - The survey that was displayed /// @property contact - The contact who saw the survey /// @property status - Whether the survey was just seen or responded to /// @property response - The associated response if one exists 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 contact Contact? @relation(fields: [contactId], references: [id], onDelete: Cascade) contactId String? responseId String? @unique //deprecated status DisplayStatus? response Response? @@index([surveyId]) @@index([contactId, createdAt]) } /// Links surveys to specific trigger actions. /// Defines which user actions should cause a survey to be displayed. /// This is the connection table between Surveys and ActionClasses that determines /// when and under what conditions a survey should be triggered. /// /// @property id - Unique identifier for the trigger /// @property survey - The survey to be triggered /// @property actionClass - The action that triggers the survey /// @property createdAt - When the trigger was created /// @property updatedAt - When the trigger was last modified 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 } /// Defines targeting rules for surveys based on contact attributes. /// Used to show surveys only to contacts matching specific criteria. /// /// @property id - Unique identifier for the filter /// @property attributeKey - The contact attribute to filter on /// @property survey - The survey being filtered /// @property condition - The comparison operator to use /// @property value - The value to compare against model SurveyAttributeFilter { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") attributeKey ContactAttributeKey @relation(fields: [attributeKeyId], references: [id], onDelete: Cascade) attributeKeyId String survey Survey @relation(fields: [surveyId], references: [id], onDelete: Cascade) surveyId String condition SurveyAttributeFilterCondition value String @@unique([surveyId, attributeKeyId]) @@index([surveyId]) @@index([attributeKeyId]) } enum SurveyType { link web website app } enum displayOptions { displayOnce displayMultiple displaySome respondMultiple } /// Represents a complete survey configuration including questions, styling, and display rules. /// Core model for the survey functionality in Formbricks. /// /// @property id - Unique identifier for the survey /// @property name - Display name of the survey /// @property type - Survey delivery method (link, web, website, app) /// @property status - Current state of the survey (draft, active, completed, etc) /// @property environment - The environment this survey belongs to /// @property questions - JSON array containing survey questions configuration /// @property displayOption - Rules for how often the survey can be shown /// @property triggers - Actions that can trigger this survey /// @property attributeFilters - Rules for targeting specific contacts 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) /// [SurveyWelcomeCard] welcomeCard Json @default("{\"enabled\": false}") /// [SurveyQuestions] questions Json @default("[]") /// [SurveyEnding] endings Json[] @default([]) thankYouCard Json? //deprecated /// [SurveyHiddenFields] hiddenFields Json @default("{\"enabled\": false}") /// [SurveyVariables] variables Json @default("[]") responses Response[] displayOption displayOptions @default(displayOnce) recontactDays Int? displayLimit Int? triggers SurveyTrigger[] /// [SurveyInlineTriggers] inlineTriggers Json? attributeFilters SurveyAttributeFilter[] displays Display[] autoClose Int? autoComplete Int? delay Int @default(0) runOnDate DateTime? closeOnDate DateTime? /// [SurveyClosedMessage] surveyClosedMessage Json? segmentId String? segment Segment? @relation(fields: [segmentId], references: [id]) /// [SurveyProjectOverwrites] projectOverwrites Json? /// [SurveyStyling] styling Json? /// [SurveySingleUse] singleUse Json? @default("{\"enabled\": false, \"isEncrypted\": true}") /// [SurveyVerifyEmail] verifyEmail Json? // deprecated isVerifyEmailEnabled Boolean @default(false) isSingleResponsePerEmailEnabled Boolean @default(false) isBackButtonHidden Boolean @default(false) pin String? resultShareKey String? @unique displayPercentage Decimal? languages SurveyLanguage[] showLanguageSwitch Boolean? documents Document[] followUps SurveyFollowUp[] /// [SurveyRecaptcha] recaptcha Json? @default("{\"enabled\": false, \"threshold\":0.1}") @@index([environmentId, updatedAt]) @@index([segmentId]) } /// Defines follow-up actions for survey responses. /// Enables automated actions based on specific survey response conditions. /// /// @property id - Unique identifier for the follow-up /// @property survey - The associated survey /// @property name - Display name for the follow-up /// @property trigger - Conditions that activate the follow-up /// @property action - Actions to take when triggered model SurveyFollowUp { 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 name String /// [SurveyFollowUpTrigger] trigger Json /// [SurveyFollowUpAction] action Json } enum ActionType { code noCode } /// Represents a user action that can trigger surveys. /// Used to define points in the user journey where surveys can be shown. /// /// @property id - Unique identifier for the action /// @property name - Display name of the action /// @property type - Whether this is a code or no-code action /// @property key - Unique identifier used in code implementation /// @property noCodeConfig - Configuration for no-code setup /// @property environment - The environment this action belongs to 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 key String? /// [ActionClassNoCodeConfig] noCodeConfig Json? environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade) environmentId String surveyTriggers SurveyTrigger[] @@unique([key, environmentId]) @@unique([name, environmentId]) @@index([environmentId, createdAt]) } enum EnvironmentType { production development } enum IntegrationType { googleSheets notion airtable slack } /// Represents third-party service integrations. /// Enables data flow between Formbricks and external services. /// /// @property id - Unique identifier for the integration /// @property type - The service being integrated (Google Sheets, Notion, etc.) /// @property environment - The environment this integration belongs to /// @property config - Service-specific configuration details model Integration { id String @id @default(cuid()) type IntegrationType environmentId String /// [IntegrationConfig] config Json environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade) @@unique([type, environmentId]) @@index([environmentId]) } enum DataMigrationStatus { pending applied failed } /// Tracks database schema migrations. /// Used to manage and track the state of data structure changes. /// /// @property id - Unique identifier for the migration /// @property name - Name of the migration /// @property status - Current state of the migration (pending, applied, failed) /// @property startedAt - When the migration began /// @property finishedAt - When the migration completed model DataMigration { id String @id @default(cuid()) startedAt DateTime @default(now()) @map(name: "started_at") finishedAt DateTime? @map(name: "finished_at") name String @unique status DataMigrationStatus } /// Represents either a production or development environment within a project. /// Each project has exactly two environments, serving as the main reference point /// for most Formbricks resources including surveys and actions. /// /// @property id - Unique identifier for the environment /// @property type - Either 'production' or 'development' /// @property project - Reference to parent project /// @property widgetSetupCompleted - Tracks initial widget setup status /// @property surveys - Collection of surveys in this environment /// @property contacts - Collection of contacts/users tracked /// @property actionClasses - Defined actions that can trigger surveys /// @property attributeKeys - Custom attributes configuration model Environment { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") type EnvironmentType project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) projectId String widgetSetupCompleted Boolean @default(false) appSetupCompleted Boolean @default(false) surveys Survey[] contacts Contact[] actionClasses ActionClass[] attributeKeys ContactAttributeKey[] webhooks Webhook[] tags Tag[] segments Segment[] integration Integration[] documents Document[] insights Insight[] ApiKeyEnvironment ApiKeyEnvironment[] @@index([projectId]) } enum WidgetPlacement { bottomLeft bottomRight topLeft topRight center } /// Main grouping mechanism for resources in Formbricks. /// Each organization can have multiple projects to separate different applications or products. /// /// @property id - Unique identifier for the project /// @property name - Display name of the project /// @property organization - Reference to parent organization /// @property environments - Development and production environments /// @property styling - Project-wide styling configuration /// @property config - Project-specific configuration /// @property recontactDays - Default recontact delay for surveys /// @property placement - Default widget placement for in-app surveys model Project { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") name String organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) organizationId String environments Environment[] brandColor String? // deprecated; use styling.brandColor instead highlightBorderColor String? // deprecated /// [Styling] styling Json @default("{\"allowStyleOverwrite\":true}") /// [ProjectConfig] config Json @default("{}") 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) languages Language[] /// [Logo] logo Json? projectTeams ProjectTeam[] @@unique([organizationId, name]) @@index([organizationId]) } /// Represents the top-level organizational hierarchy in Formbricks. /// Self-hosting instances typically have a single organization, while Formbricks Cloud /// supports multiple organizations with multi-tenancy. /// /// @property id - Unique identifier for the organization /// @property name - Display name of the organization /// @property memberships - User memberships within the organization /// @property projects - Collection of projects owned by the organization /// @property billing - JSON field containing billing information /// @property whitelabel - Whitelabel configuration for the organization /// @property isAIEnabled - Controls access to AI-powered features model Organization { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") name String memberships Membership[] projects Project[] /// [OrganizationBilling] billing Json /// [OrganizationWhitelabel] whitelabel Json @default("{}") invites Invite[] isAIEnabled Boolean @default(false) teams Team[] apiKeys ApiKey[] } enum OrganizationRole { owner manager member billing } enum MembershipRole { owner admin editor developer viewer } /// Links users to organizations with specific roles. /// Manages organization membership and permissions. /// Core model for managing user access within organizations. /// /// @property organization - The organization the user belongs to /// @property user - The member user /// @property accepted - Whether the user has accepted the membership /// @property role - User's role within the organization (owner, manager, member, billing) model Membership { organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) organizationId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId String accepted Boolean @default(false) deprecatedRole MembershipRole? //deprecated role OrganizationRole @default(member) @@id([userId, organizationId]) @@index([userId]) @@index([organizationId]) } /// Represents pending invitations to join an organization. /// Used to manage the process of adding new users to an organization. /// Once accepted, invites are converted into memberships. /// /// @property id - Unique identifier for the invite /// @property email - Email address of the invited user /// @property name - Optional display name for the invited user /// @property organization - The organization sending the invite /// @property creator - The user who created the invite /// @property acceptor - The user who accepted the invite (if accepted) /// @property expiresAt - When the invite becomes invalid /// @property role - Intended role for the invited user /// @property teamIds - Teams the user will be added to upon acceptance model Invite { id String @id @default(uuid()) email String name String? organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) organizationId String creator User @relation("inviteCreatedBy", fields: [creatorId], references: [id]) creatorId String acceptor User? @relation("inviteAcceptedBy", fields: [acceptorId], references: [id], onDelete: Cascade) acceptorId String? createdAt DateTime @default(now()) expiresAt DateTime deprecatedRole MembershipRole? //deprecated role OrganizationRole @default(member) teamIds String[] @default([]) @@index([email, organizationId]) @@index([organizationId]) } /// Represents enhanced API authentication keys with organization-level ownership. /// Used for authenticating API requests to Formbricks with more granular permissions. /// /// @property id - Unique identifier for the API key /// @property label - Optional descriptive name for the key /// @property hashedKey - Securely stored API key /// @property organization - The organization this key belongs to /// @property createdBy - User ID who created this key /// @property lastUsedAt - Timestamp of last usage /// @property apiKeyEnvironments - Environments this key has access to model ApiKey { id String @id @default(cuid()) createdAt DateTime @default(now()) createdBy String? lastUsedAt DateTime? label String hashedKey String @unique organizationId String organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) apiKeyEnvironments ApiKeyEnvironment[] /// [OrganizationAccess] organizationAccess Json @default("{}") @@index([organizationId]) } /// Defines permission levels for API keys. /// Controls what operations an API key can perform. enum ApiKeyPermission { read write manage } /// Links API keys to environments with specific permissions. /// Enables granular access control for API keys across environments. /// /// @property id - Unique identifier for the environment access entry /// @property apiKey - The associated API key /// @property environment - The environment being accessed /// @property permission - Level of access granted model ApiKeyEnvironment { id String @id @default(cuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt apiKeyId String apiKey ApiKey @relation(fields: [apiKeyId], references: [id], onDelete: Cascade) environmentId String environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade) permission ApiKeyPermission @@unique([apiKeyId, environmentId]) @@index([environmentId]) } enum IdentityProvider { email github google azuread openid saml } /// Stores third-party authentication account information. /// Enables OAuth and other external authentication methods. /// /// @property id - Unique identifier for the account /// @property user - The Formbricks user who owns this account /// @property provider - The authentication provider (GitHub, Google, etc.) /// @property providerAccountId - User ID from the provider /// @property access_token - OAuth access token /// @property refresh_token - OAuth refresh token 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 } /// Represents a user in the Formbricks system. /// Central model for user authentication and profile management. /// /// @property id - Unique identifier for the user /// @property name - Display name of the user /// @property email - User's email address /// @property role - User's professional role /// @property objective - User's main goal with Formbricks /// @property twoFactorEnabled - Whether 2FA is active /// @property memberships - Organizations the user belongs to /// @property notificationSettings - User's notification preferences 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? 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? /// [UserNotificationSettings] notificationSettings Json @default("{}") /// [Locale] locale String @default("en-US") surveys Survey[] teamUsers TeamUser[] lastLoginAt DateTime? isActive Boolean @default(true) @@index([email]) } /// Maps a short URL to its full destination. /// Used for creating memorable, shortened URLs for surveys. /// /// @property id - Short identifier/slug for the URL /// @property url - The full destination URL 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 } /// Defines a segment of contacts based on attributes. /// Used for targeting surveys to specific user groups. /// /// @property id - Unique identifier for the segment /// @property title - Display name of the segment /// @property filters - Rules defining the segment /// @property isPrivate - Whether the segment is private /// @property environment - The environment this segment belongs to 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) /// [SegmentFilter] filters Json @default("[]") environmentId String environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade) surveys Survey[] @@unique([environmentId, title]) @@index([environmentId]) } /// Represents a supported language in the system. /// Used for multilingual survey support. /// /// @property id - Unique identifier for the language /// @property code - Language code (e.g., 'en-US') /// @property alias - Optional friendly name /// @property project - The project this language is enabled for model Language { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") code String alias String? project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) projectId String surveyLanguages SurveyLanguage[] @@unique([projectId, code]) } /// Links surveys to their supported languages. /// Manages which languages are available for each survey. /// /// @property language - The supported language /// @property survey - The associated survey /// @property default - Whether this is the default language /// @property enabled - Whether this language is currently active model SurveyLanguage { language Language @relation(fields: [languageId], references: [id], onDelete: Cascade) languageId String surveyId String survey Survey @relation(fields: [surveyId], references: [id], onDelete: Cascade) default Boolean @default(false) enabled Boolean @default(true) @@id([languageId, surveyId]) @@index([surveyId]) @@index([languageId]) } enum InsightCategory { featureRequest complaint praise other } /// Stores analyzed insights from survey responses. /// Used for tracking patterns and extracting meaningful information. /// /// @property id - Unique identifier for the insight /// @property category - Type of insight (feature request, complaint, etc.) /// @property title - Summary of the insight /// @property description - Detailed explanation /// @property vector - Embedding vector for similarity search model Insight { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") environmentId String environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade) category InsightCategory title String description String vector Unsupported("vector(512)")? documentInsights DocumentInsight[] } /// Links insights to source documents. /// Enables tracing insights back to original responses. /// /// @property document - The source document /// @property insight - The derived insight model DocumentInsight { documentId String document Document @relation(fields: [documentId], references: [id], onDelete: Cascade) insightId String insight Insight @relation(fields: [insightId], references: [id], onDelete: Cascade) @@id([documentId, insightId]) @@index([insightId]) } enum Sentiment { positive negative neutral } /// Represents a processed text document from survey responses. /// Used for analysis and insight generation. /// /// @property id - Unique identifier for the document /// @property survey - The associated survey /// @property response - The source response /// @property sentiment - Analyzed sentiment (positive, negative, neutral) /// @property text - The document content /// @property vector - Embedding vector for similarity search model Document { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") environmentId String environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade) surveyId String? survey Survey? @relation(fields: [surveyId], references: [id], onDelete: Cascade) responseId String? response Response? @relation(fields: [responseId], references: [id], onDelete: Cascade) questionId String? sentiment Sentiment isSpam Boolean text String vector Unsupported("vector(512)")? documentInsights DocumentInsight[] @@unique([responseId, questionId]) @@index([createdAt]) } /// Represents a team within an organization. /// Enables group-based access control and collaboration. /// /// @property id - Unique identifier for the team /// @property name - Display name of the team /// @property organization - The parent organization /// @property teamUsers - Users who are part of this team /// @property projectTeams - Projects this team has access to model Team { id String @id @default(cuid()) createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") name String organizationId String organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) teamUsers TeamUser[] projectTeams ProjectTeam[] @@unique([organizationId, name]) } enum TeamUserRole { admin contributor } /// Links users to teams with specific roles. /// Manages team membership and permissions. /// /// @property team - The associated team /// @property user - The team member /// @property role - User's role within the team model TeamUser { createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") teamId String team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) role TeamUserRole @@id([teamId, userId]) @@index([userId]) } enum ProjectTeamPermission { read readWrite manage } /// Defines team access to specific projects. /// Manages project-level permissions for teams. /// /// @property project - The accessed project /// @property team - The team receiving access /// @property permission - Level of access granted model ProjectTeam { createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @updatedAt @map(name: "updated_at") projectId String project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) teamId String team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) permission ProjectTeamPermission @default(read) @@id([projectId, teamId]) @@index([teamId]) }