stack/apps/backend/prisma/schema.prisma
Manoj Kumar 165fe4bbc2
Add Gitlab OAuth as standard provider (#201)
* add gitlab oauth

* updated docs format

* updated error message

* Code formatting

---------

Co-authored-by: Zai Shi <zaishi00@outlook.com>
2024-08-24 22:36:52 +02:00

605 lines
17 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"
}
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[]
}
// 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)
credentialEnabled Boolean
magicLinkEnabled Boolean
createTeamOnSignUp Boolean
clientTeamCreationEnabled Boolean
projects Project[]
oauthProviderConfigs OAuthProviderConfig[]
emailServiceConfig EmailServiceConfig?
domains ProjectDomain[]
permissions Permission[]
teamCreateDefaultSystemPermissions TeamSystemPermission[]
teamMemberDefaultSystemPermissions TeamSystemPermission[]
}
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
project Project @relation("ProjectUsers", fields: [projectId], references: [id], onDelete: Cascade)
projectUserRefreshTokens ProjectUserRefreshToken[]
projectUserAuthorizationCodes ProjectUserAuthorizationCode[]
projectUserOAuthAccounts ProjectUserOAuthAccount[]
teamMembers TeamMember[]
// @deprecated
projectUserEmailVerificationCode ProjectUserEmailVerificationCode[]
// @deprecated
projectUserPasswordResetCode ProjectUserPasswordResetCode[]
// @deprecated
projectUserMagicLinkCode ProjectUserMagicLinkCode[]
primaryEmail String?
primaryEmailVerified Boolean
profileImageUrl String?
displayName String?
passwordHash String?
authWithEmail Boolean
requiresTotpMfa Boolean @default(false)
totpSecret Bytes?
clientMetadata Json?
clientReadOnlyMetadata Json?
serverMetadata Json?
@@id([projectId, projectUserId])
}
model ProjectUserOAuthAccount {
projectId String
projectUserId String @db.Uuid
projectConfigId String @db.Uuid
oauthProviderConfigId String
providerAccountId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
providerConfig OAuthProviderConfig @relation(fields: [projectConfigId, oauthProviderConfigId], references: [projectConfigId, id], onDelete: Cascade)
projectUser ProjectUser @relation(fields: [projectId, projectUserId], references: [projectId, projectUserId], onDelete: Cascade)
oauthTokens OAuthToken[]
oauthAccessToken OAuthAccessToken[]
email String?
@@id([projectId, oauthProviderConfigId, providerAccountId])
}
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
@@id([projectId, id])
@@unique([projectId, code])
}
enum VerificationCodeType {
ONE_TIME_PASSWORD
PASSWORD_RESET
CONTACT_CHANNEL_VERIFICATION
TEAM_INVITATION
MFA_ATTEMPT
}
// @deprecated
model ProjectUserEmailVerificationCode {
projectId String
projectUserId String @db.Uuid
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
code String @unique
expiresAt DateTime
usedAt DateTime?
redirectUrl String
projectUser ProjectUser @relation(fields: [projectId, projectUserId], references: [projectId, projectUserId], onDelete: Cascade)
@@id([projectId, code])
}
// @deprecated
model ProjectUserPasswordResetCode {
projectId String
projectUserId String @db.Uuid
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
code String @unique
expiresAt DateTime
usedAt DateTime?
redirectUrl String
projectUser ProjectUser @relation(fields: [projectId, projectUserId], references: [projectId, projectUserId], onDelete: Cascade)
@@id([projectId, code])
}
// @deprecated
model ProjectUserMagicLinkCode {
projectId String
projectUserId String @db.Uuid
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
code String @unique
expiresAt DateTime
usedAt DateTime?
redirectUrl String
newUser Boolean
projectUser ProjectUser @relation(fields: [projectId, projectUserId], references: [projectId, projectUserId], onDelete: Cascade)
@@id([projectId, code])
}
//#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 OAuth
// Exactly one of the xyzOAuthConfig variables should be set.
model OAuthProviderConfig {
projectConfigId String @db.Uuid
projectConfig ProjectConfig @relation(fields: [projectConfigId], references: [id], onDelete: Cascade)
id String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
enabled Boolean @default(true)
proxiedOAuthConfig ProxiedOAuthProviderConfig?
standardOAuthConfig StandardOAuthProviderConfig?
projectUserOAuthAccounts ProjectUserOAuthAccount[]
@@id([projectConfigId, id])
}
model ProxiedOAuthProviderConfig {
projectConfigId String @db.Uuid
providerConfig OAuthProviderConfig @relation(fields: [projectConfigId, id], references: [projectConfigId, id], onDelete: Cascade)
id String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
type ProxiedOAuthProviderType
@@id([projectConfigId, id])
@@unique([projectConfigId, type])
}
enum ProxiedOAuthProviderType {
GITHUB
FACEBOOK
GOOGLE
MICROSOFT
SPOTIFY
}
model StandardOAuthProviderConfig {
projectConfigId String @db.Uuid
providerConfig OAuthProviderConfig @relation(fields: [projectConfigId, id], references: [projectConfigId, id], onDelete: Cascade)
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?
@@id([projectConfigId, id])
}
enum StandardOAuthProviderType {
GITHUB
FACEBOOK
GOOGLE
MICROSOFT
SPOTIFY
DISCORD
GITLAB
}
//#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
}
//#endregion