mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-13 21:01:21 +08:00
890 lines
29 KiB
Plaintext
890 lines
29 KiB
Plaintext
// This is your Prisma schema file,
|
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
previewFeatures = ["metrics", "tracing", "relationJoins"]
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("STACK_DATABASE_CONNECTION_STRING")
|
|
directUrl = env("STACK_DIRECT_DATABASE_CONNECTION_STRING")
|
|
}
|
|
|
|
model Project {
|
|
// Note that the project with ID `internal` is handled as a special case.
|
|
id String @id
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
displayName String
|
|
description String? @default("")
|
|
configId String @db.Uuid
|
|
config ProjectConfig @relation(fields: [configId], references: [id], onDelete: Cascade)
|
|
configOverride ProjectConfigOverride?
|
|
isProductionMode Boolean
|
|
|
|
users ProjectUser[] @relation("ProjectUsers")
|
|
teams Team[]
|
|
apiKeySets ApiKeySet[]
|
|
authMethods AuthMethod[]
|
|
contactChannels ContactChannel[]
|
|
connectedAccounts ConnectedAccount[]
|
|
}
|
|
|
|
// Contains all the configuration for a project.
|
|
// More specifically, "configuration" is what we call those settings that only depend on environment variables and overrides between different deployments.
|
|
model ProjectConfig {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
allowLocalhost Boolean
|
|
signUpEnabled Boolean @default(true)
|
|
createTeamOnSignUp Boolean
|
|
clientTeamCreationEnabled Boolean
|
|
clientUserDeletionEnabled Boolean @default(false)
|
|
// TODO: remove this after moving everyone to project specific JWTs
|
|
legacyGlobalJwtSigning Boolean @default(false)
|
|
|
|
teamCreateDefaultSystemPermissions TeamSystemPermission[]
|
|
teamMemberDefaultSystemPermissions TeamSystemPermission[]
|
|
projects Project[]
|
|
oauthProviderConfigs OAuthProviderConfig[]
|
|
emailServiceConfig EmailServiceConfig?
|
|
domains ProjectDomain[]
|
|
permissions Permission[]
|
|
authMethodConfigs AuthMethodConfig[]
|
|
connectedAccountConfigs ConnectedAccountConfig[]
|
|
}
|
|
|
|
model ProjectDomain {
|
|
projectConfigId String @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
domain String
|
|
handlerPath String
|
|
|
|
projectConfig ProjectConfig @relation(fields: [projectConfigId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([projectConfigId, domain])
|
|
}
|
|
|
|
// Environment-specific overrides for a configuration.
|
|
//
|
|
// This is a quick and dirty way to allow for environment-specific overrides of the configuration.
|
|
//
|
|
// For most cases, you should prefer to use environment variables.
|
|
//
|
|
// Note: Overrides (and environment variables) are currently unimplemented, so this model is empty.
|
|
model ProjectConfigOverride {
|
|
projectId String @id
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
}
|
|
|
|
model Team {
|
|
projectId String
|
|
teamId String @default(uuid()) @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
displayName String
|
|
profileImageUrl String?
|
|
clientMetadata Json?
|
|
clientReadOnlyMetadata Json?
|
|
serverMetadata Json?
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
permissions Permission[]
|
|
teamMembers TeamMember[]
|
|
|
|
@@id([projectId, teamId])
|
|
}
|
|
|
|
// This is used for fields that are boolean but only the true value is part of a unique constraint.
|
|
// For example if you want to allow only one selected team per user, you can make an optional field with this type and add a unique constraint.
|
|
// Only the true value is considered for the unique constraint, the null value is not.
|
|
enum BooleanTrue {
|
|
TRUE
|
|
}
|
|
|
|
model TeamMember {
|
|
projectId String
|
|
projectUserId String @db.Uuid
|
|
teamId String @db.Uuid
|
|
|
|
// This will override the displayName of the user in this team.
|
|
displayName String?
|
|
// This will override the profileImageUrl of the user in this team.
|
|
profileImageUrl String?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
projectUser ProjectUser @relation(fields: [projectId, projectUserId], references: [projectId, projectUserId], onDelete: Cascade)
|
|
team Team @relation(fields: [projectId, teamId], references: [projectId, teamId], onDelete: Cascade)
|
|
isSelected BooleanTrue?
|
|
|
|
directPermissions TeamMemberDirectPermission[]
|
|
|
|
@@id([projectId, projectUserId, teamId])
|
|
@@unique([projectId, projectUserId, isSelected])
|
|
}
|
|
|
|
model TeamMemberDirectPermission {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
projectId String
|
|
projectUserId String @db.Uuid
|
|
teamId String @db.Uuid
|
|
permissionDbId String? @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
teamMember TeamMember @relation(fields: [projectId, projectUserId, teamId], references: [projectId, projectUserId, teamId], onDelete: Cascade)
|
|
|
|
// exactly one of [permissionId && permission] or [systemPermission] must be set
|
|
permission Permission? @relation(fields: [permissionDbId], references: [dbId], onDelete: Cascade)
|
|
systemPermission TeamSystemPermission?
|
|
|
|
@@unique([projectId, projectUserId, teamId, permissionDbId])
|
|
@@unique([projectId, projectUserId, teamId, systemPermission])
|
|
}
|
|
|
|
model Permission {
|
|
// The ID of this permission, as is chosen by and exposed to the user. It is different from the database ID, which is randomly generated and only used internally.
|
|
queryableId String
|
|
// The database ID of this permission. This is never exposed to any client and is only used to make sure the database has an ID column.
|
|
dbId String @id @default(uuid()) @db.Uuid
|
|
// exactly one of [projectConfigId && projectConfig] or [projectId && teamId && team] must be set
|
|
projectConfigId String? @db.Uuid
|
|
projectId String?
|
|
teamId String? @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
description String?
|
|
|
|
// The scope of the permission. If projectConfigId is set, may be GLOBAL or TEAM; if teamId is set, must be TEAM.
|
|
scope PermissionScope
|
|
projectConfig ProjectConfig? @relation(fields: [projectConfigId], references: [id], onDelete: Cascade)
|
|
team Team? @relation(fields: [projectId, teamId], references: [projectId, teamId], onDelete: Cascade)
|
|
|
|
parentEdges PermissionEdge[] @relation("ChildPermission")
|
|
childEdges PermissionEdge[] @relation("ParentPermission")
|
|
teamMemberDirectPermission TeamMemberDirectPermission[]
|
|
|
|
isDefaultTeamCreatorPermission Boolean @default(false)
|
|
isDefaultTeamMemberPermission Boolean @default(false)
|
|
|
|
@@unique([projectConfigId, queryableId])
|
|
@@unique([projectId, teamId, queryableId])
|
|
}
|
|
|
|
enum PermissionScope {
|
|
GLOBAL
|
|
TEAM
|
|
}
|
|
|
|
enum TeamSystemPermission {
|
|
UPDATE_TEAM
|
|
DELETE_TEAM
|
|
READ_MEMBERS
|
|
REMOVE_MEMBERS
|
|
INVITE_MEMBERS
|
|
}
|
|
|
|
model PermissionEdge {
|
|
edgeId String @id @default(uuid()) @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// exactly one of [parentPermissionDbId && parentPermission] or [parentTeamSystemPermission] must be set
|
|
parentPermissionDbId String? @db.Uuid
|
|
parentPermission Permission? @relation("ParentPermission", fields: [parentPermissionDbId], references: [dbId], onDelete: Cascade)
|
|
parentTeamSystemPermission TeamSystemPermission?
|
|
|
|
childPermissionDbId String @db.Uuid
|
|
childPermission Permission @relation("ChildPermission", fields: [childPermissionDbId], references: [dbId], onDelete: Cascade)
|
|
}
|
|
|
|
model ProjectUser {
|
|
projectId String
|
|
projectUserId String @default(uuid()) @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
profileImageUrl String?
|
|
displayName String?
|
|
serverMetadata Json?
|
|
clientReadOnlyMetadata Json?
|
|
clientMetadata Json?
|
|
requiresTotpMfa Boolean @default(false)
|
|
totpSecret Bytes?
|
|
|
|
project Project @relation("ProjectUsers", fields: [projectId], references: [id], onDelete: Cascade)
|
|
projectUserRefreshTokens ProjectUserRefreshToken[]
|
|
projectUserAuthorizationCodes ProjectUserAuthorizationCode[]
|
|
projectUserOAuthAccounts ProjectUserOAuthAccount[]
|
|
teamMembers TeamMember[]
|
|
contactChannels ContactChannel[]
|
|
authMethods AuthMethod[]
|
|
connectedAccounts ConnectedAccount[]
|
|
|
|
// some backlinks for the unique constraints on some auth methods
|
|
passwordAuthMethod PasswordAuthMethod[]
|
|
passkeyAuthMethod PasskeyAuthMethod[]
|
|
otpAuthMethod OtpAuthMethod[]
|
|
oauthAuthMethod OAuthAuthMethod[]
|
|
|
|
@@id([projectId, projectUserId])
|
|
|
|
// indices for sorting and filtering
|
|
@@index([projectId, displayName(sort: Asc)], name: "ProjectUser_displayName_asc")
|
|
@@index([projectId, displayName(sort: Desc)], name: "ProjectUser_displayName_desc")
|
|
@@index([projectId, createdAt(sort: Asc)], name: "ProjectUser_createdAt_asc")
|
|
@@index([projectId, createdAt(sort: Desc)], name: "ProjectUser_createdAt_desc")
|
|
}
|
|
|
|
// This should be renamed to "OAuthAccount" as it is not always bound to a user
|
|
// When ever a user goes through the OAuth flow and gets an account ID from the OAuth provider, we store that here.
|
|
model ProjectUserOAuthAccount {
|
|
projectId String
|
|
projectUserId String @db.Uuid
|
|
projectConfigId String @db.Uuid
|
|
oauthProviderConfigId String
|
|
providerAccountId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// This is used for the user to distinguish between multiple accounts from the same provider.
|
|
// we might want to add more user info here later
|
|
email String?
|
|
|
|
providerConfig OAuthProviderConfig @relation(fields: [projectConfigId, oauthProviderConfigId], references: [projectConfigId, id], onDelete: Cascade)
|
|
// Before the OAuth account is connected to a use (for example, in the link oauth process), the projectUser is null.
|
|
projectUser ProjectUser? @relation(fields: [projectId, projectUserId], references: [projectId, projectUserId], onDelete: Cascade)
|
|
oauthTokens OAuthToken[]
|
|
oauthAccessToken OAuthAccessToken[]
|
|
|
|
// At lease one of the authMethod or connectedAccount should be set.
|
|
connectedAccount ConnectedAccount?
|
|
oauthAuthMethod OAuthAuthMethod?
|
|
|
|
@@id([projectId, oauthProviderConfigId, providerAccountId])
|
|
}
|
|
|
|
enum ContactChannelType {
|
|
EMAIL
|
|
// PHONE
|
|
}
|
|
|
|
model ContactChannel {
|
|
projectId String
|
|
projectUserId String @db.Uuid
|
|
id String @default(uuid()) @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
type ContactChannelType
|
|
isPrimary BooleanTrue?
|
|
usedForAuth BooleanTrue?
|
|
isVerified Boolean
|
|
value String
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
projectUser ProjectUser @relation(fields: [projectId, projectUserId], references: [projectId, projectUserId], onDelete: Cascade)
|
|
|
|
@@id([projectId, projectUserId, id])
|
|
// each user has at most one primary contact channel of each type
|
|
@@unique([projectId, projectUserId, type, isPrimary])
|
|
// value must be unique per user per type
|
|
@@unique([projectId, projectUserId, type, value])
|
|
// only one contact channel per project with the same value and type can be used for auth
|
|
@@unique([projectId, type, value, usedForAuth])
|
|
}
|
|
|
|
model ConnectedAccountConfig {
|
|
projectConfigId String @db.Uuid
|
|
id String @default(uuid()) @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
enabled Boolean @default(true)
|
|
|
|
// this should never be null
|
|
oauthProviderConfig OAuthProviderConfig?
|
|
projectConfig ProjectConfig @relation(fields: [projectConfigId], references: [id], onDelete: Cascade)
|
|
connectedAccounts ConnectedAccount[]
|
|
|
|
@@id([projectConfigId, id])
|
|
}
|
|
|
|
model ConnectedAccount {
|
|
projectId String
|
|
id String @default(uuid()) @db.Uuid
|
|
projectConfigId String @db.Uuid
|
|
connectedAccountConfigId String @db.Uuid
|
|
projectUserId String @db.Uuid
|
|
oauthProviderConfigId String
|
|
providerAccountId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
oauthAccount ProjectUserOAuthAccount @relation(fields: [projectId, oauthProviderConfigId, providerAccountId], references: [projectId, oauthProviderConfigId, providerAccountId])
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
projectUser ProjectUser @relation(fields: [projectId, projectUserId], references: [projectId, projectUserId], onDelete: Cascade)
|
|
connectedAccountConfig ConnectedAccountConfig @relation(fields: [projectConfigId, connectedAccountConfigId], references: [projectConfigId, id], onDelete: Cascade)
|
|
oauthProviderConfig OAuthProviderConfig @relation(fields: [projectConfigId, oauthProviderConfigId], references: [projectConfigId, id], onDelete: Cascade)
|
|
|
|
@@id([projectId, id])
|
|
@@unique([projectId, oauthProviderConfigId, providerAccountId])
|
|
}
|
|
|
|
model AuthMethodConfig {
|
|
projectConfigId String @db.Uuid
|
|
id String @default(uuid()) @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
enabled Boolean @default(true)
|
|
|
|
// exactly one of xyzConfig should be set
|
|
otpConfig OtpAuthMethodConfig?
|
|
oauthProviderConfig OAuthProviderConfig?
|
|
passwordConfig PasswordAuthMethodConfig?
|
|
passkeyConfig PasskeyAuthMethodConfig?
|
|
|
|
projectConfig ProjectConfig @relation(fields: [projectConfigId], references: [id], onDelete: Cascade)
|
|
authMethods AuthMethod[]
|
|
|
|
@@id([projectConfigId, id])
|
|
}
|
|
|
|
model OtpAuthMethodConfig {
|
|
projectConfigId String @db.Uuid
|
|
authMethodConfigId String @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
contactChannelType ContactChannelType
|
|
|
|
authMethodConfig AuthMethodConfig @relation(fields: [projectConfigId, authMethodConfigId], references: [projectConfigId, id], onDelete: Cascade)
|
|
|
|
@@id([projectConfigId, authMethodConfigId])
|
|
}
|
|
|
|
model PasswordAuthMethodConfig {
|
|
projectConfigId String @db.Uuid
|
|
authMethodConfigId String @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
authMethodConfig AuthMethodConfig @relation(fields: [projectConfigId, authMethodConfigId], references: [projectConfigId, id], onDelete: Cascade)
|
|
|
|
@@id([projectConfigId, authMethodConfigId])
|
|
}
|
|
|
|
model PasskeyAuthMethodConfig {
|
|
projectConfigId String @db.Uuid
|
|
authMethodConfigId String @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
authMethodConfig AuthMethodConfig @relation(fields: [projectConfigId, authMethodConfigId], references: [projectConfigId, id], onDelete: Cascade)
|
|
|
|
@@id([projectConfigId, authMethodConfigId])
|
|
}
|
|
|
|
// Both the connected account and auth methods can use this configuration.
|
|
model OAuthProviderConfig {
|
|
projectConfigId String @db.Uuid
|
|
id String
|
|
authMethodConfigId String? @db.Uuid
|
|
connectedAccountConfigId String? @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Exactly one of the xyzOAuthConfig variables should be set.
|
|
proxiedOAuthConfig ProxiedOAuthProviderConfig?
|
|
standardOAuthConfig StandardOAuthProviderConfig?
|
|
|
|
// At least one of authMethodConfig or connectedAccountConfig should be set.
|
|
// The config relation will never be unset, but the enabled field might be set to false on authMethodConfig or connectedAccountConfig.
|
|
authMethodConfig AuthMethodConfig? @relation(fields: [projectConfigId, authMethodConfigId], references: [projectConfigId, id], onDelete: Cascade)
|
|
connectedAccountConfig ConnectedAccountConfig? @relation(fields: [projectConfigId, connectedAccountConfigId], references: [projectConfigId, id], onDelete: Cascade)
|
|
|
|
projectConfig ProjectConfig @relation(fields: [projectConfigId], references: [id], onDelete: Cascade)
|
|
projectUserOAuthAccounts ProjectUserOAuthAccount[]
|
|
connectedAccounts ConnectedAccount[]
|
|
oauthAuthMethod OAuthAuthMethod[]
|
|
|
|
@@id([projectConfigId, id])
|
|
@@unique([projectConfigId, authMethodConfigId])
|
|
@@unique([projectConfigId, connectedAccountConfigId])
|
|
}
|
|
|
|
model ProxiedOAuthProviderConfig {
|
|
projectConfigId String @db.Uuid
|
|
id String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
type ProxiedOAuthProviderType
|
|
|
|
providerConfig OAuthProviderConfig @relation(fields: [projectConfigId, id], references: [projectConfigId, id], onDelete: Cascade)
|
|
|
|
@@id([projectConfigId, id])
|
|
// each type of proxied OAuth provider can only be used once per project
|
|
@@unique([projectConfigId, type])
|
|
}
|
|
|
|
enum ProxiedOAuthProviderType {
|
|
GITHUB
|
|
GOOGLE
|
|
MICROSOFT
|
|
SPOTIFY
|
|
}
|
|
|
|
model StandardOAuthProviderConfig {
|
|
projectConfigId String @db.Uuid
|
|
id String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
type StandardOAuthProviderType
|
|
clientId String
|
|
clientSecret String
|
|
|
|
// optional extra parameters for specific oauth providers
|
|
// Facebook business integration requires a config_id
|
|
facebookConfigId String?
|
|
// Microsoft organizational directory (tenant)
|
|
microsoftTenantId String?
|
|
|
|
providerConfig OAuthProviderConfig @relation(fields: [projectConfigId, id], references: [projectConfigId, id], onDelete: Cascade)
|
|
|
|
// each type of standard OAuth provider can only be used once per project
|
|
@@id([projectConfigId, id])
|
|
}
|
|
|
|
model AuthMethod {
|
|
projectId String
|
|
id String @default(uuid()) @db.Uuid
|
|
projectUserId String @db.Uuid
|
|
authMethodConfigId String @db.Uuid
|
|
projectConfigId String @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// exactly one of the xyzAuthMethods should be set
|
|
otpAuthMethod OtpAuthMethod?
|
|
passwordAuthMethod PasswordAuthMethod?
|
|
passkeyAuthMethod PasskeyAuthMethod?
|
|
oauthAuthMethod OAuthAuthMethod?
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
projectUser ProjectUser @relation(fields: [projectId, projectUserId], references: [projectId, projectUserId], onDelete: Cascade)
|
|
authMethodConfig AuthMethodConfig @relation(fields: [projectConfigId, authMethodConfigId], references: [projectConfigId, id], onDelete: Cascade)
|
|
|
|
@@id([projectId, id])
|
|
}
|
|
|
|
model OtpAuthMethod {
|
|
projectId String
|
|
authMethodId String @db.Uuid
|
|
projectUserId String @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
authMethod AuthMethod @relation(fields: [projectId, authMethodId], references: [projectId, id], onDelete: Cascade)
|
|
projectUser ProjectUser @relation(fields: [projectId, projectUserId], references: [projectId, projectUserId], onDelete: Cascade)
|
|
|
|
@@id([projectId, authMethodId])
|
|
// a user can only have one OTP auth method
|
|
@@unique([projectId, projectUserId])
|
|
}
|
|
|
|
model PasswordAuthMethod {
|
|
projectId String
|
|
authMethodId String @db.Uuid
|
|
projectUserId String @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
passwordHash String
|
|
|
|
authMethod AuthMethod @relation(fields: [projectId, authMethodId], references: [projectId, id], onDelete: Cascade)
|
|
projectUser ProjectUser @relation(fields: [projectId, projectUserId], references: [projectId, projectUserId], onDelete: Cascade)
|
|
|
|
@@id([projectId, authMethodId])
|
|
// a user can only have one password auth method
|
|
@@unique([projectId, projectUserId])
|
|
}
|
|
|
|
model PasskeyAuthMethod {
|
|
projectId String
|
|
authMethodId String @db.Uuid
|
|
projectUserId String @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
credentialId String
|
|
publicKey String
|
|
userHandle String
|
|
transports String[]
|
|
credentialDeviceType String
|
|
counter Int
|
|
|
|
|
|
authMethod AuthMethod @relation(fields: [projectId, authMethodId], references: [projectId, id], onDelete: Cascade)
|
|
projectUser ProjectUser @relation(fields: [projectId, projectUserId], references: [projectId, projectUserId], onDelete: Cascade)
|
|
|
|
@@id([projectId, authMethodId])
|
|
// a user can only have one password auth method
|
|
@@unique([projectId, projectUserId])
|
|
}
|
|
|
|
// This connects to projectUserOauthAccount, which might be shared between auth method and connected account.
|
|
model OAuthAuthMethod {
|
|
projectId String
|
|
projectConfigId String @db.Uuid
|
|
authMethodId String @db.Uuid
|
|
oauthProviderConfigId String
|
|
providerAccountId String
|
|
projectUserId String @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
authMethod AuthMethod @relation(fields: [projectId, authMethodId], references: [projectId, id], onDelete: Cascade)
|
|
oauthAccount ProjectUserOAuthAccount @relation(fields: [projectId, oauthProviderConfigId, providerAccountId], references: [projectId, oauthProviderConfigId, providerAccountId])
|
|
projectUser ProjectUser @relation(fields: [projectId, projectUserId], references: [projectId, projectUserId], onDelete: Cascade)
|
|
oauthProviderConfig OAuthProviderConfig @relation(fields: [projectConfigId, oauthProviderConfigId], references: [projectConfigId, id], onDelete: Cascade)
|
|
|
|
@@id([projectId, authMethodId])
|
|
@@unique([projectId, oauthProviderConfigId, providerAccountId])
|
|
}
|
|
|
|
enum StandardOAuthProviderType {
|
|
GITHUB
|
|
FACEBOOK
|
|
GOOGLE
|
|
MICROSOFT
|
|
SPOTIFY
|
|
DISCORD
|
|
GITLAB
|
|
BITBUCKET
|
|
LINKEDIN
|
|
APPLE
|
|
X
|
|
}
|
|
|
|
model OAuthToken {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
|
|
projectId String
|
|
oAuthProviderConfigId String
|
|
providerAccountId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
projectUserOAuthAccount ProjectUserOAuthAccount @relation(fields: [projectId, oAuthProviderConfigId, providerAccountId], references: [projectId, oauthProviderConfigId, providerAccountId], onDelete: Cascade)
|
|
|
|
refreshToken String
|
|
scopes String[]
|
|
}
|
|
|
|
model OAuthAccessToken {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
|
|
projectId String
|
|
oAuthProviderConfigId String
|
|
providerAccountId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
projectUserOAuthAccount ProjectUserOAuthAccount @relation(fields: [projectId, oAuthProviderConfigId, providerAccountId], references: [projectId, oauthProviderConfigId, providerAccountId], onDelete: Cascade)
|
|
|
|
accessToken String
|
|
scopes String[]
|
|
expiresAt DateTime
|
|
}
|
|
|
|
model OAuthOuterInfo {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
|
|
info Json
|
|
innerState String @unique
|
|
expiresAt DateTime
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
model ProjectUserRefreshToken {
|
|
projectId String
|
|
projectUserId String @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
refreshToken String @unique
|
|
expiresAt DateTime?
|
|
|
|
projectUser ProjectUser @relation(fields: [projectId, projectUserId], references: [projectId, projectUserId], onDelete: Cascade)
|
|
|
|
@@id([projectId, refreshToken])
|
|
}
|
|
|
|
model ProjectUserAuthorizationCode {
|
|
projectId String
|
|
projectUserId String @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
authorizationCode String @unique
|
|
redirectUri String
|
|
expiresAt DateTime
|
|
|
|
codeChallenge String
|
|
codeChallengeMethod String
|
|
|
|
newUser Boolean
|
|
afterCallbackRedirectUrl String?
|
|
|
|
projectUser ProjectUser @relation(fields: [projectId, projectUserId], references: [projectId, projectUserId], onDelete: Cascade)
|
|
|
|
@@id([projectId, authorizationCode])
|
|
}
|
|
|
|
model VerificationCode {
|
|
projectId String
|
|
id String @default(uuid()) @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
type VerificationCodeType
|
|
code String
|
|
expiresAt DateTime
|
|
usedAt DateTime?
|
|
redirectUrl String?
|
|
method Json @default("null")
|
|
data Json
|
|
attemptCount Int @default(0)
|
|
|
|
@@id([projectId, id])
|
|
@@unique([projectId, code])
|
|
@@index([data(ops: JsonbPathOps)], type: Gin)
|
|
}
|
|
|
|
enum VerificationCodeType {
|
|
ONE_TIME_PASSWORD
|
|
PASSWORD_RESET
|
|
CONTACT_CHANNEL_VERIFICATION
|
|
TEAM_INVITATION
|
|
MFA_ATTEMPT
|
|
PASSKEY_REGISTRATION_CHALLENGE
|
|
PASSKEY_AUTHENTICATION_CHALLENGE
|
|
}
|
|
|
|
//#region API keys
|
|
|
|
model ApiKeySet {
|
|
projectId String
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
id String @default(uuid()) @db.Uuid
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
description String
|
|
expiresAt DateTime
|
|
manuallyRevokedAt DateTime?
|
|
publishableClientKey String? @unique
|
|
secretServerKey String? @unique
|
|
superSecretAdminKey String? @unique
|
|
|
|
@@id([projectId, id])
|
|
}
|
|
|
|
model EmailServiceConfig {
|
|
projectConfigId String @id @db.Uuid
|
|
projectConfig ProjectConfig @relation(fields: [projectConfigId], references: [id], onDelete: Cascade)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
proxiedEmailServiceConfig ProxiedEmailServiceConfig?
|
|
standardEmailServiceConfig StandardEmailServiceConfig?
|
|
|
|
emailTemplates EmailTemplate[]
|
|
}
|
|
|
|
enum EmailTemplateType {
|
|
EMAIL_VERIFICATION
|
|
PASSWORD_RESET
|
|
MAGIC_LINK
|
|
TEAM_INVITATION
|
|
}
|
|
|
|
model EmailTemplate {
|
|
projectConfigId String @db.Uuid
|
|
emailServiceConfig EmailServiceConfig @relation(fields: [projectConfigId], references: [projectConfigId], onDelete: Cascade)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
content Json
|
|
type EmailTemplateType
|
|
subject String
|
|
|
|
@@id([projectConfigId, type])
|
|
}
|
|
|
|
model ProxiedEmailServiceConfig {
|
|
projectConfigId String @id @db.Uuid
|
|
emailServiceConfig EmailServiceConfig @relation(fields: [projectConfigId], references: [projectConfigId], onDelete: Cascade)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
model StandardEmailServiceConfig {
|
|
projectConfigId String @id @db.Uuid
|
|
emailServiceConfig EmailServiceConfig @relation(fields: [projectConfigId], references: [projectConfigId], onDelete: Cascade)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
senderName String
|
|
senderEmail String
|
|
host String
|
|
port Int
|
|
username String
|
|
password String
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//#region IdP
|
|
model IdPAccountToCdfcResultMapping {
|
|
idpId String
|
|
id String
|
|
|
|
idpAccountId String @db.Uuid @unique
|
|
cdfcResult Json
|
|
|
|
@@id([idpId, id])
|
|
}
|
|
|
|
model ProjectWrapperCodes {
|
|
idpId String
|
|
id String @default(uuid()) @db.Uuid
|
|
|
|
interactionUid String
|
|
authorizationCode String @unique
|
|
|
|
cdfcResult Json
|
|
|
|
@@id([idpId, id])
|
|
}
|
|
|
|
model IdPAdapterData {
|
|
idpId String
|
|
model String
|
|
id String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
payload Json
|
|
expiresAt DateTime
|
|
|
|
@@id([idpId, model, id])
|
|
@@index([payload(ops: JsonbPathOps)], type: Gin)
|
|
@@index([expiresAt])
|
|
}
|
|
//#endregion
|
|
|
|
//#region Events
|
|
|
|
model Event {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// if isWide == false, then eventEndedAt is always equal to eventStartedAt
|
|
isWide Boolean
|
|
eventStartedAt DateTime
|
|
eventEndedAt DateTime
|
|
|
|
// TODO: add event_type, and at least one of either system_event_type or event_type is always set
|
|
systemEventTypeIds String[]
|
|
data Json
|
|
|
|
// ============================== BEGIN END USER PROPERTIES ==============================
|
|
// Below are properties describing the end user that caused this event to be logged
|
|
// This is different from a request IP. See: apps/backend/src/lib/end-users.tsx
|
|
|
|
// Note that the IP may have been spoofed, unless isEndUserIpInfoGuessTrusted is true
|
|
endUserIpInfoGuessId String? @db.Uuid
|
|
endUserIpInfoGuess EventIpInfo? @relation("EventIpInfo", fields: [endUserIpInfoGuessId], references: [id])
|
|
// If true, then endUserIpInfoGuess is not spoofed (might still be behind VPNs/proxies). If false, then the values may be spoofed.
|
|
isEndUserIpInfoGuessTrusted Boolean @default(false)
|
|
// =============================== END END USER PROPERTIES ===============================
|
|
|
|
@@index([data(ops: JsonbPathOps)], type: Gin)
|
|
}
|
|
|
|
// An IP address that was seen in an event. Use the location fields instead of refetching the location from the ip, as the real-world geoip data may have changed since the event was logged.
|
|
model EventIpInfo {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
|
|
ip String
|
|
|
|
countryCode String?
|
|
regionCode String?
|
|
cityName String?
|
|
latitude Float?
|
|
longitude Float?
|
|
tzIdentifier String?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
events Event[] @relation("EventIpInfo")
|
|
}
|
|
|
|
//#endregion
|