SaasRock primary database models and relationships.
User, AdminUser
Tenant, TenantUser, TenantSubscription
Role, Permission, UserRole
ApiKey, ApiKeyLog
SubscriptionProduct, SubscriptionPrice, SubscriptionFeature
BlogPost, BlogCategory, BlogTag
Entity, Property, Row, RowValue, RowMedia
AnalyticsUniqueVisitor, AnalyticsPageView, AnalyticsEvent
Page, PageBlock
Onboarding, OnboardingFilter, OnboardingStep, OnboardingSession
Workflow, WorkflowBlock, WorkflowBlockCondition, WorkflowBlockToBlock, WorkflowExecution
FeatureFlag, FeatureFlagFilter
KnowledgeBase, KnowledgeBaseCategory, KnowledgeBaseArticle
MetricLog
Credit
Portal, PortalUser
I'm waiting for this issue to be fixed to split schemas into module files: Support for splitting Prisma schema into multiple files #2377.
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL") // uses connection pooling
}
model AppConfiguration {
id String @id @default(cuid())
updatedAt DateTime @updatedAt
name String
url String
theme String?
authRequireEmailVerification Boolean @default(false)
authRequireOrganization Boolean @default(true)
authRequireName Boolean @default(true)
authRecaptchaSiteKey String?
analyticsEnabled Boolean @default(true)
analyticsSimpleAnalytics Boolean @default(false)
analyticsPlausibleAnalytics Boolean @default(false)
analyticsGoogleAnalyticsTrackingId String?
subscriptionRequired Boolean @default(true)
subscriptionAllowSubscribeBeforeSignUp Boolean @default(true)
subscriptionAllowSignUpBeforeSubscribe Boolean @default(true)
cookiesEnabled Boolean @default(false)
metricsEnabled Boolean @default(false)
metricsLogToConsole Boolean @default(false)
metricsSaveToDatabase Boolean @default(false)
metricsIgnoreUrls String?
brandingLogo String?
brandingLogoDarkMode String?
brandingIcon String?
brandingIconDarkMode String?
brandingFavicon String?
}
model AppCookie {
id String @id @default(cuid())
category Int
name String
description String
enabled Boolean @default(true)
expiry String?
domain String?
type String?
href String?
}
model User {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
email String @unique
passwordHash String
firstName String
lastName String
avatar String?
phone String?
defaultTenantId String?
verifyToken String?
githubId String? @unique
googleId String? @unique
locale String?
active Boolean @default(false)
admin AdminUser? // Has access to the admin panel
createdApiKeys ApiKey[]
createdGroups Group[]
groups GroupUser[]
createdLinkedAccounts LinkedAccount[]
logs Log[]
createdRows Row[]
createdRowComments RowComment[]
createdRowCommentReactions RowCommentReaction[]
createdEntityViews EntityView[] @relation("createdByUser")
rowPermissions RowPermission[]
assignedTasks RowTask[] @relation("assignedToUser")
completedTasks RowTask[] @relation("completedByUser")
createdRowTasks RowTask[] @relation("createdByUser")
tenants TenantUser[]
invitation TenantUserInvitation? @relation("createdUser")
sentInvitations TenantUserInvitation[] @relation("fromUser")
roles UserRole[]
readEmails EmailRead[]
entityViews EntityView[]
onboardingSessions OnboardingSession[]
tags TagUser[]
tenantIpAddresses TenantIpAddress[]
promptFlowExecutions PromptFlowExecution[]
analyticsUniqueSessions AnalyticsUniqueVisitor[]
metricLogs MetricLog[]
formulaLogs FormulaLog[]
createdTenantRelationships TenantRelationship[]
integrationSyncs IntegrationSync[]
blogArticles BlogPost[]
knowledgeBaseArticles KnowledgeBaseArticle[]
events Event[]
workflowsCreated Workflow[] @relation("createdByUser")
workflowsExecuted WorkflowExecution[] @relation("executedByUser")
workflowVariablesCreated WorkflowVariable[]
workflowCredentialsCreated WorkflowCredential[]
feedback Feedback[]
credits Credit[]
portals Portal[]
}
// Has access to the admin panel
model AdminUser {
userId String @unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model Tenant {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
slug String @unique
name String
icon String?
subscriptionId String?
active Boolean @default(false)
deactivatedReason String?
apiKeys ApiKey[]
apiKeyLogs ApiKeyLog[]
groups Group[]
asClientLinkedAccounts LinkedAccount[] @relation("clientTenant")
createdLinkedAccounts LinkedAccount[] @relation("createdByTenant")
asProviderLinkedAccounts LinkedAccount[] @relation("providerTenant")
logs Log[]
rows Row[]
rowPermissions RowPermission[]
subscription TenantSubscription?
users TenantUser[]
invitations TenantUserInvitation[]
userRoles UserRole[]
inboundAddresses TenantInboundAddress[]
events Event[]
fromRegistration Registration?
entityViews EntityView[]
emailSenders EmailSender[]
campaigns Campaign[]
outboundEmails OutboundEmail[]
tags TagTenant[]
onboardingSessions OnboardingSession[]
ipAddresses TenantIpAddress[]
tenantSettingsRow TenantSettingsRow?
promptFlowExecutions PromptFlowExecution[]
metricLogs MetricLog[]
formulaLogs FormulaLog[]
types TenantType[]
fromTenants TenantRelationship[] @relation("fromTenant")
toTenants TenantRelationship[] @relation("toTenant")
integrations Integration[]
entityProperties Property[]
blogPosts BlogPost[]
blogTags BlogTag[]
blogCategories BlogCategory[]
entityGroupConfigurations EntityGroupConfiguration[]
entityTemplates EntityTemplate[]
workflows Workflow[]
workflowExecutions WorkflowExecution[]
workflowVariables WorkflowVariable[]
workflowCredentials WorkflowCredential[]
feedback Feedback[]
credits Credit[]
portals Portal[]
portalsUsers PortalUser[]
@@index([slug])
}
model Registration {
id String @id @default(cuid())
createdAt DateTime @default(now())
email String @unique
firstName String
lastName String
slug String?
token String @unique
ipAddress String?
company String?
selectedSubscriptionPriceId String?
createdTenantId String? @unique
createdTenant Tenant? @relation(fields: [createdTenantId], references: [id], onDelete: Cascade)
}
model Blacklist {
id String @id @default(cuid())
createdAt DateTime @default(now())
type String // email, domain, ip
value String
active Boolean @default(true)
registerAttempts Int @default(0)
}
model TenantSubscription {
id String @id @default(cuid())
tenantId String @unique
stripeCustomerId String?
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
products TenantSubscriptionProduct[]
}
model TenantSubscriptionProduct {
id String @id @default(cuid())
createdAt DateTime @default(now())
tenantSubscriptionId String
subscriptionProductId String
cancelledAt DateTime?
endsAt DateTime?
stripeSubscriptionId String?
quantity Int?
fromCheckoutSessionId String?
currentPeriodStart DateTime?
currentPeriodEnd DateTime?
tenantSubscription TenantSubscription @relation(fields: [tenantSubscriptionId], references: [id], onDelete: Cascade)
subscriptionProduct SubscriptionProduct @relation(fields: [subscriptionProductId], references: [id])
prices TenantSubscriptionProductPrice[]
}
model TenantSubscriptionProductPrice {
id String @id @default(cuid())
tenantSubscriptionProductId String
tenantSubscriptionProduct TenantSubscriptionProduct @relation(fields: [tenantSubscriptionProductId], references: [id], onDelete: Cascade)
subscriptionPriceId String?
subscriptionPrice SubscriptionPrice? @relation(fields: [subscriptionPriceId], references: [id])
subscriptionUsageBasedPriceId String?
subscriptionUsageBasedPrice SubscriptionUsageBasedPrice? @relation(fields: [subscriptionUsageBasedPriceId], references: [id])
usageRecords TenantSubscriptionUsageRecord[]
}
model TenantSubscriptionUsageRecord {
id String @id @default(cuid())
tenantSubscriptionProductPriceId String
tenantSubscriptionProductPrice TenantSubscriptionProductPrice @relation(fields: [tenantSubscriptionProductPriceId], references: [id], onDelete: Cascade)
timestamp Int
quantity Int
stripeSubscriptionItemId String?
}
model CheckoutSessionStatus {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
id String @unique
pending Boolean @default(true) // has not added products to tenant
email String
fromUrl String
fromUserId String?
fromTenantId String?
createdUserId String?
createdTenantId String?
}
model TenantUser {
id String @id @default(cuid())
createdAt DateTime @default(now())
tenantId String
userId String
type Int
joined Int
status Int
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
roles TenantUserRole[]
}
model Role {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
name String @unique
description String
type String
assignToNewUsers Boolean
isDefault Boolean
order Int
permissions RolePermission[]
rowPermissions RowPermission[]
users UserRole[]
}
model Permission {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
name String @unique
description String
type String
isDefault Boolean
order Int
inRoles RolePermission[]
entityId String?
entity Entity? @relation(fields: [entityId], references: [id], onDelete: Cascade)
inTenantTypeRelationships TenantTypeRelationship[]
}
model RolePermission {
id String @id @default(cuid())
roleId String
permissionId String
permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
}
model UserRole {
id String @id @default(cuid())
createdAt DateTime @default(now())
userId String
roleId String
tenantId String?
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model Group {
id String @id @default(cuid())
createdAt DateTime @default(now())
createdByUserId String
tenantId String?
name String
description String
color Int
createdByUser User @relation(fields: [createdByUserId], references: [id], onDelete: Cascade)
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
users GroupUser[]
rowPermissions RowPermission[]
@@index([createdByUserId], name: "group_createdByUserId")
}
model GroupUser {
id String @id @default(cuid())
groupId String
userId String
group Group @relation(fields: [groupId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model TenantUserRole {
id String @id @default(cuid())
tenantUserId String
order Int
name String
tenantUser TenantUser @relation(fields: [tenantUserId], references: [id], onDelete: Cascade)
}
model TenantUserInvitation {
id String @id @default(cuid())
tenantId String
email String
firstName String
lastName String
type Int
pending Boolean
createdUserId String? @unique
fromUserId String?
fromUser User? @relation(name: "fromUser", fields: [fromUserId], references: [id])
user User? @relation(name: "createdUser", fields: [createdUserId], references: [id])
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
}
model LinkedAccount {
id String @id @default(cuid())
createdAt DateTime @default(now())
createdByUserId String
createdByTenantId String
providerTenantId String
clientTenantId String
status Int
clientTenant Tenant @relation("clientTenant", fields: [clientTenantId], references: [id], onDelete: Cascade)
createdByTenant Tenant @relation("createdByTenant", fields: [createdByTenantId], references: [id], onDelete: Cascade)
createdByUser User @relation(fields: [createdByUserId], references: [id], onDelete: Cascade)
providerTenant Tenant @relation("providerTenant", fields: [providerTenantId], references: [id], onDelete: Cascade)
}
model ApiKey {
id String @id @default(cuid())
createdAt DateTime @default(now())
createdByUserId String
tenantId String
key String @default(uuid())
alias String
expires DateTime?
active Boolean
createdByUser User @relation(fields: [createdByUserId], references: [id], onDelete: Cascade)
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
entities ApiKeyEntity[]
apiKeyLogs ApiKeyLog[]
logs Log[]
createdRows Row[]
tenantIpAddresses TenantIpAddress[]
integrationSyncs IntegrationSync[]
@@unique([tenantId, alias])
@@unique([tenantId, key])
@@index([key])
}
model ApiKeyEntity {
id String @id @default(cuid())
apiKeyId String
entityId String
create Boolean
read Boolean
update Boolean
delete Boolean
apiKey ApiKey @relation(fields: [apiKeyId], references: [id], onDelete: Cascade)
entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
}
model Log {
id String @id @default(cuid())
createdAt DateTime @default(now())
tenantId String?
userId String?
apiKeyId String?
rowId String?
url String
action String
details String?
commentId String?
apiKey ApiKey? @relation(fields: [apiKeyId], references: [id], onDelete: Cascade)
comment RowComment? @relation(fields: [commentId], references: [id])
row Row? @relation(fields: [rowId], references: [id])
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
webhookLogs EntityWebhookLog[]
}
model ApiKeyLog {
id String @id @default(cuid())
createdAt DateTime @default(now())
apiKeyId String?
apiKey ApiKey? @relation(fields: [apiKeyId], references: [id], onDelete: Cascade)
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
ip String
endpoint String
method String
params String
status Int?
duration Int?
error String?
type String?
@@index([tenantId], name: "api_key_log_tenant")
@@index([tenantId, createdAt], name: "api_key_log_tenant_created_at")
@@index([tenantId, type], name: "api_key_log_tenant_type")
}
model SubscriptionProduct {
id String @id @default(cuid())
stripeId String
order Int
title String
active Boolean
model Int
public Boolean
groupTitle String?
groupDescription String?
description String?
badge String?
billingAddressCollection String @default("auto")
hasQuantity Boolean @default(false)
canBuyAgain Boolean @default(false)
prices SubscriptionPrice[]
features SubscriptionFeature[]
tenantProducts TenantSubscriptionProduct[]
usageBasedPrices SubscriptionUsageBasedPrice[]
assignsTenantTypes TenantType[]
}
model SubscriptionPrice {
id String @id @default(cuid())
subscriptionProductId String
subscriptionProduct SubscriptionProduct @relation(fields: [subscriptionProductId], references: [id], onDelete: Cascade)
stripeId String
type Int
billingPeriod Int
price Decimal
currency String
trialDays Int
active Boolean
tenantProductPrices TenantSubscriptionProductPrice[]
}
model SubscriptionUsageBasedPrice {
id String @id @default(cuid())
subscriptionProductId String
subscriptionProduct SubscriptionProduct @relation(fields: [subscriptionProductId], references: [id], onDelete: Cascade)
stripeId String
billingPeriod Int
currency String
unit String
unitTitle String
unitTitlePlural String
usageType String
aggregateUsage String
tiersMode String
billingScheme String
tiers SubscriptionUsageBasedTier[]
tenantProductPrices TenantSubscriptionProductPrice[]
}
model SubscriptionUsageBasedTier {
id String @id @default(cuid())
subscriptionUsageBasedPriceId String
subscriptionUsageBasedPrice SubscriptionUsageBasedPrice @relation(fields: [subscriptionUsageBasedPriceId], references: [id], onDelete: Cascade)
from Int
to Int?
perUnitPrice Decimal?
flatFeePrice Decimal?
}
model SubscriptionFeature {
id String @id @default(cuid())
subscriptionProductId String
order Int
title String
name String
type Int
value Int
href String?
badge String?
accumulate Boolean @default(false)
subscriptionProduct SubscriptionProduct @relation(fields: [subscriptionProductId], references: [id], onDelete: Cascade)
}
model BlogCategory {
id String @id @default(cuid())
createdAt DateTime @default(now())
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
name String
color Int
posts BlogPost[]
@@unique([tenantId, name])
}
model BlogTag {
id String @id @default(cuid())
createdAt DateTime @default(now())
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
name String @unique
color Int
posts BlogPostTag[]
}
model BlogPostTag {
id String @id @default(cuid())
postId String
tagId String
post BlogPost @relation(fields: [postId], references: [id], onDelete: Cascade)
tag BlogTag @relation(fields: [tagId], references: [id], onDelete: Cascade)
}
model BlogPost {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime? @updatedAt
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
slug String
title String
description String
date DateTime
image String
content String
readingTime String
published Boolean
authorId String?
categoryId String?
contentType String @default("markdown")
author User? @relation(fields: [authorId], references: [id], onDelete: Cascade)
category BlogCategory? @relation(fields: [categoryId], references: [id], onDelete: Cascade)
tags BlogPostTag[]
@@unique([tenantId, slug])
}
// <--- START: Entities --->
// TODO: Wrap entities in modules (e.g. CRM, HelpDesk...)
model Module {
id String @id @default(cuid())
type String @default("app") // app, admin, all
order Int
name String @unique
title String
description String
icon String
entities Entity[]
}
model Entity {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
moduleId String?
name String @unique
slug String @unique
order Int
prefix String @unique
type String @default("app") // app, admin, all
title String
titlePlural String
isAutogenerated Boolean
hasApi Boolean
icon String
active Boolean
showInSidebar Boolean @default(true)
hasTags Boolean @default(true)
hasComments Boolean @default(true)
hasTasks Boolean @default(true)
hasActivity Boolean @default(true)
hasBulkDelete Boolean @default(false)
hasViews Boolean @default(true)
defaultVisibility String @default("private")
onCreated String? @default("redirectToOverview") // redirectToOverview, redirectToNew, redirectToList, redirectToEdit, addAnother
onEdit String? @default("editRoute") // editRoute, overviewRoute, overviewAlwaysEditable
promptFlowGroupId String?
createdPermissions Permission[]
apiKeys ApiKeyEntity[]
tags EntityTag[]
permissions EntityTenantUserPermission[]
webhooks EntityWebhook[]
properties Property[]
rows Row[]
views EntityView[]
parentEntities EntityRelationship[] @relation(name: "childEntities")
childEntities EntityRelationship[] @relation(name: "parentEntities")
module Module? @relation(fields: [moduleId], references: [id])
groups EntityGroupEntity[]
promptFlowGroup PromptFlowGroupEntity[]
inTenantTypes TenantTypeEntity[]
promptFlows PromptFlow[]
inPromptFlowOutputs PromptFlowOutput[]
integrationObjectMappings IntegrationObjectMap[]
integrationSyncLogs IntegrationSyncLog[]
templates EntityTemplate[]
@@index([name], name: "entity_name")
@@index([slug], name: "entity_slug")
}
model Property {
id String @id @default(cuid())
entityId String
order Int
name String
title String
type Int
subtype String?
isDefault Boolean @default(false)
isRequired Boolean @default(false)
isHidden Boolean @default(false)
isDisplay Boolean @default(false)
isUnique Boolean @default(false) // TODO: Validate uniqueness
isReadOnly Boolean @default(false)
showInCreate Boolean @default(true)
canUpdate Boolean @default(true)
formulaId String?
formula Formula? @relation(fields: [formulaId], references: [id], onDelete: Cascade)
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id])
attributes PropertyAttribute[]
entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
options PropertyOption[]
values RowValue[]
inViewProperties EntityViewProperty[]
inViewGroupBy EntityView[]
inPromptFlowMappings PromptFlowOutputMapping[]
integrationPropertyMappings IntegrationPropertyMap[]
@@unique([entityId, name, tenantId])
@@unique([entityId, title, tenantId])
@@index([entityId], name: "entity_property")
@@index([entityId, name], name: "entity_property_name")
}
model EntityView {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdByUserId String?
createdByUser User? @relation(name: "createdByUser", fields: [createdByUserId], references: [id])
entityId String
entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
userId String?
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
layout String @default("table") // table, board, calendar, list, gallery...
order Int
name String
title String
pageSize Int
isDefault Boolean
isSystem Boolean @default(false)
gridColumns Int? @default(5)
gridColumnsSm Int? @default(2)
gridColumnsMd Int? @default(3)
gridColumnsLg Int? @default(4)
gridColumnsXl Int? @default(5)
gridColumns2xl Int? @default(6)
gridGap String? @default("sm")
properties EntityViewProperty[]
filters EntityViewFilter[]
sort EntityViewSort[]
groupByPropertyId String?
groupByProperty Property? @relation(fields: [groupByPropertyId], references: [id], onDelete: Cascade)
inGroups EntityGroupEntity[]
inChildRelationships EntityRelationship[] @relation(name: "childEntityView")
inParentRelationships EntityRelationship[] @relation(name: "parentEntityView")
@@index([entityId], name: "entity_view")
@@index([entityId, name], name: "entity_view_name")
}
model EntityViewProperty {
id String @id @default(cuid())
entityViewId String
entityView EntityView @relation(fields: [entityViewId], references: [id], onDelete: Cascade)
propertyId String?
property Property? @relation(fields: [propertyId], references: [id], onDelete: Cascade)
name String? // if not a property, e.g. "default.folio"
order Int
@@index([entityViewId], name: "entity_view_property")
@@index([entityViewId, name], name: "entity_view_property_name")
}
model EntityViewFilter {
id String @id @default(cuid())
entityViewId String
entityView EntityView @relation(fields: [entityViewId], references: [id], onDelete: Cascade)
match String @default("and") // and, or
name String
condition String // is, isNot, contains, doesNotContain...
value String
@@index([entityViewId], name: "entity_view_filter")
@@index([entityViewId, name], name: "entity_view_filter_name")
}
model EntityViewSort {
id String @id @default(cuid())
entityViewId String
entityView EntityView @relation(fields: [entityViewId], references: [id], onDelete: Cascade)
name String
asc Boolean
order Int
@@index([entityViewId], name: "entity_view_sort")
@@index([entityViewId, name], name: "entity_view_sort_name")
}
model PropertyAttribute {
id String @id @default(cuid())
propertyId String
property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade)
name String // pattern, min, max, step, rows, defaultValue, maxSize, acceptFileTypes, uppercase...
value String
@@unique([propertyId, name])
@@index([propertyId], name: "property_attribute")
@@index([propertyId, name], name: "property_attribute_name")
}
model PropertyOption {
id String @id @default(cuid())
propertyId String
order Int
value String
name String?
color Int @default(0)
property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade)
// values RowValueSelection[]
@@index([propertyId], name: "property_option")
@@index([propertyId, name], name: "property_option_name")
}
model EntityTag {
id String @id @default(cuid())
createdAt DateTime @default(now())
entityId String
value String
color Int
entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
rowTags RowTag[]
@@index([entityId], name: "entity_tag")
@@index([entityId, value], name: "entity_tag_value")
}
model EntityTenantUserPermission {
id String @id @default(cuid())
entityId String
level Int
entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
}
model EntityWebhook {
id String @id @default(cuid())
entityId String
action String
method String
endpoint String
entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
logs EntityWebhookLog[]
}
model EntityWebhookLog {
id String @id @default(cuid())
webhookId String
logId String
status Int
error String?
log Log @relation(fields: [logId], references: [id], onDelete: Cascade)
webhook EntityWebhook @relation(fields: [webhookId], references: [id], onDelete: Cascade)
}
model EntityRelationship {
id String @id @default(cuid())
parentId String
parent Entity @relation(name: "parentEntities", fields: [parentId], references: [id], onDelete: Cascade)
childId String
child Entity @relation(name: "childEntities", fields: [childId], references: [id], onDelete: Cascade)
order Int?
title String?
type String @default("one-to-many")
required Boolean @default(false)
cascade Boolean @default(false)
readOnly Boolean @default(false)
hiddenIfEmpty Boolean @default(false)
childEntityViewId String?
childEntityView EntityView? @relation(name: "childEntityView", fields: [childEntityViewId], references: [id], onDelete: Cascade)
parentEntityViewId String?
parentEntityView EntityView? @relation(name: "parentEntityView", fields: [parentEntityViewId], references: [id], onDelete: Cascade)
rows RowRelationship[]
@@unique([parentId, childId, title])
@@index([parentId], name: "parent_entity_relationship")
@@index([childId], name: "child_entity_relationship")
@@index([parentId, childId], name: "parent_child_entity_relationship")
@@index([parentId, childId, order], name: "parent_child_entity_relationship_order")
}
model SampleCustomEntity {
rowId String @unique
row Row @relation(fields: [rowId], references: [id], onDelete: Cascade)
customText String
customNumber Decimal
customDate DateTime
customBoolean Boolean
customSelect String
}
model RowRelationship {
id String @id @default(cuid())
createdAt DateTime @default(now())
relationshipId String
relationship EntityRelationship @relation(fields: [relationshipId], references: [id], onDelete: Cascade)
parentId String
parent Row @relation(name: "parentRow", fields: [parentId], references: [id], onDelete: Cascade)
childId String
child Row @relation(name: "childRow", fields: [childId], references: [id], onDelete: Cascade)
metadata String?
integrationSyncLogs IntegrationSyncLog[]
@@unique([parentId, childId])
@@index([parentId], name: "parent_row_relationship")
@@index([childId], name: "child_row_relationship")
@@index([parentId, childId], name: "parent_child_row_relationship")
}
model Row {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
entityId String
tenantId String?
folio Int
createdByUserId String?
createdByApiKeyId String?
order Int @default(0)
createdByApiKey ApiKey? @relation(fields: [createdByApiKeyId], references: [id])
createdByUser User? @relation(fields: [createdByUserId], references: [id])
entity Entity @relation(fields: [entityId], references: [id])
tenant Tenant? @relation(fields: [tenantId], references: [id])
logs Log[]
comments RowComment[]
permissions RowPermission[]
tags RowTag[]
tasks RowTask[]
values RowValue[]
childRows RowRelationship[] @relation("parentRow")
parentRows RowRelationship[] @relation("childRow")
sampleCustomEntity SampleCustomEntity?
outboundEmails OutboundEmail[]
tenantSettingsRow TenantSettingsRow[]
formulaCalculationLogs FormulaComponentLog[]
integrationSyncLogs IntegrationSyncLog[]
integrationRows IntegrationRow[]
inEntityGroupConfigurationRows EntityGroupConfigurationRow[]
@@index([deletedAt], name: "row_deletedAt")
@@index([entityId], name: "row_entity")
@@index([entityId, tenantId], name: "row_entity_tenant")
@@index([entityId, tenantId, createdAt], name: "row_entity_tenant_created_at")
@@index([tenantId], name: "row_tenant")
@@index([createdByUserId], name: "row_createdByUserId")
}
model RowValue {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime? @updatedAt
rowId String
propertyId String
textValue String?
numberValue Decimal?
dateValue DateTime?
booleanValue Boolean?
// selection RowValueSelection[] // TODO: MULTI SELECT
property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade)
row Row @relation(fields: [rowId], references: [id], onDelete: Cascade)
media RowMedia[]
multiple RowValueMultiple[]
range RowValueRange?
@@index([rowId], name: "row_value_row")
@@index([rowId, propertyId], name: "row_value_row_property")
}
model RowValueMultiple {
id String @id @default(cuid())
rowValueId String
order Int
value String
rowValue RowValue @relation(fields: [rowValueId], references: [id], onDelete: Cascade)
@@index([rowValueId], name: "row_value_multiple_row_value")
}
model RowValueRange {
rowValueId String @unique
numberMin Decimal?
numberMax Decimal?
dateMin DateTime?
dateMax DateTime?
rowValue RowValue @relation(fields: [rowValueId], references: [id], onDelete: Cascade)
@@index([rowValueId], name: "row_value_range_row_value")
}
// // TODO: MULTI SELECT
// model RowValueSelection {
// id String @id @default(cuid())
// rowValueId String
// propertyOptionId String
// propertyOption PropertyOption @relation(fields: [propertyOptionId], references: [id], onDelete: Cascade)
// rowValue RowValue @relation(fields: [rowValueId], references: [id], onDelete: Cascade)
// }
model RowPermission {
id String @id @default(cuid())
rowId String
tenantId String?
roleId String?
groupId String?
userId String?
public Boolean?
access String @default("view")
group Group? @relation(fields: [groupId], references: [id], onDelete: Cascade)
role Role? @relation(fields: [roleId], references: [id], onDelete: Cascade)
row Row @relation(fields: [rowId], references: [id], onDelete: Cascade)
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([rowId], name: "row_permission_row")
@@index([rowId, tenantId], name: "row_permission_row_tenant")
@@index([rowId, roleId], name: "row_permission_row_role")
@@index([rowId, groupId], name: "row_permission_row_group")
@@index([rowId, userId], name: "row_permission_row_user")
@@index([public], name: "row_permission_public")
}
model RowMedia {
id String @id @default(cuid())
rowValueId String
title String
name String
file String
type String
publicUrl String?
storageBucket String?
storageProvider String?
rowValue RowValue @relation(fields: [rowValueId], references: [id], onDelete: Cascade)
@@index([rowValueId], name: "row_media_row_value")
@@index([rowValueId, name], name: "row_media_row_value_name")
}
model RowTag {
id String @id @default(cuid())
createdAt DateTime @default(now())
rowId String
tagId String
row Row @relation(fields: [rowId], references: [id], onDelete: Cascade)
tag EntityTag @relation(fields: [tagId], references: [id], onDelete: Cascade)
@@index([rowId], name: "row_tag_row")
@@index([rowId, tagId], name: "row_tag_row_tag")
}
model RowComment {
id String @id @default(cuid())
createdAt DateTime @default(now())
createdByUserId String
rowId String
value String
isDeleted Boolean?
createdByUser User @relation(fields: [createdByUserId], references: [id], onDelete: Cascade)
row Row @relation(fields: [rowId], references: [id], onDelete: Cascade)
logs Log[]
reactions RowCommentReaction[]
@@index([rowId], name: "row_comment_row")
}
model RowCommentReaction {
id String @id @default(cuid())
createdAt DateTime @default(now())
createdByUserId String
rowCommentId String
reaction String
createdByUser User @relation(fields: [createdByUserId], references: [id], onDelete: Cascade)
rowComment RowComment @relation(fields: [rowCommentId], references: [id], onDelete: Cascade)
}
model RowTask {
id String @id @default(cuid())
createdAt DateTime @default(now())
createdByUserId String
rowId String
title String
description String
completed Boolean
completedAt DateTime?
completedByUserId String?
assignedToUserId String?
deadline DateTime?
assignedToUser User? @relation("assignedToUser", fields: [assignedToUserId], references: [id], onDelete: Cascade)
completedByUser User? @relation("completedByUser", fields: [completedByUserId], references: [id], onDelete: Cascade)
createdByUser User @relation("createdByUser", fields: [createdByUserId], references: [id], onDelete: Cascade)
row Row @relation(fields: [rowId], references: [id], onDelete: Cascade)
}
model EntityTemplate {
id String @id @default(cuid())
createdAt DateTime @default(now())
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
entityId String
entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
title String
config String
@@unique([tenantId, entityId, title])
}
// <--- END: Entities --->
// <--- START: Inbound Emails --->
model TenantInboundAddress {
id String @id @default(cuid())
tenantId String
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
address String @unique
email Email[]
}
model Email {
id String @id @default(cuid())
tenantInboundAddressId String?
tenantInboundAddress TenantInboundAddress? @relation(fields: [tenantInboundAddressId], references: [id], onDelete: Cascade)
messageId String @unique
type String // inbound, outbound
date DateTime
subject String
fromEmail String
fromName String?
toEmail String
toName String?
textBody String
htmlBody String
reads EmailRead[]
attachments EmailAttachment[]
cc EmailCc[]
}
model EmailRead {
id String @id @default(cuid())
createdAt DateTime @default(now())
emailId String
email Email @relation(fields: [emailId], references: [id], onDelete: Cascade)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model EmailCc {
id String @id @default(cuid())
emailId String
toEmail String
toName String?
email Email @relation(fields: [emailId], references: [id], onDelete: Cascade)
}
model EmailAttachment {
id String @id @default(cuid())
emailId String
name String
type String
length Int
content String
publicUrl String?
storageBucket String?
storageProvider String?
email Email @relation(fields: [emailId], references: [id], onDelete: Cascade)
}
// <--- END: Inbound Emails --->
// <--- START: Events --->
model Event {
id String @id @default(cuid())
createdAt DateTime @default(now())
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id])
userId String?
user User? @relation(fields: [userId], references: [id])
name String
data String
resource String?
description String?
attempts EventWebhookAttempt[]
}
model EventWebhookAttempt {
id String @id @default(cuid())
createdAt DateTime @default(now())
startedAt DateTime?
finishedAt DateTime?
eventId String
event Event @relation(fields: [eventId], references: [id], onDelete: Cascade)
endpoint String
success Boolean?
status Int?
message String?
body String?
}
// <--- END: Events --->
// <!--- Analytics --->
model AnalyticsSettings {
id String @id @default(cuid())
public Boolean @default(false)
ignorePages String
onlyPages String
}
model AnalyticsUniqueVisitor {
id String @id @default(cuid())
createdAt DateTime @default(now())
cookie String @unique
via String?
httpReferrer String?
browser String?
browserVersion String?
os String?
osVersion String?
device String?
source String?
medium String?
campaign String?
content String?
term String?
country String?
city String?
fromUrl String?
fromRoute String?
pageViews AnalyticsPageView[]
events AnalyticsEvent[]
userId String?
user User? @relation(fields: [userId], references: [id])
portalId String?
portal Portal? @relation(fields: [portalId], references: [id], onDelete: Cascade)
}
model AnalyticsPageView {
id String @id @default(cuid())
createdAt DateTime @default(now())
uniqueVisitorId String
uniqueVisitor AnalyticsUniqueVisitor @relation(fields: [uniqueVisitorId], references: [id], onDelete: Cascade)
url String
route String?
portalId String?
portal Portal? @relation(fields: [portalId], references: [id], onDelete: Cascade)
}
model AnalyticsEvent {
id String @id @default(cuid())
createdAt DateTime @default(now())
uniqueVisitorId String
uniqueVisitor AnalyticsUniqueVisitor @relation(fields: [uniqueVisitorId], references: [id], onDelete: Cascade)
action String
category String?
label String?
value String?
url String?
route String?
featureFlagId String?
featureFlag FeatureFlag? @relation(fields: [featureFlagId], references: [id])
portalId String?
portal Portal? @relation(fields: [portalId], references: [id], onDelete: Cascade)
}
// <!--- Email marketing --->
model EmailSender {
id String @id @default(cuid())
tenantId String?
provider String
stream String
apiKey String
fromEmail String
fromName String?
replyToEmail String?
tenant Tenant? @relation(fields: [tenantId], references: [id])
campaigns Campaign[]
outboundEmails OutboundEmail[]
}
model Campaign {
id String @id @default(cuid())
tenantId String?
emailSenderId String
name String
subject String
htmlBody String
textBody String?
status String @default("draft")
track Boolean
sentAt DateTime?
emailSender EmailSender @relation(fields: [emailSenderId], references: [id])
recipients OutboundEmail[]
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
}
model OutboundEmail {
id String @id @default(cuid())
createdAt DateTime @default(now())
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
campaignId String?
campaign Campaign? @relation(fields: [campaignId], references: [id], onDelete: Cascade)
contactRowId String?
contactRow Row? @relation(fields: [contactRowId], references: [id])
email String
fromSenderId String
isPreview Boolean?
error String?
sentAt DateTime?
deliveredAt DateTime?
bouncedAt DateTime?
spamComplainedAt DateTime?
unsubscribedAt DateTime?
fromSender EmailSender @relation(fields: [fromSenderId], references: [id])
opens OutboundEmailOpen[]
clicks OutboundEmailClick[]
}
model OutboundEmailOpen {
id String @id @default(cuid())
createdAt DateTime @default(now())
firstOpen Boolean
outboundEmailId String
outboundEmail OutboundEmail @relation(fields: [outboundEmailId], references: [id], onDelete: Cascade)
}
model OutboundEmailClick {
id String @id @default(cuid())
createdAt DateTime @default(now())
link String
outboundEmailId String
outboundEmail OutboundEmail @relation(fields: [outboundEmailId], references: [id], onDelete: Cascade)
}
model Page {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
slug String
isPublished Boolean @default(false)
isPublic Boolean @default(false)
metaTags PageMetaTag[]
blocks PageBlock[]
}
model PageMetaTag {
id String @id @default(cuid())
pageId String?
page Page? @relation(fields: [pageId], references: [id], onDelete: Cascade)
order Int?
name String
value String
@@unique([pageId, name, value])
}
model PageBlock {
id String @id @default(cuid())
pageId String
page Page @relation(fields: [pageId], references: [id])
order Int
type String // hero, gallery, logoClouds, video...
value String
}
model Tag {
id String @id @default(cuid())
name String @unique
color Int?
users TagUser[]
tenants TagTenant[]
}
model TagUser {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id])
tagId String
tag Tag @relation(fields: [tagId], references: [id])
}
model TagTenant {
id String @id @default(cuid())
tenantId String
tenant Tenant @relation(fields: [tenantId], references: [id])
tagId String
tag Tag @relation(fields: [tagId], references: [id])
}
model Onboarding {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String
type String // modal, page
realtime Boolean @default(false)
active Boolean @default(false)
canBeDismissed Boolean @default(true)
height String?
filters OnboardingFilter[]
steps OnboardingStep[]
sessions OnboardingSession[]
}
model OnboardingFilter {
id String @id @default(cuid())
createdAt DateTime @default(now())
onboardingId String
onboarding Onboarding @relation(fields: [onboardingId], references: [id], onDelete: Cascade)
type String
value String?
matches OnboardingSessionFilterMatch[]
}
model OnboardingStep {
id String @id @default(cuid())
onboardingId String
onboarding Onboarding @relation(fields: [onboardingId], references: [id], onDelete: Cascade)
order Int
block String
sessionSteps OnboardingSessionStep[]
}
model OnboardingSession {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
onboardingId String
onboarding Onboarding @relation(fields: [onboardingId], references: [id], onDelete: Cascade)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
status String // active, completed, dismissed
startedAt DateTime?
completedAt DateTime?
dismissedAt DateTime?
createdRealtime Boolean @default(false)
matches OnboardingSessionFilterMatch[]
sessionSteps OnboardingSessionStep[]
actions OnboardingSessionAction[]
@@unique([onboardingId, userId, tenantId])
}
model OnboardingSessionAction {
id String @id @default(cuid())
createdAt DateTime @default(now())
onboardingSessionId String
onboardingSession OnboardingSession @relation(fields: [onboardingSessionId], references: [id], onDelete: Cascade)
type String
name String
value String
}
model OnboardingSessionFilterMatch {
id String @id @default(cuid())
onboardingFilterId String
onboardingFilter OnboardingFilter @relation(fields: [onboardingFilterId], references: [id], onDelete: Cascade)
onboardingSessionId String
onboardingSession OnboardingSession @relation(fields: [onboardingSessionId], references: [id], onDelete: Cascade)
}
model OnboardingSessionStep {
id String @id @default(cuid())
onboardingSessionId String
onboardingSession OnboardingSession @relation(fields: [onboardingSessionId], references: [id], onDelete: Cascade)
stepId String
step OnboardingStep @relation(fields: [stepId], references: [id], onDelete: Cascade)
seenAt DateTime?
completedAt DateTime?
}
model TenantIpAddress {
id String @id @default(cuid())
tenantId String
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
userId String?
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
apiKeyId String?
apiKey ApiKey? @relation(fields: [apiKeyId], references: [id], onDelete: Cascade)
ip String
fromUrl String
createdAt DateTime @default(now())
@@unique([tenantId, ip, userId, apiKeyId])
}
model FeatureFlag {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
name String
description String
enabled Boolean @default(false)
events AnalyticsEvent[]
filters FeatureFlagFilter[]
@@unique([name, description])
}
model FeatureFlagFilter {
id String @id @default(cuid())
createdAt DateTime @default(now())
featureFlagId String
featureFlag FeatureFlag @relation(fields: [featureFlagId], references: [id], onDelete: Cascade)
type String // [FeatureFlagsFilterType] percentage, darkMode, language.is, page.is, analytics.browser.is...
value String? // 0-100, true, false, en, de, fr, ...
action String?
}
model TenantSettingsRow {
tenantId String @unique
rowId String
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
row Row @relation(fields: [rowId], references: [id], onDelete: Cascade)
}
model PromptFlowGroup {
id String @id @default(cuid())
createdAt DateTime @default(now())
order Int
title String
description String
templates PromptFlowGroupTemplate[]
promptFlows PromptFlow[]
entities PromptFlowGroupEntity[]
}
model PromptFlowGroupTemplate {
id String @id @default(cuid())
createdAt DateTime @default(now())
order Int
title String
promptFlowGroupId String
promptFlowGroup PromptFlowGroup @relation(fields: [promptFlowGroupId], references: [id], onDelete: Cascade)
}
model PromptFlowGroupEntity {
entityId String
entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
promptFlowGroupId String
promptFlowGroup PromptFlowGroup @relation(fields: [promptFlowGroupId], references: [id], onDelete: Cascade)
@@id([entityId, promptFlowGroupId])
}
model PromptFlow {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
model String // gpt-3.5-turbo, gpt-4...
title String
description String
actionTitle String?
executionType String @default("sequential") // sequential, parallel
promptFlowGroupId String?
stream Boolean @default(false)
public Boolean @default(true)
inputVariables PromptFlowInputVariable[]
inputEntityId String?
inputEntity Entity? @relation(fields: [inputEntityId], references: [id], onDelete: Cascade)
promptFlowGroup PromptFlowGroup? @relation(fields: [promptFlowGroupId], references: [id], onDelete: Cascade)
templates PromptTemplate[]
executions PromptFlowExecution[]
outputs PromptFlowOutput[]
}
model PromptFlowInputVariable {
id String @id @default(cuid())
promptFlowId String
promptFlow PromptFlow @relation(fields: [promptFlowId], references: [id], onDelete: Cascade)
type String
name String
title String
isRequired Boolean
}
model PromptTemplate {
id String @id @default(cuid())
flowId String
flow PromptFlow @relation(fields: [flowId], references: [id], onDelete: Cascade)
order Int
title String
template String
temperature Decimal
maxTokens Int?
generations Int?
results PromptTemplateResult[]
inPromptFlowMappings PromptFlowOutputMapping[]
}
model PromptFlowOutput {
id String @id @default(cuid())
promptFlowId String
promptFlow PromptFlow @relation(fields: [promptFlowId], references: [id], onDelete: Cascade)
type String
entityId String
entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
mappings PromptFlowOutputMapping[]
}
model PromptFlowOutputMapping {
id String @id @default(cuid())
promptFlowOutputId String
promptFlowOutput PromptFlowOutput @relation(fields: [promptFlowOutputId], references: [id], onDelete: Cascade)
promptTemplateId String
promptTemplate PromptTemplate @relation(fields: [promptTemplateId], references: [id], onDelete: Cascade)
propertyId String
property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade)
@@unique([promptFlowOutputId, promptTemplateId, propertyId])
}
model PromptFlowExecution {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
flowId String
flow PromptFlow @relation(fields: [flowId], references: [id], onDelete: Cascade)
model String?
userId String?
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
status String // pending, running, success, error
error String?
startedAt DateTime?
completedAt DateTime?
duration Int?
results PromptTemplateResult[]
}
model PromptTemplateResult {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
flowExecutionId String
flowExecution PromptFlowExecution @relation(fields: [flowExecutionId], references: [id])
templateId String?
template PromptTemplate? @relation(fields: [templateId], references: [id])
order Int
status String // pending, running, success, error
prompt String
response String?
error String?
startedAt DateTime?
completedAt DateTime?
}
model MetricLog {
id String @id @default(cuid())
createdAt DateTime @default(now())
env String
type String // loader, action
route String
url String
function String
duration Int
userId String?
tenantId String?
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
}
model Formula {
id String @id @default(cuid())
createdAt DateTime @default(now())
name String
description String?
resultAs String // string, number, boolean, date
calculationTrigger String // one or many: always, onList, onCreated, onOverview, onEdit, custom, manual
withLogs Boolean @default(false)
components FormulaComponent[]
inProperties Property[]
logs FormulaLog[]
}
model FormulaComponent {
id String @id @default(cuid())
formulaId String
formula Formula @relation(fields: [formulaId], references: [id], onDelete: Cascade)
order Int
type String //name, operator, parenthesis, value
value String
}
model FormulaLog {
id String @id @default(cuid())
createdAt DateTime @default(now())
formulaId String
userId String?
tenantId String?
originalTrigger String?
triggeredBy String
expression String
result String
duration Int @default(0)
error String?
rowValueId String?
formula Formula @relation(fields: [formulaId], references: [id], onDelete: Cascade)
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
components FormulaComponentLog[]
}
model FormulaComponentLog {
id String @id @default(cuid())
order Int
type String //name, operator, parenthesis, value
value String
rowId String?
row Row? @relation(fields: [rowId], references: [id], onDelete: Cascade)
formulaLogId String
formulaLog FormulaLog @relation(fields: [formulaLogId], references: [id], onDelete: Cascade)
}
model EntityGroup {
id String @id @default(cuid())
createdAt DateTime @default(now())
order Int
slug String
title String
icon String
collapsible Boolean
section String?
entities EntityGroupEntity[]
configurationRows EntityGroupConfiguration[]
@@unique([slug])
}
model EntityGroupEntity {
id String @id @default(cuid())
entityGroupId String
entityGroup EntityGroup @relation(fields: [entityGroupId], references: [id], onDelete: Cascade)
entityId String
entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
allViewId String?
allView EntityView? @relation(fields: [allViewId], references: [id], onDelete: Cascade)
selectMin Int?
selectMax Int?
}
model TenantType {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String @unique
titlePlural String
description String?
isDefault Boolean @default(false)
tenants Tenant[]
fromTypes TenantTypeRelationship[] @relation("fromType")
toTypes TenantTypeRelationship[] @relation("toType")
subscriptionProducts SubscriptionProduct[]
entities TenantTypeEntity[]
}
model TenantTypeEntity {
id String @id @default(cuid())
tenantTypeId String?
tenantType TenantType? @relation(fields: [tenantTypeId], references: [id], onDelete: Cascade)
entityId String
entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
enabled Boolean
}
model TenantTypeRelationship {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
canCreate Boolean @default(false)
fromTypeId String?
toTypeId String?
fromType TenantType? @relation(name: "fromType", fields: [fromTypeId], references: [id], onDelete: Cascade)
toType TenantType? @relation(name: "toType", fields: [toTypeId], references: [id], onDelete: Cascade)
permissions Permission[]
relationships TenantRelationship[]
@@unique([fromTypeId, toTypeId])
}
model TenantRelationship {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenantTypeRelationshipId String
fromTenantId String
toTenantId String
createdByUserId String?
tenantTypeRelationship TenantTypeRelationship @relation(fields: [tenantTypeRelationshipId], references: [id], onDelete: Cascade)
fromTenant Tenant @relation(name: "fromTenant", fields: [fromTenantId], references: [id], onDelete: Cascade)
toTenant Tenant @relation(name: "toTenant", fields: [toTenantId], references: [id], onDelete: Cascade)
createdByUser User? @relation(fields: [createdByUserId], references: [id], onDelete: Cascade)
@@unique([fromTenantId, toTenantId])
}
model Integration {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
type String
config String
tenantId String?
isAdmin Boolean @default(false)
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
objectMappings IntegrationObjectMap[]
syncs IntegrationSync[]
@@unique([type, isAdmin, tenantId])
}
model IntegrationObjectMap {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
integrationId String
integration Integration @relation(fields: [integrationId], references: [id], onDelete: Cascade)
fromName String
fromTitle String
toEntityId String
toEntity Entity @relation(fields: [toEntityId], references: [id], onDelete: Cascade)
propertyMappings IntegrationPropertyMap[]
rows IntegrationRow[]
}
model IntegrationPropertyMap {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
objectMapId String
objectMap IntegrationObjectMap @relation(fields: [objectMapId], references: [id], onDelete: Cascade)
fromName String
fromTitle String
fromType String
type String // default, custom
isUnique Boolean @default(false)
toPropertyId String
toProperty Property @relation(fields: [toPropertyId], references: [id], onDelete: Cascade)
}
model IntegrationSync {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
integrationId String
integration Integration @relation(fields: [integrationId], references: [id], onDelete: Cascade)
startedAt DateTime?
completedAt DateTime?
duration Int?
status String
error String?
createdByUserId String?
createdByUser User? @relation(fields: [createdByUserId], references: [id], onDelete: Cascade)
createdByApiKeyId String?
createdByApiKey ApiKey? @relation(fields: [createdByApiKeyId], references: [id], onDelete: Cascade)
logs IntegrationSyncLog[]
}
model IntegrationSyncLog {
id String @id @default(cuid())
createdAt DateTime @default(now())
syncId String
sync IntegrationSync @relation(fields: [syncId], references: [id], onDelete: Cascade)
type String
operation String
details String
entityId String
entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
rowId String?
row Row? @relation(fields: [rowId], references: [id])
relationshipId String?
relationship RowRelationship? @relation(fields: [relationshipId], references: [id])
}
model IntegrationRow {
id String @id @default(cuid())
objectMapId String
objectMap IntegrationObjectMap @relation(fields: [objectMapId], references: [id], onDelete: Cascade)
rowId String
row Row @relation(fields: [rowId], references: [id])
externalId String
}
model KnowledgeBase {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
basePath String
slug String
title String
description String
defaultLanguage String
layout String
color Int
enabled Boolean
languages String
links String
logo String
seoImage String
categories KnowledgeBaseCategory[]
articles KnowledgeBaseArticle[]
views KnowledgeBaseViews[]
@@unique([slug])
}
model KnowledgeBaseCategory {
id String @id @default(cuid())
knowledgeBaseId String
knowledgeBase KnowledgeBase @relation(fields: [knowledgeBaseId], references: [id])
slug String
order Int
title String
description String
icon String
language String
seoImage String
sections KnowledgeBaseCategorySection[]
articles KnowledgeBaseArticle[]
@@unique([knowledgeBaseId, slug])
}
model KnowledgeBaseCategorySection {
id String @id @default(cuid())
categoryId String
category KnowledgeBaseCategory @relation(fields: [categoryId], references: [id], onDelete: Cascade)
order Int
title String
description String
articles KnowledgeBaseArticle[]
}
model KnowledgeBaseArticle {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime? @updatedAt
knowledgeBaseId String
knowledgeBase KnowledgeBase @relation(fields: [knowledgeBaseId], references: [id])
categoryId String?
category KnowledgeBaseCategory? @relation(fields: [categoryId], references: [id])
sectionId String?
section KnowledgeBaseCategorySection? @relation(fields: [sectionId], references: [id])
slug String
title String
description String
order Int
contentDraft String
contentPublished String @default("")
contentPublishedAsText String @default("")
contentType String
language String
featuredOrder Int?
seoImage String
publishedAt DateTime?
relatedInArticleId String?
createdByUserId String?
createdByUser User? @relation(fields: [createdByUserId], references: [id], onDelete: Cascade)
views KnowledgeBaseArticleViews[]
upvotes KnowledgeBaseArticleUpvotes[]
downvotes KnowledgeBaseArticleDownvotes[]
relatedArticles KnowledgeBaseRelatedArticle[] @relation(name: "relatedArticles")
relatedInArticles KnowledgeBaseRelatedArticle[] @relation(name: "relatedInArticles")
@@unique([knowledgeBaseId, slug])
}
model KnowledgeBaseRelatedArticle {
id String @id @default(cuid())
articleId String
article KnowledgeBaseArticle @relation(name: "relatedArticles", fields: [articleId], references: [id], onDelete: Cascade)
relatedArticle KnowledgeBaseArticle @relation(name: "relatedInArticles", fields: [relatedArticleId], references: [id], onDelete: Cascade)
relatedArticleId String
}
model KnowledgeBaseViews {
id String @id @default(cuid())
createdAt DateTime @default(now())
knowledgeBaseId String
knowledgeBase KnowledgeBase @relation(fields: [knowledgeBaseId], references: [id], onDelete: Cascade)
userAnalyticsId String
@@unique([knowledgeBaseId, userAnalyticsId])
}
model KnowledgeBaseArticleViews {
knowledgeBaseArticleId String
knowledgeBaseArticle KnowledgeBaseArticle @relation(fields: [knowledgeBaseArticleId], references: [id], onDelete: Cascade)
userAnalyticsId String
@@unique([knowledgeBaseArticleId, userAnalyticsId])
}
model KnowledgeBaseArticleUpvotes {
createdAt DateTime @default(now())
knowledgeBaseArticleId String
knowledgeBaseArticle KnowledgeBaseArticle @relation(fields: [knowledgeBaseArticleId], references: [id], onDelete: Cascade)
userAnalyticsId String
@@unique([knowledgeBaseArticleId, userAnalyticsId])
}
model KnowledgeBaseArticleDownvotes {
createdAt DateTime @default(now())
knowledgeBaseArticleId String
knowledgeBaseArticle KnowledgeBaseArticle @relation(fields: [knowledgeBaseArticleId], references: [id], onDelete: Cascade)
userAnalyticsId String
@@unique([knowledgeBaseArticleId, userAnalyticsId])
}
model EntityGroupConfiguration {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
entityGroupId String
entityGroup EntityGroup @relation(fields: [entityGroupId], references: [id], onDelete: Cascade)
title String
rows EntityGroupConfigurationRow[]
}
model EntityGroupConfigurationRow {
id String @id @default(cuid())
entityGroupConfigurationId String
entityGroupConfiguration EntityGroupConfiguration @relation(fields: [entityGroupConfigurationId], references: [id], onDelete: Cascade)
rowId String
row Row @relation(fields: [rowId], references: [id], onDelete: Cascade)
@@unique([entityGroupConfigurationId, rowId])
}
model FileUploadProgress {
id String @id @default(cuid())
fileName String
progressServer Int
progressStorage Int
url String?
error String?
chunks FileChunk[]
}
model FileChunk {
id Int @id @default(autoincrement())
fileUploadId String
fileUpload FileUploadProgress @relation(fields: [fileUploadId], references: [id], onDelete: Cascade)
index Int
data Bytes
}
model Workflow {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
name String
description String
status String @default("draft")
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id])
createdByUserId String?
createdByUser User? @relation(name: "createdByUser", fields: [createdByUserId], references: [id])
appliesToAllTenants Boolean @default(false)
blocks WorkflowBlock[]
inputExamples WorkflowInputExample[]
executions WorkflowExecution[]
}
model WorkflowBlock {
id String @id @default(cuid())
workflowId String // Foreign key to the Workflow
workflow Workflow @relation(fields: [workflowId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
type String
description String
isTrigger Boolean @default(false)
isBlock Boolean @default(false)
fromBlocks WorkflowBlockToBlock[] @relation(name: "toBlock")
toBlocks WorkflowBlockToBlock[] @relation(name: "fromBlock")
input String
executions WorkflowBlockExecution[] @relation(name: "executions")
fromExecutions WorkflowBlockExecution[] @relation(name: "fromExecutions")
conditionsGroups WorkflowBlockConditionGroup[]
waitingInExecutions WorkflowExecution[]
}
model WorkflowBlockConditionGroup {
id String @id @default(cuid())
workflowBlockId String
workflowBlock WorkflowBlock @relation(fields: [workflowBlockId], references: [id], onDelete: Cascade)
index Int
type String // AND or OR
conditions WorkflowBlockCondition[]
}
model WorkflowBlockCondition {
id String @id @default(cuid())
workflowBlockConditionGroupId String
workflowBlockConditionGroup WorkflowBlockConditionGroup @relation(fields: [workflowBlockConditionGroupId], references: [id], onDelete: Cascade)
index Int
variable String
operator String
value String
}
model WorkflowBlockToBlock {
id String @id @default(cuid())
fromBlockId String
fromBlock WorkflowBlock @relation(name: "fromBlock", fields: [fromBlockId], references: [id], onDelete: Cascade)
toBlockId String
toBlock WorkflowBlock @relation(name: "toBlock", fields: [toBlockId], references: [id], onDelete: Cascade)
condition String?
@@unique([fromBlockId, toBlockId])
}
model WorkflowExecution {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
workflowId String
workflow Workflow @relation(fields: [workflowId], references: [id], onDelete: Cascade)
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
type String // manual, api, stream
status String
input String
output String?
duration Int?
endedAt DateTime?
error String?
waitingBlockId String?
waitingBlock WorkflowBlock? @relation(fields: [waitingBlockId], references: [id])
createdByUserId String?
createdByUser User? @relation(name: "executedByUser", fields: [createdByUserId], references: [id])
appliesToAllTenants Boolean @default(false)
blockRuns WorkflowBlockExecution[]
}
model WorkflowInputExample {
id String @id @default(cuid())
createdAt DateTime @default(now())
workflowId String
workflow Workflow @relation(fields: [workflowId], references: [id], onDelete: Cascade)
title String
input String?
@@unique([workflowId, title])
}
model WorkflowBlockExecution {
id String @id @default(cuid())
workflowExecutionId String
workflowExecution WorkflowExecution @relation(fields: [workflowExecutionId], references: [id], onDelete: Cascade)
workflowBlockId String
workflowBlock WorkflowBlock @relation(name: "executions", fields: [workflowBlockId], references: [id], onDelete: Cascade)
fromWorkflowBlockId String?
fromWorkflowBlock WorkflowBlock? @relation(name: "fromExecutions", fields: [fromWorkflowBlockId], references: [id])
status String
startedAt DateTime
input String?
output String?
duration Int?
endedAt DateTime?
error String?
}
model WorkflowVariable {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
name String
value String
createdByUserId String?
createdByUser User? @relation(fields: [userId], references: [id])
userId String?
@@unique([tenantId, name])
}
model WorkflowCredential {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
name String
value String
createdByUserId String?
createdByUser User? @relation(fields: [userId], references: [id])
userId String?
@@unique([tenantId, name])
}
model IpAddress {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
ip String @unique
provider String
type String
countryCode String
countryName String
regionCode String
regionName String
city String
zipCode String
latitude Decimal?
longitude Decimal?
metadata String
logs IpAddressLog[]
}
model IpAddressLog {
id String @id @default(cuid())
createdAt DateTime @default(now())
ip String
url String
action String
description String
success Boolean
error String?
metadata String?
ipAddressId String?
ipAddress IpAddress? @relation(fields: [ipAddressId], references: [id])
}
model Credit {
id String @id @default(cuid())
createdAt DateTime @default(now())
tenantId String
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
userId String?
user User? @relation(fields: [userId], references: [id])
amount Int
type String
objectId String?
@@index([tenantId, userId])
@@index([tenantId, createdAt])
}
model Feedback {
id String @id @default(cuid())
createdAt DateTime @default(now())
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
userId String?
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
message String
fromUrl String
}
model Portal {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
createdByUserId String?
createdByUser User? @relation(fields: [createdByUserId], references: [id], onDelete: Cascade)
subdomain String @unique
domain String? @unique
title String
isPublished Boolean @default(false)
stripeAccountId String?
themeColor String?
themeScheme String?
seoTitle String?
seoDescription String?
seoImage String?
seoThumbnail String?
seoTwitterCreator String?
seoTwitterSite String?
seoKeywords String?
authRequireEmailVerification Boolean @default(false)
authRequireOrganization Boolean @default(true)
authRequireName Boolean @default(true)
analyticsSimpleAnalytics Boolean @default(false)
analyticsPlausibleAnalytics Boolean @default(false)
analyticsGoogleAnalyticsTrackingId String?
brandingLogo String?
brandingLogoDarkMode String?
brandingIcon String?
brandingIconDarkMode String?
brandingFavicon String?
affiliatesRewardfulApiKey String?
affiliatesRewardfulUrl String?
metadata Json?
users PortalUser[]
pages PortalPage[]
registrations PortalUserRegistration[]
subscriptionProducts PortalSubscriptionProduct[]
subscriptionPrices PortalSubscriptionPrice[]
subscriptionFeatures PortalSubscriptionFeature[]
userSubscriptions PortalUserSubscription[]
userSubscriptionProducts PortalUserSubscriptionProduct[]
userSubscriptionProductPrices PortalUserSubscriptionProductPrice[]
checkoutSessionStatus PortalCheckoutSessionStatus[]
analyticsUniqueVisitors AnalyticsUniqueVisitor[]
analyticsPageViews AnalyticsPageView[]
analyticsEvents AnalyticsEvent[]
}
model PortalUser {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
portalId String
portal Portal @relation(fields: [portalId], references: [id], onDelete: Cascade)
email String
passwordHash String
firstName String
lastName String
avatar String?
phone String?
verifyToken String?
githubId String?
googleId String?
locale String?
fromRegistration PortalUserRegistration?
subscription PortalUserSubscription?
@@unique([portalId, email])
@@unique([portalId, githubId])
@@unique([portalId, googleId])
@@index([portalId])
}
model PortalPage {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
portalId String
portal Portal @relation(fields: [portalId], references: [id], onDelete: Cascade)
name String
title String
description String
content String
@@unique([portalId, name])
}
model PortalUserRegistration {
id String @id @default(cuid())
createdAt DateTime @default(now())
portalId String
portal Portal @relation(fields: [portalId], references: [id], onDelete: Cascade)
email String
firstName String
lastName String
slug String?
token String @unique
ipAddress String?
company String?
selectedSubscriptionPriceId String?
createdPortalUserId String? @unique
createdPortalUser PortalUser? @relation(fields: [createdPortalUserId], references: [id], onDelete: Cascade)
@@unique([portalId, email])
}
model PortalSubscriptionProduct {
id String @id @default(cuid())
portalId String
portal Portal @relation(fields: [portalId], references: [id], onDelete: Cascade)
stripeId String
order Int
title String
active Boolean
model Int
public Boolean
groupTitle String?
groupDescription String?
description String?
badge String?
billingAddressCollection String @default("auto")
hasQuantity Boolean @default(false)
canBuyAgain Boolean @default(false)
prices PortalSubscriptionPrice[]
features PortalSubscriptionFeature[]
portalUserProducts PortalUserSubscriptionProduct[]
}
model PortalSubscriptionPrice {
id String @id @default(cuid())
portalId String
portal Portal @relation(fields: [portalId], references: [id], onDelete: Cascade)
subscriptionProductId String
subscriptionProduct PortalSubscriptionProduct @relation(fields: [subscriptionProductId], references: [id], onDelete: Cascade)
stripeId String
type Int
billingPeriod Int
price Decimal
currency String
trialDays Int
active Boolean
portalUserProductPrices PortalUserSubscriptionProductPrice[]
}
model PortalSubscriptionFeature {
id String @id @default(cuid())
portalId String
portal Portal @relation(fields: [portalId], references: [id], onDelete: Cascade)
subscriptionProductId String
order Int
title String
name String
type Int
value Int
href String?
badge String?
accumulate Boolean @default(false)
subscriptionProduct PortalSubscriptionProduct @relation(fields: [subscriptionProductId], references: [id], onDelete: Cascade)
}
model PortalUserSubscription {
id String @id @default(cuid())
portalId String
portal Portal @relation(fields: [portalId], references: [id], onDelete: Cascade)
portalUserId String @unique
stripeCustomerId String?
portalUser PortalUser @relation(fields: [portalUserId], references: [id], onDelete: Cascade)
products PortalUserSubscriptionProduct[]
}
model PortalUserSubscriptionProduct {
id String @id @default(cuid())
portalId String
portal Portal @relation(fields: [portalId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
portalUserSubscriptionId String
subscriptionProductId String
cancelledAt DateTime?
endsAt DateTime?
stripeSubscriptionId String?
quantity Int?
fromCheckoutSessionId String?
currentPeriodStart DateTime?
currentPeriodEnd DateTime?
portalUserSubscription PortalUserSubscription @relation(fields: [portalUserSubscriptionId], references: [id], onDelete: Cascade)
subscriptionProduct PortalSubscriptionProduct @relation(fields: [subscriptionProductId], references: [id])
prices PortalUserSubscriptionProductPrice[]
}
model PortalUserSubscriptionProductPrice {
id String @id @default(cuid())
portalId String
portal Portal @relation(fields: [portalId], references: [id], onDelete: Cascade)
portalUserSubscriptionProductId String
portalUserSubscriptionProduct PortalUserSubscriptionProduct @relation(fields: [portalUserSubscriptionProductId], references: [id], onDelete: Cascade)
subscriptionPriceId String?
subscriptionPrice PortalSubscriptionPrice? @relation(fields: [subscriptionPriceId], references: [id])
}
model PortalCheckoutSessionStatus {
id String @unique
portalId String
portal Portal @relation(fields: [portalId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
pending Boolean @default(true) // has not added products to tenant
email String
fromUrl String
fromUserId String?
createdUserId String?
}
We respect your privacy. We respect your privacy.
TLDR: We use cookies for language selection, theme, and analytics. Learn more. TLDR: We use cookies for language selection, theme, and analytics. Learn more