b1987dc090
## Summary Adds Billing Limits to the webapp. Customers can set a monthly spend cap. When usage crosses the limit, billable environments enter a grace period. If the limit is not resolved before grace expires, new triggers are rejected until the organization increases or removes the limit.
3202 lines
95 KiB
Plaintext
3202 lines
95 KiB
Plaintext
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
directUrl = env("DIRECT_URL")
|
|
}
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
output = "../generated/prisma"
|
|
binaryTargets = ["native", "debian-openssl-1.1.x"]
|
|
previewFeatures = ["metrics"]
|
|
}
|
|
|
|
model User {
|
|
id String @id @default(cuid())
|
|
email String @unique
|
|
|
|
authenticationMethod AuthenticationMethod
|
|
authenticationProfile Json?
|
|
authenticationExtraParams Json?
|
|
authIdentifier String? @unique
|
|
|
|
displayName String?
|
|
name String?
|
|
avatarUrl String?
|
|
|
|
admin Boolean @default(false)
|
|
|
|
/// Preferences for the dashboard
|
|
dashboardPreferences Json?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
/// @deprecated
|
|
isOnCloudWaitlist Boolean @default(false)
|
|
/// @deprecated
|
|
featureCloud Boolean @default(false)
|
|
/// @deprecated
|
|
isOnHostedRepoWaitlist Boolean @default(false)
|
|
|
|
marketingEmails Boolean @default(true)
|
|
confirmedBasicDetails Boolean @default(false)
|
|
|
|
referralSource String?
|
|
onboardingData Json?
|
|
|
|
orgMemberships OrgMember[]
|
|
sentInvites OrgMemberInvite[]
|
|
|
|
mfaEnabledAt DateTime?
|
|
mfaSecretReference SecretReference? @relation(fields: [mfaSecretReferenceId], references: [id])
|
|
mfaSecretReferenceId String?
|
|
/// Hash of the last used code to prevent replay attacks
|
|
mfaLastUsedCode String?
|
|
|
|
/// Maximum session lifetime in seconds for this user. Default = 1 year (Gregorian).
|
|
/// May be further restricted by Organization.maxSessionDuration on any of the user's orgs.
|
|
sessionDuration Int @default(31556952)
|
|
|
|
/// Absolute timestamp at which the user's current session must end. Written
|
|
/// at login (and any time the effective duration is recomputed) and shortened
|
|
/// when an admin lowers an org cap. Read on requireUser / getUser; null is
|
|
/// treated as "no enforced deadline" (legacy sessions from before this
|
|
/// shipped). Read-on-demand has zero per-request DB cost — the value
|
|
/// piggybacks on the User fetch that requireUser already does.
|
|
nextSessionEnd DateTime?
|
|
|
|
invitationCode InvitationCode? @relation(fields: [invitationCodeId], references: [id])
|
|
invitationCodeId String?
|
|
personalAccessTokens PersonalAccessToken[]
|
|
deployments WorkerDeployment[]
|
|
backupCodes MfaBackupCode[]
|
|
bulkActions BulkActionGroup[]
|
|
|
|
impersonationsPerformed ImpersonationAuditLog[] @relation("ImpersonationAdmin")
|
|
impersonationsReceived ImpersonationAuditLog[] @relation("ImpersonationTarget")
|
|
customerQueries CustomerQuery[]
|
|
metricsDashboards MetricsDashboard[]
|
|
platformNotifications PlatformNotification[]
|
|
platformNotificationInteractions PlatformNotificationInteraction[]
|
|
}
|
|
|
|
model MfaBackupCode {
|
|
id String @id @default(cuid())
|
|
/// Hash of the actual code
|
|
code String
|
|
|
|
user User @relation(fields: [userId], references: [id])
|
|
userId String
|
|
|
|
usedAt DateTime?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([userId, code])
|
|
}
|
|
|
|
// @deprecated This model is no longer used as the Cloud is out of private beta
|
|
// Leaving it here for now for historical reasons
|
|
model InvitationCode {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
|
|
users User[]
|
|
|
|
createdAt DateTime @default(now())
|
|
}
|
|
|
|
enum AuthenticationMethod {
|
|
GITHUB
|
|
MAGIC_LINK
|
|
GOOGLE
|
|
SSO
|
|
}
|
|
|
|
/// Used to generate PersonalAccessTokens, they're one-time use
|
|
model AuthorizationCode {
|
|
id String @id @default(cuid())
|
|
|
|
code String @unique
|
|
|
|
personalAccessToken PersonalAccessToken? @relation(fields: [personalAccessTokenId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
personalAccessTokenId String?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
// Used by User's to perform API actions
|
|
model PersonalAccessToken {
|
|
id String @id @default(cuid())
|
|
|
|
/// If generated by the CLI this will be "cli", otherwise user-provided
|
|
name String
|
|
|
|
/// This is the token encrypted using the ENCRYPTION_KEY
|
|
encryptedToken Json
|
|
|
|
/// This is shown in the UI, with ********
|
|
obfuscatedToken String
|
|
|
|
/// This is used to find the token in the database
|
|
hashedToken String @unique
|
|
|
|
user User @relation(fields: [userId], references: [id])
|
|
userId String
|
|
|
|
revokedAt DateTime?
|
|
lastAccessedAt DateTime?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
authorizationCodes AuthorizationCode[]
|
|
}
|
|
|
|
enum OrganizationAccessTokenType {
|
|
USER
|
|
SYSTEM
|
|
}
|
|
|
|
model OrganizationAccessToken {
|
|
id String @id @default(cuid())
|
|
|
|
/// User-provided name for the token
|
|
name String
|
|
|
|
/// Used to differentiate between user-generated and system-generated tokens
|
|
type OrganizationAccessTokenType @default(USER)
|
|
|
|
/// This is used to find the token in the database
|
|
hashedToken String @unique
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id])
|
|
organizationId String
|
|
|
|
/// Optional expiration date for the token
|
|
expiresAt DateTime?
|
|
revokedAt DateTime?
|
|
lastAccessedAt DateTime?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([organizationId, type, createdAt(sort: Desc)])
|
|
}
|
|
|
|
model Organization {
|
|
id String @id @default(cuid())
|
|
slug String @unique
|
|
title String
|
|
|
|
maximumExecutionTimePerRunInMs Int @default(900000) // 15 minutes
|
|
maximumConcurrencyLimit Int @default(10)
|
|
/// This is deprecated and will be removed in the future
|
|
maximumSchedulesLimit Int @default(5)
|
|
|
|
maximumDevQueueSize Int?
|
|
maximumDeployedQueueSize Int?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
companySize String?
|
|
|
|
onboardingData Json?
|
|
|
|
avatar Json?
|
|
|
|
runsEnabled Boolean @default(true)
|
|
|
|
v3Enabled Boolean @default(false)
|
|
|
|
/// @deprecated
|
|
v2Enabled Boolean @default(false)
|
|
/// @deprecated
|
|
v2MarqsEnabled Boolean @default(false)
|
|
/// @deprecated
|
|
hasRequestedV3 Boolean @default(false)
|
|
|
|
environments RuntimeEnvironment[]
|
|
|
|
apiRateLimiterConfig Json?
|
|
realtimeRateLimiterConfig Json?
|
|
|
|
batchRateLimitConfig Json?
|
|
batchQueueConcurrencyConfig Json?
|
|
|
|
featureFlags Json?
|
|
|
|
maximumProjectCount Int @default(25)
|
|
|
|
/// Maximum session lifetime in seconds for members of this organization.
|
|
/// When set, caps each member's User.sessionDuration. The most restrictive cap across
|
|
/// all of a user's orgs (excluding nulls) wins.
|
|
maxSessionDuration Int?
|
|
|
|
projects Project[]
|
|
members OrgMember[]
|
|
invites OrgMemberInvite[]
|
|
organizationIntegrations OrganizationIntegration[]
|
|
organizationAccessTokens OrganizationAccessToken[]
|
|
workerGroups WorkerInstanceGroup[]
|
|
workerInstances WorkerInstance[]
|
|
githubAppInstallations GithubAppInstallation[]
|
|
customerQueries CustomerQuery[]
|
|
metricsDashboards MetricsDashboard[]
|
|
prompts Prompt[]
|
|
|
|
platformNotifications PlatformNotification[]
|
|
errorGroupStates ErrorGroupState[]
|
|
|
|
/// S2 basin that holds this org's realtime streams. Null until the
|
|
/// per-org basin has been provisioned (OSS / s2-lite installs leave
|
|
/// it null forever; reads fall back to the global basin env var).
|
|
/// Set once at provisioning time; retention is reconfigured in-place
|
|
/// when the org's plan changes.
|
|
streamBasinName String?
|
|
}
|
|
|
|
model OrgMember {
|
|
id String @id @default(cuid())
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
organizationId String
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
userId String
|
|
|
|
role OrgMemberRole @default(MEMBER)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
environments RuntimeEnvironment[]
|
|
|
|
@@unique([organizationId, userId])
|
|
}
|
|
|
|
enum OrgMemberRole {
|
|
ADMIN
|
|
MEMBER
|
|
}
|
|
|
|
model OrgMemberInvite {
|
|
id String @id @default(cuid())
|
|
token String @unique @default(cuid())
|
|
email String
|
|
role OrgMemberRole @default(MEMBER)
|
|
|
|
/// Optional RBAC role to assign on invite acceptance. When set, the
|
|
/// accept-invite flow calls the loaded RBAC plugin's setUserRole with
|
|
/// this id after creating the OrgMember. Null = legacy behaviour, the
|
|
/// runtime fallback derives the role from `role` above.
|
|
///
|
|
/// Plain text (not an FK) — the RBAC plugin's RbacRole table lives on
|
|
/// a separate schema (Drizzle, not Prisma) so we can't model the FK
|
|
/// here. Validation happens at write time (action) and read time
|
|
/// (acceptInvite).
|
|
rbacRoleId String?
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
organizationId String
|
|
|
|
inviter User @relation(fields: [inviterId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
inviterId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([organizationId, email])
|
|
}
|
|
|
|
model RuntimeEnvironment {
|
|
id String @id @default(cuid())
|
|
slug String
|
|
apiKey String @unique
|
|
|
|
/// @deprecated was for v2
|
|
pkApiKey String @unique
|
|
|
|
type RuntimeEnvironmentType @default(DEVELOPMENT)
|
|
|
|
// Preview branches
|
|
/// If true, this environment has branches and is treated differently in the dashboard/API
|
|
/// NB: this flag is NOT used for Development branches, instead (type, parentEnvironmentId) = (DEVELOPMENT, NULL) is used
|
|
isBranchableEnvironment Boolean @default(false)
|
|
branchName String?
|
|
parentEnvironment RuntimeEnvironment? @relation("parentEnvironment", fields: [parentEnvironmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
parentEnvironmentId String?
|
|
childEnvironments RuntimeEnvironment[] @relation("parentEnvironment")
|
|
|
|
// This is GitMeta type
|
|
git Json?
|
|
|
|
/// When set API calls will fail
|
|
archivedAt DateTime?
|
|
|
|
///A memorable code for the environment
|
|
shortcode String
|
|
|
|
maximumConcurrencyLimit Int @default(5)
|
|
concurrencyLimitBurstFactor Decimal @default("2.00") @db.Decimal(4, 2)
|
|
paused Boolean @default(false)
|
|
pauseSource EnvironmentPauseSource?
|
|
|
|
autoEnableInternalSources Boolean @default(true)
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
organizationId String
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
//when the org member is deleted, it will keep the environment but set it to null
|
|
orgMember OrgMember? @relation(fields: [orgMemberId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
orgMemberId String?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
/// Allows us to customize the built-in environment variables for a specific environment, like TRIGGER_OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT
|
|
builtInEnvironmentVariableOverrides Json?
|
|
|
|
tunnelId String?
|
|
|
|
backgroundWorkers BackgroundWorker[]
|
|
backgroundWorkerTasks BackgroundWorkerTask[]
|
|
taskRuns TaskRun[]
|
|
taskQueues TaskQueue[]
|
|
batchTaskRuns BatchTaskRun[]
|
|
environmentVariableValues EnvironmentVariableValue[]
|
|
checkpoints Checkpoint[]
|
|
workerDeployments WorkerDeployment[]
|
|
workerDeploymentPromotions WorkerDeploymentPromotion[]
|
|
taskRunAttempts TaskRunAttempt[]
|
|
CheckpointRestoreEvent CheckpointRestoreEvent[]
|
|
taskScheduleInstances TaskScheduleInstance[]
|
|
alerts ProjectAlert[]
|
|
|
|
sessions RuntimeEnvironmentSession[]
|
|
currentSession RuntimeEnvironmentSession? @relation("currentSession", fields: [currentSessionId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
currentSessionId String?
|
|
taskRunNumberCounter TaskRunNumberCounter[]
|
|
taskRunCheckpoints TaskRunCheckpoint[]
|
|
waitpoints Waitpoint[]
|
|
workerInstances WorkerInstance[]
|
|
waitpointTags WaitpointTag[]
|
|
BulkActionGroup BulkActionGroup[]
|
|
customerQueries CustomerQuery[]
|
|
prompts Prompt[]
|
|
playgroundConversations PlaygroundConversation[]
|
|
errorGroupStates ErrorGroupState[]
|
|
taskIdentifiers TaskIdentifier[]
|
|
revokedApiKeys RevokedApiKey[]
|
|
|
|
@@unique([projectId, slug, orgMemberId])
|
|
@@unique([projectId, shortcode])
|
|
@@index([parentEnvironmentId])
|
|
@@index([projectId])
|
|
@@index([organizationId])
|
|
}
|
|
|
|
/// Records of previously-valid API keys that are still accepted for authentication
|
|
/// during a grace window after rotation. Extend or end the grace period by updating `expiresAt`.
|
|
model RevokedApiKey {
|
|
id String @id @default(cuid())
|
|
apiKey String
|
|
runtimeEnvironment RuntimeEnvironment @relation(fields: [runtimeEnvironmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
runtimeEnvironmentId String
|
|
expiresAt DateTime
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([apiKey])
|
|
@@index([runtimeEnvironmentId])
|
|
}
|
|
|
|
enum RuntimeEnvironmentType {
|
|
PRODUCTION
|
|
STAGING
|
|
DEVELOPMENT
|
|
PREVIEW
|
|
}
|
|
|
|
enum EnvironmentPauseSource {
|
|
BILLING_LIMIT
|
|
}
|
|
|
|
model Project {
|
|
id String @id @default(cuid())
|
|
slug String @unique
|
|
name String
|
|
|
|
externalRef String @unique
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
organizationId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
version ProjectVersion @default(V2)
|
|
engine RunEngineVersion @default(V1)
|
|
|
|
builderProjectId String?
|
|
|
|
workerGroups WorkerInstanceGroup[]
|
|
workers WorkerInstance[]
|
|
|
|
defaultWorkerGroup WorkerInstanceGroup? @relation("ProjectDefaultWorkerGroup", fields: [defaultWorkerGroupId], references: [id])
|
|
defaultWorkerGroupId String?
|
|
|
|
/// The master queues they are allowed to use (impacts what they can set as default and trigger runs with)
|
|
allowedWorkerQueues String[] @default([]) @map("allowedMasterQueues")
|
|
|
|
environments RuntimeEnvironment[]
|
|
backgroundWorkers BackgroundWorker[]
|
|
backgroundWorkerTasks BackgroundWorkerTask[]
|
|
taskRuns TaskRun[]
|
|
runTags TaskRunTag[]
|
|
taskQueues TaskQueue[]
|
|
environmentVariables EnvironmentVariable[]
|
|
checkpoints Checkpoint[]
|
|
WorkerDeployment WorkerDeployment[]
|
|
CheckpointRestoreEvent CheckpointRestoreEvent[]
|
|
taskSchedules TaskSchedule[]
|
|
alertChannels ProjectAlertChannel[]
|
|
alerts ProjectAlert[]
|
|
alertStorages ProjectAlertStorage[]
|
|
bulkActionGroups BulkActionGroup[]
|
|
BackgroundWorkerFile BackgroundWorkerFile[]
|
|
waitpoints Waitpoint[]
|
|
taskRunWaitpoints TaskRunWaitpoint[]
|
|
taskRunCheckpoints TaskRunCheckpoint[]
|
|
waitpointTags WaitpointTag[]
|
|
connectedGithubRepository ConnectedGithubRepository?
|
|
organizationProjectIntegration OrganizationProjectIntegration[]
|
|
customerQueries CustomerQuery[]
|
|
playgroundConversations PlaygroundConversation[]
|
|
|
|
buildSettings Json?
|
|
onboardingData Json?
|
|
taskScheduleInstances TaskScheduleInstance[]
|
|
metricsDashboards MetricsDashboard[]
|
|
llmModels LlmModel[]
|
|
prompts Prompt[]
|
|
platformNotifications PlatformNotification[]
|
|
errorGroupStates ErrorGroupState[]
|
|
taskIdentifiers TaskIdentifier[]
|
|
}
|
|
|
|
enum ProjectVersion {
|
|
V2
|
|
V3
|
|
}
|
|
|
|
model SecretReference {
|
|
id String @id @default(cuid())
|
|
key String @unique
|
|
provider SecretStoreProvider @default(DATABASE)
|
|
|
|
environmentVariableValues EnvironmentVariableValue[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
OrganizationIntegration OrganizationIntegration[]
|
|
User User[]
|
|
}
|
|
|
|
enum SecretStoreProvider {
|
|
DATABASE
|
|
AWS_PARAM_STORE
|
|
}
|
|
|
|
model SecretStore {
|
|
key String @unique
|
|
value Json
|
|
version String @default("1")
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([key(ops: raw("text_pattern_ops"))], type: BTree)
|
|
}
|
|
|
|
model DataMigration {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
completedAt DateTime?
|
|
}
|
|
|
|
// ====================================================
|
|
// v3 Models
|
|
// ====================================================
|
|
model BackgroundWorker {
|
|
id String @id @default(cuid())
|
|
|
|
friendlyId String @unique
|
|
|
|
engine RunEngineVersion @default(V1)
|
|
|
|
contentHash String
|
|
sdkVersion String @default("unknown")
|
|
cliVersion String @default("unknown")
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
runtimeEnvironment RuntimeEnvironment @relation(fields: [runtimeEnvironmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
runtimeEnvironmentId String
|
|
|
|
version String
|
|
metadata Json
|
|
|
|
runtime String?
|
|
runtimeVersion String?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tasks BackgroundWorkerTask[]
|
|
attempts TaskRunAttempt[]
|
|
lockedRuns TaskRun[]
|
|
files BackgroundWorkerFile[]
|
|
queues TaskQueue[]
|
|
promptVersions PromptVersion[]
|
|
|
|
deployment WorkerDeployment?
|
|
|
|
workerGroup WorkerInstanceGroup? @relation(fields: [workerGroupId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
workerGroupId String?
|
|
|
|
supportsLazyAttempts Boolean @default(false)
|
|
|
|
taskIdentifiers TaskIdentifier[]
|
|
|
|
@@unique([projectId, runtimeEnvironmentId, version])
|
|
@@index([runtimeEnvironmentId])
|
|
// Get the latest worker for a given environment
|
|
@@index([runtimeEnvironmentId, createdAt(sort: Desc)])
|
|
}
|
|
|
|
model BackgroundWorkerFile {
|
|
id String @id @default(cuid())
|
|
|
|
friendlyId String @unique
|
|
|
|
filePath String
|
|
contentHash String
|
|
contents Bytes
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
backgroundWorkers BackgroundWorker[]
|
|
|
|
tasks BackgroundWorkerTask[]
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@unique([projectId, contentHash])
|
|
}
|
|
|
|
model Prompt {
|
|
id String @id @default(cuid())
|
|
friendlyId String @unique @map("friendly_id")
|
|
slug String
|
|
description String?
|
|
type String @default("text") // "text" | "chat"
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
organizationId String
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
runtimeEnvironment RuntimeEnvironment @relation(fields: [runtimeEnvironmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
runtimeEnvironmentId String
|
|
|
|
filePath String?
|
|
exportName String?
|
|
variableSchema Json?
|
|
defaultModel String?
|
|
defaultConfig Json?
|
|
|
|
tags String[] @default([])
|
|
archivedAt DateTime?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
versions PromptVersion[]
|
|
|
|
@@unique([projectId, runtimeEnvironmentId, slug])
|
|
@@index([projectId])
|
|
@@index([runtimeEnvironmentId])
|
|
@@map("prompts")
|
|
}
|
|
|
|
model PromptVersion {
|
|
id String @id @default(cuid())
|
|
version Int
|
|
|
|
prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
promptId String
|
|
|
|
textContent String?
|
|
chatContent Json?
|
|
|
|
model String?
|
|
config Json?
|
|
|
|
source String // "deploy" | "dashboard" | "api"
|
|
commitMessage String?
|
|
contentHash String
|
|
|
|
labels String[] @default([])
|
|
|
|
worker BackgroundWorker? @relation(fields: [workerId], references: [id])
|
|
workerId String?
|
|
|
|
createdBy String?
|
|
createdAt DateTime @default(now())
|
|
|
|
@@unique([promptId, version])
|
|
@@index([promptId])
|
|
@@index([contentHash])
|
|
@@map("prompt_versions")
|
|
}
|
|
|
|
model BackgroundWorkerTask {
|
|
id String @id @default(cuid())
|
|
slug String
|
|
|
|
description String?
|
|
|
|
friendlyId String @unique
|
|
|
|
filePath String
|
|
exportName String?
|
|
|
|
worker BackgroundWorker @relation(fields: [workerId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
workerId String
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
file BackgroundWorkerFile? @relation(fields: [fileId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
fileId String?
|
|
|
|
runtimeEnvironment RuntimeEnvironment @relation(fields: [runtimeEnvironmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
runtimeEnvironmentId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
attempts TaskRunAttempt[]
|
|
runs TaskRun[]
|
|
|
|
queueConfig Json?
|
|
retryConfig Json?
|
|
machineConfig Json?
|
|
|
|
queueId String?
|
|
queue TaskQueue? @relation(fields: [queueId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
|
|
maxDurationInSeconds Int?
|
|
|
|
ttl String?
|
|
|
|
triggerSource TaskTriggerSource @default(STANDARD)
|
|
|
|
/// Extra task configuration JSON. Shape depends on triggerSource.
|
|
/// AGENT: { type: "ai-sdk-chat" }
|
|
config Json?
|
|
|
|
payloadSchema Json?
|
|
|
|
@@unique([workerId, slug])
|
|
// Quick lookup of task identifiers
|
|
@@index([projectId, slug])
|
|
@@index([runtimeEnvironmentId, projectId])
|
|
@@index([runtimeEnvironmentId, slug, triggerSource])
|
|
}
|
|
|
|
enum TaskTriggerSource {
|
|
STANDARD
|
|
SCHEDULED
|
|
AGENT
|
|
}
|
|
|
|
model PlaygroundConversation {
|
|
id String @id @default(cuid())
|
|
|
|
/// The chat session ID used by the transport
|
|
chatId String
|
|
|
|
/// User-editable conversation title (auto-generated from first message)
|
|
title String @default("New conversation")
|
|
|
|
/// Which agent this conversation is with
|
|
agentSlug String
|
|
|
|
/// The current active run backing this conversation (null if no run yet)
|
|
runId String?
|
|
run TaskRun? @relation(fields: [runId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
|
|
/// The client data JSON used for this conversation
|
|
clientData Json?
|
|
|
|
/// Accumulated UIMessages from completed turns (for resume without stream replay)
|
|
messages Json?
|
|
|
|
/// Last SSE event ID — resume from this position to avoid replaying old turns
|
|
lastEventId String?
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
runtimeEnvironment RuntimeEnvironment @relation(fields: [runtimeEnvironmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
runtimeEnvironmentId String
|
|
|
|
/// The user who started this conversation
|
|
userId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([chatId, runtimeEnvironmentId])
|
|
@@index([runtimeEnvironmentId, agentSlug, updatedAt(sort: Desc)])
|
|
@@index([userId, runtimeEnvironmentId])
|
|
}
|
|
|
|
/// Durable, typed, bidirectional I/O primitive. Owns two S2 streams (.out / .in).
|
|
/// The row is essentially static — no status, no counters, no pointers. No
|
|
/// foreign keys: project/runtimeEnvironment/organization ids are plain
|
|
/// scalar columns (matches TaskRun pattern). List-style queries are served
|
|
/// from ClickHouse, not Postgres, so only point-lookup indexes live here.
|
|
model Session {
|
|
id String @id @default(cuid())
|
|
friendlyId String @unique
|
|
/// User-supplied identifier scoped to the environment. Used for
|
|
/// idempotent upsert and for resolving sessions via the public API.
|
|
externalId String?
|
|
|
|
/// Plain string — intentionally not an enum.
|
|
type String
|
|
|
|
/// Denormalized scoping columns — no FK relations.
|
|
projectId String
|
|
runtimeEnvironmentId String
|
|
environmentType RuntimeEnvironmentType
|
|
organizationId String
|
|
|
|
/// Task this session triggers runs against. Required — Sessions are
|
|
/// task-bound: creating a session also triggers its first run, and
|
|
/// every subsequent re-trigger uses this same identifier.
|
|
taskIdentifier String
|
|
|
|
/// Trigger config used for every run this session schedules. Shape
|
|
/// (validated at the route layer, opaque to the DB):
|
|
/// { basePayload: object, machine?: string, queue?: string,
|
|
/// tags?: string[], maxAttempts?: number,
|
|
/// idleTimeoutInSeconds?: number }
|
|
/// `basePayload` carries the customer's client-data; runtime fields
|
|
/// (chatId, messages, trigger) are merged at trigger time.
|
|
triggerConfig Json
|
|
|
|
/// Whether this session was created from the Test/playground UI rather
|
|
/// than by a real chat.agent() trigger. Mirrors TaskRun.isTest.
|
|
isTest Boolean @default(false)
|
|
|
|
tags String[] @default([])
|
|
metadata Json?
|
|
|
|
/// Live run pointer — non-FK so run deletion never cascades. Can lag
|
|
/// reality; the `.in/append` handler re-checks the snapshot status
|
|
/// before reusing it.
|
|
currentRunId String?
|
|
/// Monotonic counter used for optimistic locking on `currentRunId`
|
|
/// swaps. Bumped atomically alongside any update that changes
|
|
/// `currentRunId`.
|
|
currentRunVersion Int @default(0)
|
|
|
|
/// Terminal markers — written once, never flipped back.
|
|
closedAt DateTime?
|
|
closedReason String?
|
|
expiresAt DateTime?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
/// S2 basin where this session's stream pair lives. Stamped at create
|
|
/// time from `Organization.streamBasinName` so reads can resolve the
|
|
/// basin without joining org. Null when the org has no per-org basin
|
|
/// (OSS, or pre-backfill); reads fall back to the global basin.
|
|
streamBasinName String?
|
|
|
|
/// Storage URI (with protocol prefix) for this session's chat.agent
|
|
/// snapshot blob. Set on first snapshot write. Null = pre-column session,
|
|
/// fall back to computed default path.
|
|
chatSnapshotStoragePath String?
|
|
|
|
runs SessionRun[]
|
|
|
|
/// Idempotency: `(env, externalId)` uniquely identifies a session.
|
|
/// PostgreSQL treats NULLs as distinct, so `externalId=NULL` rows never collide.
|
|
@@unique([runtimeEnvironmentId, externalId])
|
|
@@index([expiresAt])
|
|
@@index([currentRunId])
|
|
}
|
|
|
|
/// Historical record of every run a Session has owned. Append-only —
|
|
/// rows are inserted on each `ensureRunForSession` claim, never updated.
|
|
/// Lets us reconstruct the run timeline of a chat for debugging /
|
|
/// dashboard surfaces. The relation cascades on Session delete (tied to
|
|
/// the session lifecycle) but `runId` is a plain string column with no
|
|
/// FK to TaskRun so run pruning is independent.
|
|
model SessionRun {
|
|
id String @id @default(cuid())
|
|
|
|
sessionId String
|
|
/// TaskRun.id (no FK — runs may be archived independently of session history)
|
|
runId String @unique
|
|
/// One of: "initial" | "continuation" | "upgrade" | "manual".
|
|
/// Plain string for forward-compat with future trigger reasons.
|
|
reason String
|
|
triggeredAt DateTime @default(now())
|
|
|
|
session Session @relation(fields: [sessionId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([sessionId])
|
|
}
|
|
|
|
model TaskRun {
|
|
id String @id @default(cuid())
|
|
|
|
number Int @default(0)
|
|
friendlyId String @unique
|
|
|
|
engine RunEngineVersion @default(V1)
|
|
|
|
status TaskRunStatus @default(PENDING)
|
|
statusReason String?
|
|
|
|
idempotencyKey String?
|
|
idempotencyKeyExpiresAt DateTime?
|
|
/// Stores the user-provided key and scope: { key: string, scope: "run" | "attempt" | "global" }
|
|
idempotencyKeyOptions Json?
|
|
|
|
/// Debounce options: { key: string, delay: string, createdAt: Date }
|
|
debounce Json?
|
|
|
|
taskIdentifier String
|
|
|
|
isTest Boolean @default(false)
|
|
|
|
payload String
|
|
payloadType String @default("application/json")
|
|
context Json?
|
|
traceContext Json?
|
|
|
|
traceId String
|
|
spanId String
|
|
|
|
runtimeEnvironment RuntimeEnvironment @relation(fields: [runtimeEnvironmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
runtimeEnvironmentId String
|
|
|
|
environmentType RuntimeEnvironmentType?
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
organizationId String?
|
|
|
|
// The specific queue this run is in
|
|
queue String
|
|
// The queueId is set when the run is locked to a specific queue
|
|
lockedQueueId String?
|
|
|
|
/// The main queue that this run is part of
|
|
workerQueue String @default("main") @map("masterQueue")
|
|
|
|
/// User-facing geo region, stamped at trigger; workerQueue is where it actually ran.
|
|
region String?
|
|
|
|
/// @deprecated
|
|
secondaryMasterQueue String?
|
|
|
|
/// From engine v2+ this will be defined after a run has been dequeued (starting at 1)
|
|
attemptNumber Int?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
attempts TaskRunAttempt[] @relation("attempts")
|
|
tags TaskRunTag[]
|
|
|
|
/// Denormized column that holds the raw tags
|
|
runTags String[]
|
|
|
|
/// Denormalized version of the background worker task
|
|
taskVersion String?
|
|
sdkVersion String?
|
|
cliVersion String?
|
|
|
|
checkpoints Checkpoint[]
|
|
|
|
/// startedAt marks the point at which a run is dequeued from MarQS
|
|
startedAt DateTime?
|
|
/// executedAt is set when the first attempt is about to execute
|
|
executedAt DateTime?
|
|
completedAt DateTime?
|
|
machinePreset String?
|
|
|
|
usageDurationMs Int @default(0)
|
|
costInCents Float @default(0)
|
|
baseCostInCents Float @default(0)
|
|
|
|
lockedAt DateTime?
|
|
lockedBy BackgroundWorkerTask? @relation(fields: [lockedById], references: [id])
|
|
lockedById String?
|
|
|
|
lockedToVersion BackgroundWorker? @relation(fields: [lockedToVersionId], references: [id])
|
|
lockedToVersionId String?
|
|
|
|
/// The "priority" of the run. This is just a negative offset in ms for the queue timestamp
|
|
/// E.g. a value of 60_000 would put the run into the queue 60s ago.
|
|
priorityMs Int @default(0)
|
|
|
|
concurrencyKey String?
|
|
|
|
delayUntil DateTime?
|
|
queuedAt DateTime?
|
|
ttl String?
|
|
expiredAt DateTime?
|
|
maxAttempts Int?
|
|
lockedRetryConfig Json?
|
|
|
|
/// optional token that can be used to authenticate the task run
|
|
oneTimeUseToken String?
|
|
|
|
///When this run is finished, the waitpoint will be marked as completed
|
|
associatedWaitpoint Waitpoint? @relation("CompletingRun")
|
|
|
|
///If there are any blocked waitpoints, the run won't be executed
|
|
blockedByWaitpoints TaskRunWaitpoint[]
|
|
|
|
/// All waitpoints that blocked this run at some point, used for display purposes
|
|
connectedWaitpoints Waitpoint[] @relation("WaitpointRunConnections")
|
|
|
|
/// Where the logs are stored
|
|
taskEventStore String @default("taskEvent")
|
|
|
|
queueTimestamp DateTime?
|
|
|
|
batchItems BatchTaskRunItem[]
|
|
dependency TaskRunDependency?
|
|
CheckpointRestoreEvent CheckpointRestoreEvent[]
|
|
executionSnapshots TaskRunExecutionSnapshot[]
|
|
|
|
alerts ProjectAlert[]
|
|
|
|
scheduleInstanceId String?
|
|
scheduleId String?
|
|
|
|
sourceBulkActionItems BulkActionItem[] @relation("SourceActionItemRun")
|
|
destinationBulkActionItems BulkActionItem[] @relation("DestinationActionItemRun")
|
|
|
|
bulkActionGroupIds String[] @default([])
|
|
|
|
logsDeletedAt DateTime?
|
|
|
|
replayedFromTaskRunFriendlyId String?
|
|
|
|
/// This represents the original task that that was triggered outside of a Trigger.dev task
|
|
rootTaskRun TaskRun? @relation("TaskRootRun", fields: [rootTaskRunId], references: [id], onDelete: SetNull, onUpdate: NoAction)
|
|
rootTaskRunId String?
|
|
|
|
/// The root run will have a list of all the descendant runs, children, grand children, etc.
|
|
descendantRuns TaskRun[] @relation("TaskRootRun")
|
|
|
|
/// The immediate parent run of this task run
|
|
parentTaskRun TaskRun? @relation("TaskParentRun", fields: [parentTaskRunId], references: [id], onDelete: SetNull, onUpdate: NoAction)
|
|
parentTaskRunId String?
|
|
|
|
/// The immediate child runs of this task run
|
|
childRuns TaskRun[] @relation("TaskParentRun")
|
|
|
|
/// The immediate parent attempt of this task run
|
|
parentTaskRunAttempt TaskRunAttempt? @relation("TaskParentRunAttempt", fields: [parentTaskRunAttemptId], references: [id], onDelete: SetNull, onUpdate: NoAction)
|
|
parentTaskRunAttemptId String?
|
|
|
|
/// The batch run that this task run is a part of
|
|
batch BatchTaskRun? @relation(fields: [batchId], references: [id], onDelete: SetNull, onUpdate: NoAction)
|
|
batchId String?
|
|
|
|
/// whether or not the task run was created because of a triggerAndWait for batchTriggerAndWait
|
|
resumeParentOnCompletion Boolean @default(false)
|
|
|
|
/// The depth of this task run in the task run hierarchy
|
|
depth Int @default(0)
|
|
|
|
/// The span ID of the "trigger" span in the parent task run
|
|
parentSpanId String?
|
|
|
|
/// Holds the state of the run chain for deadlock detection
|
|
runChainState Json?
|
|
|
|
/// seed run metadata
|
|
seedMetadata String?
|
|
seedMetadataType String @default("application/json")
|
|
|
|
/// Run metadata
|
|
metadata String?
|
|
metadataType String @default("application/json")
|
|
metadataVersion Int @default(1)
|
|
|
|
/// Structured annotations: triggerSource, triggerAction, rootTriggerSource, rootScheduleId
|
|
annotations Json?
|
|
|
|
/// Whether the latest attempt was a warm start. Null until first attempt starts.
|
|
isWarmStart Boolean?
|
|
|
|
/// Run output
|
|
output String?
|
|
outputType String @default("application/json")
|
|
|
|
/// Run error
|
|
error Json?
|
|
|
|
/// Organization's billing plan type (cached for fallback when billing API fails)
|
|
planType String?
|
|
|
|
maxDurationInSeconds Int?
|
|
|
|
/// The version of the realtime streams implementation used by the run
|
|
realtimeStreamsVersion String @default("v1")
|
|
/// Store the stream keys that are being used by the run
|
|
realtimeStreams String[] @default([])
|
|
/// S2 basin where this run's realtime streams live. Stamped at create
|
|
/// time from `Organization.streamBasinName` so reads can resolve the
|
|
/// basin without joining org. Null when the org has no per-org basin
|
|
/// (OSS, or pre-backfill); reads fall back to the global basin.
|
|
streamBasinName String?
|
|
|
|
playgroundConversations PlaygroundConversation[]
|
|
|
|
@@unique([oneTimeUseToken])
|
|
@@unique([runtimeEnvironmentId, taskIdentifier, idempotencyKey])
|
|
// Finding child runs
|
|
@@index([parentTaskRunId])
|
|
// Run page inspector
|
|
@@index([spanId])
|
|
@@index([parentSpanId])
|
|
// Finding runs in a batch
|
|
@@index([runTags(ops: ArrayOps)], type: Gin)
|
|
@@index([runtimeEnvironmentId, batchId])
|
|
@@index([runtimeEnvironmentId, createdAt(sort: Desc)])
|
|
@@index([createdAt], type: Brin)
|
|
}
|
|
|
|
model TaskRunTemplate {
|
|
id String @id @default(cuid())
|
|
|
|
taskSlug String
|
|
triggerSource TaskTriggerSource
|
|
|
|
label String
|
|
|
|
payload String?
|
|
payloadType String @default("application/json")
|
|
metadata String?
|
|
metadataType String @default("application/json")
|
|
queue String?
|
|
concurrencyKey String?
|
|
ttlSeconds Int?
|
|
maxAttempts Int?
|
|
maxDurationSeconds Int?
|
|
tags String[]
|
|
machinePreset String?
|
|
|
|
projectId String
|
|
organizationId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([projectId, taskSlug, triggerSource, createdAt(sort: Desc)])
|
|
}
|
|
|
|
enum TaskRunStatus {
|
|
///
|
|
/// NON-FINAL STATUSES
|
|
///
|
|
|
|
/// Task has been scheduled to run in the future
|
|
DELAYED
|
|
/// Task is waiting to be executed by a worker
|
|
PENDING
|
|
|
|
/// The run is pending a version update because it cannot execute without additional information (task, queue, etc.). Replaces WAITING_FOR_DEPLOY
|
|
PENDING_VERSION
|
|
|
|
/// Task hasn't been deployed yet but is waiting to be executed. Deprecated in favor of PENDING_VERSION
|
|
WAITING_FOR_DEPLOY
|
|
|
|
/// Task has been dequeued from the queue but is not yet executing
|
|
DEQUEUED
|
|
|
|
/// Task is currently being executed by a worker
|
|
EXECUTING
|
|
|
|
/// Task has been paused by the system, and will be resumed by the system
|
|
WAITING_TO_RESUME
|
|
|
|
/// Task has failed and is waiting to be retried
|
|
RETRYING_AFTER_FAILURE
|
|
|
|
/// Task has been paused by the user, and can be resumed by the user
|
|
PAUSED
|
|
|
|
///
|
|
/// FINAL STATUSES
|
|
///
|
|
|
|
/// Task has been canceled by the user
|
|
CANCELED
|
|
|
|
/// Task was interrupted during execution, mostly this happens in development environments
|
|
INTERRUPTED
|
|
|
|
/// Task has been completed successfully
|
|
COMPLETED_SUCCESSFULLY
|
|
|
|
/// Task has been completed with errors
|
|
COMPLETED_WITH_ERRORS
|
|
|
|
/// Task has failed to complete, due to an error in the system
|
|
SYSTEM_FAILURE
|
|
|
|
/// Task has crashed and won't be retried, most likely the worker ran out of resources, e.g. memory or storage
|
|
CRASHED
|
|
|
|
/// Task reached the ttl without being executed
|
|
EXPIRED
|
|
|
|
/// Task has been timed out when using maxDuration
|
|
TIMED_OUT
|
|
}
|
|
|
|
enum RunEngineVersion {
|
|
/// The original version that uses marqs v1 and Graphile
|
|
V1
|
|
V2
|
|
}
|
|
|
|
/// Used by the RunEngine during TaskRun execution
|
|
/// It has the required information to transactionally progress a run through states,
|
|
/// and prevent side effects like heartbeats failing a run that has progressed.
|
|
/// It is optimised for performance and is designed to be cleared at some point,
|
|
/// so there are no cascading relationships to other models.
|
|
model TaskRunExecutionSnapshot {
|
|
id String @id @default(cuid())
|
|
|
|
/// This should always be 2+ (V1 didn't use the run engine or snapshots)
|
|
engine RunEngineVersion @default(V2)
|
|
|
|
/// The execution status
|
|
executionStatus TaskRunExecutionStatus
|
|
/// For debugging
|
|
description String
|
|
|
|
/// We store invalid snapshots as a record of the run state when we tried to move
|
|
isValid Boolean @default(true)
|
|
error String?
|
|
|
|
/// The previous snapshot ID
|
|
previousSnapshotId String?
|
|
|
|
/// Run
|
|
runId String
|
|
run TaskRun @relation(fields: [runId], references: [id])
|
|
runStatus TaskRunStatus
|
|
|
|
// Batch
|
|
batchId String?
|
|
|
|
/// This is the current run attempt number. Users can define how many attempts they want for a run.
|
|
attemptNumber Int?
|
|
|
|
/// Environment
|
|
environmentId String
|
|
environmentType RuntimeEnvironmentType
|
|
projectId String
|
|
organizationId String
|
|
|
|
/// Waitpoints that have been completed for this execution
|
|
completedWaitpoints Waitpoint[] @relation("completedWaitpoints")
|
|
|
|
/// An array of waitpoint IDs in the correct order, used for batches
|
|
completedWaitpointOrder String[]
|
|
|
|
/// Checkpoint
|
|
checkpointId String?
|
|
checkpoint TaskRunCheckpoint? @relation(fields: [checkpointId], references: [id])
|
|
|
|
/// Worker
|
|
workerId String?
|
|
runnerId String?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
lastHeartbeatAt DateTime?
|
|
|
|
/// Metadata used by various systems in the run engine
|
|
metadata Json?
|
|
|
|
/// Used to get the latest valid snapshot quickly
|
|
@@index([runId, isValid, createdAt(sort: Desc)])
|
|
}
|
|
|
|
enum TaskRunExecutionStatus {
|
|
/// Run has been created
|
|
RUN_CREATED
|
|
/// Run is delayed, waiting to be enqueued
|
|
DELAYED
|
|
/// Run is in the RunQueue
|
|
QUEUED
|
|
/// Run is in the RunQueue, and is also executing. This happens when a run is continued cannot reacquire concurrency
|
|
QUEUED_EXECUTING
|
|
/// Run has been pulled from the queue, but isn't executing yet
|
|
PENDING_EXECUTING
|
|
/// Run is executing on a worker
|
|
EXECUTING
|
|
/// Run is executing on a worker but is waiting for waitpoints to complete
|
|
EXECUTING_WITH_WAITPOINTS
|
|
/// Run has been suspended and may be waiting for waitpoints to complete before resuming
|
|
SUSPENDED
|
|
/// Run has been scheduled for cancellation
|
|
PENDING_CANCEL
|
|
/// Run is finished (success of failure)
|
|
FINISHED
|
|
}
|
|
|
|
model TaskRunCheckpoint {
|
|
id String @id @default(cuid())
|
|
|
|
friendlyId String @unique
|
|
|
|
type TaskRunCheckpointType
|
|
location String
|
|
imageRef String?
|
|
reason String?
|
|
metadata String?
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
runtimeEnvironment RuntimeEnvironment @relation(fields: [runtimeEnvironmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
runtimeEnvironmentId String
|
|
|
|
executionSnapshot TaskRunExecutionSnapshot[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
enum TaskRunCheckpointType {
|
|
DOCKER
|
|
KUBERNETES
|
|
COMPUTE
|
|
}
|
|
|
|
/// A Waitpoint blocks a run from continuing until it's completed
|
|
/// If there's a waitpoint blocking a run, it shouldn't be in the queue
|
|
model Waitpoint {
|
|
id String @id @default(cuid())
|
|
|
|
friendlyId String @unique
|
|
|
|
type WaitpointType
|
|
status WaitpointStatus @default(PENDING)
|
|
|
|
completedAt DateTime?
|
|
|
|
/// If it's an Event type waitpoint, this is the event. It can also be provided for the DATETIME type
|
|
idempotencyKey String
|
|
/// If this is true then we can show it in the dashboard/return it from the SDK
|
|
userProvidedIdempotencyKey Boolean
|
|
|
|
/// If there's a user provided idempotency key, this is the time it expires at
|
|
idempotencyKeyExpiresAt DateTime?
|
|
|
|
/// If an idempotencyKey is no longer active, we store it here and generate a new one for the idempotencyKey field.
|
|
/// Clearing an idempotencyKey is useful for debounce or cancelling child runs.
|
|
/// This is a workaround because Prisma doesn't support partial indexes.
|
|
inactiveIdempotencyKey String?
|
|
|
|
/// If it's a RUN type waitpoint, this is the associated run
|
|
completedByTaskRunId String? @unique
|
|
completedByTaskRun TaskRun? @relation("CompletingRun", fields: [completedByTaskRunId], references: [id], onDelete: SetNull)
|
|
|
|
/// If it's a DATETIME type waitpoint, this is the date.
|
|
/// If it's a MANUAL waitpoint, this can be set as the `timeout`.
|
|
completedAfter DateTime?
|
|
|
|
/// If it's a BATCH type waitpoint, this is the associated batch
|
|
completedByBatchId String?
|
|
completedByBatch BatchTaskRun? @relation(fields: [completedByBatchId], references: [id], onDelete: SetNull)
|
|
|
|
/// The runs this waitpoint is blocking
|
|
blockingTaskRuns TaskRunWaitpoint[]
|
|
|
|
/// All runs that have ever been blocked by this waitpoint, used for display purposes
|
|
connectedRuns TaskRun[] @relation("WaitpointRunConnections")
|
|
|
|
/// When a waitpoint is complete
|
|
completedExecutionSnapshots TaskRunExecutionSnapshot[] @relation("completedWaitpoints")
|
|
|
|
/// When completed, an output can be stored here
|
|
output String?
|
|
outputType String @default("application/json")
|
|
outputIsError Boolean @default(false)
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
environmentId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
/// Denormized column that holds the raw tags
|
|
/// Denormalized column that holds the raw tags
|
|
tags String[]
|
|
|
|
/// Quickly find an idempotent waitpoint
|
|
@@unique([environmentId, idempotencyKey])
|
|
/// Quickly find a batch waitpoint
|
|
@@index([completedByBatchId])
|
|
/// Used on the Waitpoint dashboard pages
|
|
/// Time period filtering
|
|
@@index([environmentId, type, createdAt(sort: Desc)])
|
|
/// Status filtering
|
|
@@index([environmentId, type, status])
|
|
/// For the waitpoint token dashboard page
|
|
@@index([environmentId, type, id(sort: Desc)])
|
|
}
|
|
|
|
enum WaitpointType {
|
|
RUN
|
|
DATETIME
|
|
MANUAL
|
|
BATCH
|
|
}
|
|
|
|
enum WaitpointStatus {
|
|
PENDING
|
|
COMPLETED
|
|
}
|
|
|
|
model TaskRunWaitpoint {
|
|
id String @id @default(cuid())
|
|
|
|
taskRun TaskRun @relation(fields: [taskRunId], references: [id])
|
|
taskRunId String
|
|
|
|
waitpoint Waitpoint @relation(fields: [waitpointId], references: [id])
|
|
waitpointId String
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
/// This span id is completed when the waitpoint is completed. This is used with cached runs (idempotent)
|
|
spanIdToComplete String?
|
|
|
|
//associated batch
|
|
batchId String?
|
|
batch BatchTaskRun? @relation(fields: [batchId], references: [id])
|
|
//if there's an associated batch and this isn't set it's for the entire batch
|
|
//if it is set, it's a specific run in the batch
|
|
batchIndex Int?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
/// There are two constraints, the one below and also one that Prisma doesn't support
|
|
/// The second one implemented in SQL only prevents a TaskRun + Waitpoint with a null batchIndex
|
|
@@unique([taskRunId, waitpointId, batchIndex])
|
|
@@index([taskRunId])
|
|
@@index([waitpointId])
|
|
}
|
|
|
|
model WaitpointTag {
|
|
id String @id @default(cuid())
|
|
name String
|
|
|
|
environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
environmentId String
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@unique([environmentId, name])
|
|
}
|
|
|
|
model FeatureFlag {
|
|
id String @id @default(cuid())
|
|
|
|
key String @unique
|
|
value Json?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
model WorkerInstance {
|
|
id String @id @default(cuid())
|
|
|
|
/// For example "worker-1"
|
|
name String
|
|
|
|
/// If managed, it will default to the name, e.g. "worker-1"
|
|
/// If unmanged, it will be prefixed with the deployment ID e.g. "deploy-123-worker-1"
|
|
resourceIdentifier String
|
|
|
|
metadata Json?
|
|
|
|
workerGroup WorkerInstanceGroup @relation(fields: [workerGroupId], references: [id])
|
|
workerGroupId String
|
|
|
|
organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
organizationId String?
|
|
|
|
project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String?
|
|
|
|
environment RuntimeEnvironment? @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
environmentId String?
|
|
|
|
deployment WorkerDeployment? @relation(fields: [deploymentId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
deploymentId String?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
lastDequeueAt DateTime?
|
|
lastHeartbeatAt DateTime?
|
|
|
|
@@unique([workerGroupId, resourceIdentifier])
|
|
}
|
|
|
|
enum WorkerInstanceGroupType {
|
|
MANAGED
|
|
UNMANAGED
|
|
}
|
|
|
|
enum WorkloadType {
|
|
CONTAINER
|
|
MICROVM
|
|
}
|
|
|
|
model WorkerInstanceGroup {
|
|
id String @id @default(cuid())
|
|
type WorkerInstanceGroupType
|
|
|
|
/// For example "us-east-1"
|
|
name String
|
|
|
|
/// If managed, it will default to the name, e.g. "us-east-1"
|
|
/// If unmanged, it will be prefixed with the project ID e.g. "project_1-us-east-1"
|
|
masterQueue String @unique
|
|
|
|
/// "N. Virginia, USA", "Frankfurt, Germany", etc. Used for display purposes
|
|
description String?
|
|
hidden Boolean @default(false)
|
|
|
|
token WorkerGroupToken @relation(fields: [tokenId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
tokenId String @unique
|
|
|
|
workers WorkerInstance[]
|
|
backgroundWorkers BackgroundWorker[]
|
|
|
|
defaultForProjects Project[] @relation("ProjectDefaultWorkerGroup")
|
|
|
|
organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
organizationId String?
|
|
|
|
project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String?
|
|
|
|
cloudProvider String?
|
|
/// "usa", "europe", etc. Used like a pseudo enum for things like flags
|
|
location String?
|
|
staticIPs String?
|
|
|
|
workloadType WorkloadType @default(CONTAINER)
|
|
|
|
/// Geo region; container + MICROVM groups for one geo share it. Set-once once it has runs.
|
|
region String?
|
|
|
|
/// When true, runs enqueued to this worker queue may skip the intermediate queue
|
|
/// and be pushed directly to the worker queue when concurrency is available.
|
|
enableFastPath Boolean @default(false)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
model WorkerGroupToken {
|
|
id String @id @default(cuid())
|
|
|
|
tokenHash String @unique
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
workerGroup WorkerInstanceGroup?
|
|
}
|
|
|
|
model TaskRunTag {
|
|
id String @id @default(cuid())
|
|
name String
|
|
|
|
friendlyId String @unique
|
|
|
|
runs TaskRun[]
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@unique([projectId, name])
|
|
//Makes run filtering by tag faster
|
|
@@index([name, id])
|
|
}
|
|
|
|
/// This is used for triggerAndWait and batchTriggerAndWait. The taskRun is the child task, it points at a parent attempt or a batch
|
|
model TaskRunDependency {
|
|
id String @id @default(cuid())
|
|
|
|
/// The child run
|
|
taskRun TaskRun @relation(fields: [taskRunId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
taskRunId String @unique
|
|
|
|
checkpointEvent CheckpointRestoreEvent? @relation(fields: [checkpointEventId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
checkpointEventId String? @unique
|
|
|
|
/// An attempt that is dependent on this task run.
|
|
dependentAttempt TaskRunAttempt? @relation(fields: [dependentAttemptId], references: [id])
|
|
dependentAttemptId String?
|
|
|
|
/// A batch run that is dependent on this task run
|
|
dependentBatchRun BatchTaskRun? @relation("dependentBatchRun", fields: [dependentBatchRunId], references: [id])
|
|
dependentBatchRunId String?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
resumedAt DateTime?
|
|
|
|
@@index([dependentAttemptId])
|
|
@@index([dependentBatchRunId])
|
|
}
|
|
|
|
/// deprecated, we hadn't included the project id in the unique constraint
|
|
model TaskRunCounter {
|
|
taskIdentifier String @id
|
|
lastNumber Int @default(0)
|
|
}
|
|
|
|
/// Used for the TaskRun number (e.g. #1,421)
|
|
model TaskRunNumberCounter {
|
|
id String @id @default(cuid())
|
|
|
|
taskIdentifier String
|
|
environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
environmentId String
|
|
|
|
lastNumber Int @default(0)
|
|
|
|
@@unique([taskIdentifier, environmentId])
|
|
}
|
|
|
|
/// This is not used from engine v2+, attempts use the TaskRunExecutionSnapshot and TaskRun
|
|
model TaskRunAttempt {
|
|
id String @id @default(cuid())
|
|
number Int @default(0)
|
|
|
|
friendlyId String @unique
|
|
|
|
taskRun TaskRun @relation("attempts", fields: [taskRunId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
taskRunId String
|
|
|
|
backgroundWorker BackgroundWorker @relation(fields: [backgroundWorkerId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
backgroundWorkerId String
|
|
|
|
backgroundWorkerTask BackgroundWorkerTask @relation(fields: [backgroundWorkerTaskId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
backgroundWorkerTaskId String
|
|
|
|
runtimeEnvironment RuntimeEnvironment @relation(fields: [runtimeEnvironmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
runtimeEnvironmentId String
|
|
|
|
queue TaskQueue @relation(fields: [queueId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
queueId String
|
|
|
|
status TaskRunAttemptStatus @default(PENDING)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
startedAt DateTime?
|
|
completedAt DateTime?
|
|
|
|
usageDurationMs Int @default(0)
|
|
|
|
error Json?
|
|
output String?
|
|
outputType String @default("application/json")
|
|
|
|
dependencies TaskRunDependency[]
|
|
batchDependencies BatchTaskRun[]
|
|
|
|
checkpoints Checkpoint[]
|
|
batchTaskRunItems BatchTaskRunItem[]
|
|
CheckpointRestoreEvent CheckpointRestoreEvent[]
|
|
alerts ProjectAlert[]
|
|
childRuns TaskRun[] @relation("TaskParentRunAttempt")
|
|
|
|
@@unique([taskRunId, number])
|
|
@@index([taskRunId])
|
|
}
|
|
|
|
enum TaskRunAttemptStatus {
|
|
/// NON-FINAL
|
|
PENDING
|
|
EXECUTING
|
|
PAUSED
|
|
/// FINAL
|
|
FAILED
|
|
CANCELED
|
|
COMPLETED
|
|
}
|
|
|
|
/// This is the unified otel span/log model that will eventually be replaced by clickhouse
|
|
model TaskEvent {
|
|
id String @id @default(cuid())
|
|
|
|
/// This matches the span name for a trace event, or the log body for a log event
|
|
message String
|
|
|
|
traceId String
|
|
spanId String
|
|
parentId String?
|
|
tracestate String?
|
|
|
|
isError Boolean @default(false)
|
|
isPartial Boolean @default(false)
|
|
isCancelled Boolean @default(false)
|
|
/// deprecated: don't use this, moving this to properties, this now uses TaskEventKind.LOG
|
|
isDebug Boolean @default(false)
|
|
|
|
serviceName String
|
|
serviceNamespace String
|
|
|
|
level TaskEventLevel @default(TRACE)
|
|
kind TaskEventKind @default(INTERNAL)
|
|
status TaskEventStatus @default(UNSET)
|
|
|
|
links Json?
|
|
events Json?
|
|
|
|
/// This is the time the event started in nanoseconds since the epoch
|
|
startTime BigInt
|
|
|
|
/// This is the duration of the event in nanoseconds
|
|
duration BigInt @default(0)
|
|
|
|
attemptId String?
|
|
attemptNumber Int?
|
|
|
|
environmentId String
|
|
environmentType RuntimeEnvironmentType
|
|
|
|
organizationId String
|
|
|
|
projectId String
|
|
projectRef String
|
|
|
|
runId String
|
|
runIsTest Boolean @default(false)
|
|
|
|
idempotencyKey String?
|
|
|
|
taskSlug String
|
|
taskPath String?
|
|
taskExportName String?
|
|
|
|
workerId String?
|
|
workerVersion String?
|
|
|
|
queueId String?
|
|
queueName String?
|
|
|
|
batchId String?
|
|
|
|
/// This represents all the span attributes available, like http.status_code, and special attributes like $style.icon, $output, $metadata.payload.userId, as it's used for searching and filtering
|
|
properties Json
|
|
|
|
/// This represents all span attributes in the $metadata namespace, like $metadata.payload
|
|
metadata Json?
|
|
|
|
/// This represents all span attributes in the $style namespace, like $style
|
|
style Json?
|
|
|
|
/// This represents all span attributes in the $output namespace, like $output
|
|
output Json?
|
|
|
|
/// This represents the mimetype of the output, such as application/json or application/super+json
|
|
outputType String?
|
|
|
|
payload Json?
|
|
payloadType String?
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
// This represents the amount of "usage time" the event took, e.g. the CPU time
|
|
usageDurationMs Int @default(0)
|
|
usageCostInCents Float @default(0)
|
|
|
|
machinePreset String?
|
|
machinePresetCpu Float?
|
|
machinePresetMemory Float?
|
|
machinePresetCentsPerMs Float?
|
|
|
|
/// Used on the run page
|
|
@@index([traceId])
|
|
/// Used when looking up span events to complete when a run completes
|
|
@@index([spanId])
|
|
// Used for getting all logs for a run
|
|
@@index([runId])
|
|
}
|
|
|
|
enum TaskEventLevel {
|
|
TRACE
|
|
DEBUG
|
|
LOG
|
|
INFO
|
|
WARN
|
|
ERROR
|
|
}
|
|
|
|
enum TaskEventKind {
|
|
UNSPECIFIED
|
|
INTERNAL
|
|
SERVER
|
|
CLIENT
|
|
PRODUCER
|
|
CONSUMER
|
|
UNRECOGNIZED
|
|
LOG
|
|
}
|
|
|
|
enum TaskEventStatus {
|
|
UNSET
|
|
OK
|
|
ERROR
|
|
UNRECOGNIZED
|
|
}
|
|
|
|
model TaskQueue {
|
|
id String @id @default(cuid())
|
|
|
|
friendlyId String @unique
|
|
|
|
name String
|
|
type TaskQueueType @default(VIRTUAL)
|
|
|
|
version TaskQueueVersion @default(V1)
|
|
orderableName String?
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
runtimeEnvironment RuntimeEnvironment @relation(fields: [runtimeEnvironmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
runtimeEnvironmentId String
|
|
|
|
/// Represents the current concurrency limit for the queue
|
|
concurrencyLimit Int?
|
|
/// When the concurrency limit was overridden
|
|
concurrencyLimitOverriddenAt DateTime?
|
|
/// Who overrode the concurrency limit (will be null if overridden via the API)
|
|
concurrencyLimitOverriddenBy String?
|
|
/// If concurrencyLimit is overridden, this is the overridden value
|
|
concurrencyLimitBase Int?
|
|
rateLimit Json?
|
|
|
|
paused Boolean @default(false)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
attempts TaskRunAttempt[]
|
|
tasks BackgroundWorkerTask[]
|
|
workers BackgroundWorker[]
|
|
|
|
@@unique([runtimeEnvironmentId, name])
|
|
}
|
|
|
|
enum TaskQueueType {
|
|
VIRTUAL
|
|
NAMED
|
|
}
|
|
|
|
enum TaskQueueVersion {
|
|
V1
|
|
V2
|
|
}
|
|
|
|
model BatchTaskRun {
|
|
id String @id @default(cuid())
|
|
friendlyId String @unique
|
|
idempotencyKey String?
|
|
idempotencyKeyExpiresAt DateTime?
|
|
runtimeEnvironment RuntimeEnvironment @relation(fields: [runtimeEnvironmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
status BatchTaskRunStatus @default(PENDING)
|
|
runtimeEnvironmentId String
|
|
/// This only includes new runs, not idempotent runs.
|
|
runs TaskRun[]
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// new columns
|
|
/// Friendly IDs
|
|
runIds String[] @default([])
|
|
runCount Int @default(0)
|
|
payload String?
|
|
payloadType String @default("application/json")
|
|
options Json?
|
|
batchVersion String @default("v1")
|
|
|
|
//engine v2
|
|
/// Specific run blockers,
|
|
runsBlocked TaskRunWaitpoint[]
|
|
/// Waitpoints that are blocked by this batch.
|
|
/// When a Batch is created it blocks execution of the associated parent run (for andWait)
|
|
waitpoints Waitpoint[]
|
|
|
|
// This is for v3 batches
|
|
/// sealed is set to true once no more items can be added to the batch
|
|
sealed Boolean @default(false)
|
|
sealedAt DateTime?
|
|
/// this is the expected number of items in the batch
|
|
expectedCount Int @default(0)
|
|
/// this is the completed number of items in the batch. once this reaches expectedCount, and the batch is sealed, the batch is considered completed
|
|
completedCount Int @default(0)
|
|
completedAt DateTime?
|
|
resumedAt DateTime?
|
|
|
|
/// this is used to be able to "seal" this BatchTaskRun when all of the runs have been triggered asynchronously, and using the "parallel" processing strategy
|
|
processingJobsCount Int @default(0)
|
|
processingJobsExpectedCount Int @default(0)
|
|
|
|
/// optional token that can be used to authenticate the task run
|
|
oneTimeUseToken String?
|
|
|
|
// Run Engine v2 batch queue fields
|
|
/// When processing started (status changed to PROCESSING)
|
|
processingStartedAt DateTime?
|
|
/// When processing completed (all items processed)
|
|
processingCompletedAt DateTime?
|
|
/// Count of successfully created runs
|
|
successfulRunCount Int?
|
|
/// Count of failed run creations
|
|
failedRunCount Int?
|
|
/// Detailed failure records
|
|
errors BatchTaskRunError[]
|
|
|
|
///all the below properties are engine v1 only
|
|
items BatchTaskRunItem[]
|
|
taskIdentifier String?
|
|
checkpointEvent CheckpointRestoreEvent? @relation(fields: [checkpointEventId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
checkpointEventId String? @unique
|
|
dependentTaskAttempt TaskRunAttempt? @relation(fields: [dependentTaskAttemptId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
dependentTaskAttemptId String?
|
|
runDependencies TaskRunDependency[] @relation("dependentBatchRun")
|
|
|
|
@@unique([oneTimeUseToken])
|
|
///this is used for all engine versions
|
|
@@unique([runtimeEnvironmentId, idempotencyKey])
|
|
@@index([dependentTaskAttemptId])
|
|
// This is for the batch list dashboard page
|
|
@@index([runtimeEnvironmentId, id(sort: Desc)])
|
|
}
|
|
|
|
enum BatchTaskRunStatus {
|
|
PENDING
|
|
PROCESSING
|
|
COMPLETED
|
|
PARTIAL_FAILED
|
|
ABORTED
|
|
}
|
|
|
|
///Used in engine V1 only
|
|
model BatchTaskRunItem {
|
|
id String @id @default(cuid())
|
|
|
|
status BatchTaskRunItemStatus @default(PENDING)
|
|
|
|
batchTaskRun BatchTaskRun @relation(fields: [batchTaskRunId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
batchTaskRunId String
|
|
|
|
taskRun TaskRun @relation(fields: [taskRunId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
taskRunId String
|
|
|
|
taskRunAttempt TaskRunAttempt? @relation(fields: [taskRunAttemptId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
taskRunAttemptId String?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
completedAt DateTime?
|
|
|
|
@@unique([batchTaskRunId, taskRunId])
|
|
@@index([taskRunAttemptId], map: "idx_batchtaskrunitem_taskrunattempt")
|
|
@@index([taskRunId], map: "idx_batchtaskrunitem_taskrun")
|
|
}
|
|
|
|
enum BatchTaskRunItemStatus {
|
|
PENDING
|
|
FAILED
|
|
CANCELED
|
|
COMPLETED
|
|
}
|
|
|
|
/// Track individual run creation failures in batch processing (Run Engine v2)
|
|
model BatchTaskRunError {
|
|
id String @id @default(cuid())
|
|
batchTaskRun BatchTaskRun @relation(fields: [batchTaskRunId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
batchTaskRunId String
|
|
|
|
/// Which item in the batch (0-based index)
|
|
index Int
|
|
/// The task identifier that was being triggered
|
|
taskIdentifier String
|
|
/// The payload that failed (JSON, may be truncated)
|
|
payload String?
|
|
/// The options that were used
|
|
options Json?
|
|
/// Error message
|
|
error String
|
|
/// Error code if available
|
|
errorCode String?
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@unique([batchTaskRunId, index])
|
|
@@index([batchTaskRunId])
|
|
}
|
|
|
|
model EnvironmentVariable {
|
|
id String @id @default(cuid())
|
|
friendlyId String @unique
|
|
key String
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
values EnvironmentVariableValue[]
|
|
|
|
@@unique([projectId, key])
|
|
}
|
|
|
|
model EnvironmentVariableValue {
|
|
id String @id @default(cuid())
|
|
valueReference SecretReference? @relation(fields: [valueReferenceId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
valueReferenceId String?
|
|
variable EnvironmentVariable @relation(fields: [variableId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
variableId String
|
|
environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
environmentId String
|
|
|
|
/// If true, the value is secret and cannot be revealed
|
|
isSecret Boolean @default(false)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
version Int @default(1)
|
|
lastUpdatedBy Json?
|
|
|
|
@@unique([variableId, environmentId])
|
|
@@index([environmentId])
|
|
}
|
|
|
|
model Checkpoint {
|
|
id String @id @default(cuid())
|
|
|
|
friendlyId String @unique
|
|
|
|
type CheckpointType
|
|
location String
|
|
imageRef String
|
|
reason String?
|
|
metadata String?
|
|
|
|
events CheckpointRestoreEvent[]
|
|
|
|
run TaskRun @relation(fields: [runId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
runId String
|
|
|
|
attempt TaskRunAttempt @relation(fields: [attemptId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
attemptId String
|
|
attemptNumber Int?
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
runtimeEnvironment RuntimeEnvironment @relation(fields: [runtimeEnvironmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
runtimeEnvironmentId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([attemptId])
|
|
@@index([runId])
|
|
}
|
|
|
|
enum CheckpointType {
|
|
DOCKER
|
|
KUBERNETES
|
|
}
|
|
|
|
model CheckpointRestoreEvent {
|
|
id String @id @default(cuid())
|
|
|
|
type CheckpointRestoreEventType
|
|
reason String?
|
|
metadata String?
|
|
|
|
checkpoint Checkpoint @relation(fields: [checkpointId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
checkpointId String
|
|
|
|
run TaskRun @relation(fields: [runId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
runId String
|
|
|
|
attempt TaskRunAttempt @relation(fields: [attemptId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
attemptId String
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
runtimeEnvironment RuntimeEnvironment @relation(fields: [runtimeEnvironmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
runtimeEnvironmentId String
|
|
|
|
taskRunDependency TaskRunDependency?
|
|
batchTaskRunDependency BatchTaskRun?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([checkpointId])
|
|
@@index([runId])
|
|
}
|
|
|
|
enum CheckpointRestoreEventType {
|
|
CHECKPOINT
|
|
RESTORE
|
|
}
|
|
|
|
enum WorkerDeploymentType {
|
|
MANAGED
|
|
UNMANAGED
|
|
V1
|
|
}
|
|
|
|
model WorkerDeployment {
|
|
id String @id @default(cuid())
|
|
|
|
contentHash String
|
|
friendlyId String @unique
|
|
shortCode String
|
|
version String
|
|
|
|
runtime String?
|
|
runtimeVersion String?
|
|
|
|
imageReference String?
|
|
imagePlatform String @default("linux/amd64")
|
|
|
|
externalBuildData Json?
|
|
buildServerMetadata Json?
|
|
|
|
status WorkerDeploymentStatus @default(PENDING)
|
|
type WorkerDeploymentType @default(V1)
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
environmentId String
|
|
|
|
worker BackgroundWorker? @relation(fields: [workerId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
workerId String? @unique
|
|
|
|
triggeredBy User? @relation(fields: [triggeredById], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
triggeredById String?
|
|
triggeredVia String?
|
|
commitSHA String?
|
|
|
|
startedAt DateTime?
|
|
installedAt DateTime?
|
|
builtAt DateTime?
|
|
deployedAt DateTime?
|
|
|
|
failedAt DateTime?
|
|
errorData Json?
|
|
|
|
canceledAt DateTime?
|
|
canceledReason String?
|
|
|
|
// This is GitMeta type
|
|
git Json?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
promotions WorkerDeploymentPromotion[]
|
|
alerts ProjectAlert[]
|
|
workerInstance WorkerInstance[]
|
|
integrationDeployments IntegrationDeployment[]
|
|
|
|
@@unique([projectId, shortCode])
|
|
@@unique([environmentId, version])
|
|
@@index([commitSHA])
|
|
}
|
|
|
|
enum WorkerDeploymentStatus {
|
|
PENDING
|
|
INSTALLING
|
|
/// This is the status when the image is being built
|
|
BUILDING
|
|
/// This is the status when the image is built and we are waiting for the indexing to finish
|
|
DEPLOYING
|
|
/// This is the status when the image is built and indexed, meaning we have everything we need to deploy
|
|
DEPLOYED
|
|
FAILED
|
|
CANCELED
|
|
/// This is the status when the image is built and indexing does not finish in time
|
|
TIMED_OUT
|
|
}
|
|
|
|
model WorkerDeploymentPromotion {
|
|
id String @id @default(cuid())
|
|
|
|
/// This is the promotion label, e.g. "current"
|
|
label String
|
|
|
|
deployment WorkerDeployment @relation(fields: [deploymentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
deploymentId String
|
|
|
|
environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
environmentId String
|
|
|
|
// Only one promotion per environment can be active at a time
|
|
@@unique([environmentId, label])
|
|
}
|
|
|
|
///Schedules can be attached to tasks to trigger them on a schedule
|
|
model TaskSchedule {
|
|
id String @id @default(cuid())
|
|
|
|
type ScheduleType @default(IMPERATIVE)
|
|
|
|
///users see this as `id`. They start with schedule_
|
|
friendlyId String @unique
|
|
///a reference to a task (not a foreign key because it's across versions)
|
|
taskIdentifier String
|
|
|
|
///can be provided and we won't create another with the same key
|
|
deduplicationKey String @default(cuid())
|
|
userProvidedDeduplicationKey Boolean @default(false)
|
|
|
|
///the CRON pattern
|
|
generatorExpression String
|
|
generatorDescription String @default("")
|
|
generatorType ScheduleGeneratorType @default(CRON)
|
|
|
|
/// These are IANA format string, or the default "UTC". E.g. "America/New_York"
|
|
timezone String @default("UTC")
|
|
|
|
///Can be provided by the user then accessed inside a run
|
|
externalId String?
|
|
|
|
///Instances of the schedule that are active
|
|
instances TaskScheduleInstance[]
|
|
|
|
/// @deprecated stop writing 2026-04-30; reads moved out of code (UI now derives from cron's previous slot). Drop in follow-up.
|
|
lastRunTriggeredAt DateTime?
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
active Boolean @default(true)
|
|
|
|
@@unique([projectId, deduplicationKey])
|
|
/// Dashboard list view
|
|
@@index([projectId])
|
|
@@index([projectId, createdAt(sort: Desc)])
|
|
}
|
|
|
|
enum ScheduleType {
|
|
/// defined on your task using the `cron` property
|
|
DECLARATIVE
|
|
/// explicit calls to the SDK are used to create, or using the dashboard
|
|
IMPERATIVE
|
|
}
|
|
|
|
enum ScheduleGeneratorType {
|
|
CRON
|
|
}
|
|
|
|
///An instance links a schedule with an environment
|
|
model TaskScheduleInstance {
|
|
id String @id @default(cuid())
|
|
|
|
taskSchedule TaskSchedule @relation(fields: [taskScheduleId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
taskScheduleId String
|
|
|
|
environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
environmentId String
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
active Boolean @default(true)
|
|
|
|
/// @deprecated stop writing 2026-04-30; engine derives from cron + exactScheduleTime. Drop in follow-up.
|
|
lastScheduledTimestamp DateTime?
|
|
/// @deprecated stop writing 2026-04-30; engine derives from cron + now(). Drop in follow-up.
|
|
nextScheduledTimestamp DateTime?
|
|
|
|
//you can only have a schedule attached to each environment once
|
|
@@unique([taskScheduleId, environmentId])
|
|
@@index([environmentId])
|
|
@@index([projectId, active])
|
|
}
|
|
|
|
model RuntimeEnvironmentSession {
|
|
id String @id @default(cuid())
|
|
|
|
ipAddress String
|
|
|
|
environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
environmentId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
disconnectedAt DateTime?
|
|
|
|
currentEnvironments RuntimeEnvironment[] @relation("currentSession")
|
|
}
|
|
|
|
model ProjectAlertChannel {
|
|
id String @id @default(cuid())
|
|
|
|
friendlyId String @unique
|
|
|
|
///can be provided and we won't create another with the same key
|
|
deduplicationKey String @default(cuid())
|
|
userProvidedDeduplicationKey Boolean @default(false)
|
|
|
|
integration OrganizationIntegration? @relation(fields: [integrationId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
integrationId String?
|
|
|
|
enabled Boolean @default(true)
|
|
|
|
type ProjectAlertChannelType
|
|
name String
|
|
properties Json
|
|
alertTypes ProjectAlertType[]
|
|
environmentTypes RuntimeEnvironmentType[] @default([STAGING, PRODUCTION])
|
|
|
|
errorAlertConfig Json?
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
alerts ProjectAlert[]
|
|
alertStorages ProjectAlertStorage[]
|
|
|
|
@@unique([projectId, deduplicationKey])
|
|
}
|
|
|
|
enum ProjectAlertChannelType {
|
|
EMAIL
|
|
SLACK
|
|
WEBHOOK
|
|
}
|
|
|
|
model ProjectAlert {
|
|
id String @id @default(cuid())
|
|
friendlyId String @unique
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
environmentId String
|
|
|
|
channel ProjectAlertChannel @relation(fields: [channelId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
channelId String
|
|
|
|
status ProjectAlertStatus @default(PENDING)
|
|
|
|
type ProjectAlertType
|
|
|
|
taskRunAttempt TaskRunAttempt? @relation(fields: [taskRunAttemptId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
taskRunAttemptId String?
|
|
|
|
taskRun TaskRun? @relation(fields: [taskRunId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
taskRunId String?
|
|
|
|
workerDeployment WorkerDeployment? @relation(fields: [workerDeploymentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
workerDeploymentId String?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
enum ProjectAlertType {
|
|
TASK_RUN
|
|
/// deprecated, we don't send new alerts for this type
|
|
TASK_RUN_ATTEMPT
|
|
DEPLOYMENT_FAILURE
|
|
DEPLOYMENT_SUCCESS
|
|
ERROR_GROUP
|
|
}
|
|
|
|
enum ProjectAlertStatus {
|
|
PENDING
|
|
SENT
|
|
FAILED
|
|
}
|
|
|
|
model ProjectAlertStorage {
|
|
id String @id @default(cuid())
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
alertChannel ProjectAlertChannel @relation(fields: [alertChannelId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
alertChannelId String
|
|
|
|
alertType ProjectAlertType
|
|
|
|
storageId String
|
|
storageData Json
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([alertChannelId, alertType, storageId])
|
|
}
|
|
|
|
model OrganizationIntegration {
|
|
id String @id @default(cuid())
|
|
|
|
friendlyId String @unique
|
|
|
|
service IntegrationService
|
|
externalOrganizationId String? /// Identifier for external, integration's organization (e.g. Vercel's team)
|
|
|
|
integrationData Json
|
|
|
|
tokenReference SecretReference @relation(fields: [tokenReferenceId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
tokenReferenceId String
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
organizationId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
alertChannels ProjectAlertChannel[]
|
|
organizationProjectIntegration OrganizationProjectIntegration[]
|
|
|
|
@@index([externalOrganizationId])
|
|
}
|
|
|
|
model OrganizationProjectIntegration {
|
|
id String @id @default(cuid())
|
|
|
|
organizationIntegration OrganizationIntegration @relation(fields: [organizationIntegrationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
organizationIntegrationId String
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
externalEntityId String /// Identifier for webhooks, for example Vercel's projectId
|
|
integrationData Json /// Save useful data like config or external entity name
|
|
installedBy String? /// UserId who installed the integration
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
@@index([projectId])
|
|
@@index([projectId, organizationIntegrationId])
|
|
@@index([externalEntityId])
|
|
}
|
|
|
|
enum IntegrationService {
|
|
SLACK
|
|
VERCEL
|
|
}
|
|
|
|
/// Bulk actions, like canceling and replaying runs
|
|
model BulkActionGroup {
|
|
id String @id @default(cuid())
|
|
|
|
friendlyId String @unique
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
/// If this is set then it's a V2 Bulk Action that supports queries
|
|
environment RuntimeEnvironment? @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
environmentId String?
|
|
|
|
type BulkActionType
|
|
items BulkActionItem[]
|
|
|
|
/// When the group is created it's pending. After we've processed all the items it's completed. This does not mean the associated runs are completed.
|
|
status BulkActionStatus @default(PENDING)
|
|
|
|
/// The query that will be executed to get the runs to process (if null, we are passing run ids directly)
|
|
queryName String?
|
|
/// The params that will be passed to the query
|
|
params Json?
|
|
/// Billing-limit dedupe key (grace hitAt or resolve job key). Null for dashboard bulk actions.
|
|
dedupeKey String?
|
|
/// The cursor that will be passed to the query (null for the first page)
|
|
cursor Json?
|
|
/// The number of runs that have been processed successfully
|
|
successCount Int @default(0)
|
|
/// The number of runs that have been failed
|
|
failureCount Int @default(0)
|
|
/// The total number of runs that will be processed
|
|
totalCount Int @default(0)
|
|
|
|
completionNotification BulkActionNotificationType @default(NONE)
|
|
|
|
/// The userId who did the bulk action
|
|
user User? @relation(fields: [userId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
userId String?
|
|
|
|
/// The name of the bulk action
|
|
name String?
|
|
|
|
/// The time the bulk action was completed
|
|
completedAt DateTime?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([environmentId, createdAt(sort: Desc)])
|
|
// NOTE: the real index is PARTIAL (`WHERE "dedupeKey" IS NOT NULL`) and created
|
|
// CONCURRENTLY — see migration 20260626120001_bulk_action_group_dedupe_key_index.
|
|
// Prisma can't express partial indexes, so this @@index is an approximation (as with
|
|
// the INCLUDE/fillfactor indexes elsewhere in this schema). `migrate dev` will report
|
|
// drift here; do NOT accept its drop/recreate — keep the hand-written migration.
|
|
@@index([environmentId, type, dedupeKey])
|
|
}
|
|
|
|
enum BulkActionType {
|
|
/// Cancels existing runs. This populates the destination runs.
|
|
CANCEL
|
|
/// Replays existing runs. The original runs go as source runs, and the new runs go as destination runs.
|
|
REPLAY
|
|
}
|
|
|
|
enum BulkActionStatus {
|
|
PENDING
|
|
COMPLETED
|
|
ABORTED
|
|
}
|
|
|
|
enum BulkActionNotificationType {
|
|
NONE
|
|
EMAIL
|
|
}
|
|
|
|
model BulkActionItem {
|
|
id String @id @default(cuid())
|
|
|
|
/// @deprecated not used in new BulkActions
|
|
friendlyId String?
|
|
|
|
group BulkActionGroup @relation(fields: [groupId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
groupId String
|
|
|
|
type BulkActionType
|
|
|
|
/// When the item is created it's pending. After we've processed the item it's completed. This does not mean the associated runs are completed.
|
|
status BulkActionItemStatus @default(PENDING)
|
|
|
|
/// The run that is the source of the action, e.g. when replaying this is the original run
|
|
sourceRun TaskRun @relation("SourceActionItemRun", fields: [sourceRunId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
sourceRunId String
|
|
|
|
/// The run that's a result of the action, this will be set when the run has been created
|
|
destinationRun TaskRun? @relation("DestinationActionItemRun", fields: [destinationRunId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
destinationRunId String?
|
|
|
|
error String?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
enum BulkActionItemStatus {
|
|
PENDING
|
|
COMPLETED
|
|
FAILED
|
|
}
|
|
|
|
model RealtimeStreamChunk {
|
|
id String @id @default(cuid())
|
|
|
|
key String
|
|
value String
|
|
|
|
sequence Int
|
|
|
|
runId String
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([runId])
|
|
@@index([createdAt])
|
|
}
|
|
|
|
/// This is the unified otel span/log model that will eventually be replaced by clickhouse
|
|
model TaskEventPartitioned {
|
|
id String @default(cuid())
|
|
/// This matches the span name for a trace event, or the log body for a log event
|
|
message String
|
|
|
|
traceId String
|
|
spanId String
|
|
parentId String?
|
|
tracestate String?
|
|
|
|
isError Boolean @default(false)
|
|
isPartial Boolean @default(false)
|
|
isCancelled Boolean @default(false)
|
|
|
|
serviceName String
|
|
serviceNamespace String
|
|
|
|
level TaskEventLevel @default(TRACE)
|
|
kind TaskEventKind @default(INTERNAL)
|
|
status TaskEventStatus @default(UNSET)
|
|
|
|
links Json?
|
|
events Json?
|
|
|
|
/// This is the time the event started in nanoseconds since the epoch
|
|
startTime BigInt
|
|
|
|
/// This is the duration of the event in nanoseconds
|
|
duration BigInt @default(0)
|
|
|
|
attemptId String?
|
|
attemptNumber Int?
|
|
|
|
environmentId String
|
|
environmentType RuntimeEnvironmentType
|
|
|
|
organizationId String
|
|
|
|
projectId String
|
|
projectRef String
|
|
|
|
runId String
|
|
runIsTest Boolean @default(false)
|
|
|
|
idempotencyKey String?
|
|
|
|
taskSlug String
|
|
taskPath String?
|
|
taskExportName String?
|
|
|
|
workerId String?
|
|
workerVersion String?
|
|
|
|
queueId String?
|
|
queueName String?
|
|
|
|
batchId String?
|
|
|
|
/// This represents all the span attributes available, like http.status_code, and special attributes like $style.icon, $output, $metadata.payload.userId, as it's used for searching and filtering
|
|
properties Json
|
|
|
|
/// This represents all span attributes in the $metadata namespace, like $metadata.payload
|
|
metadata Json?
|
|
|
|
/// This represents all span attributes in the $style namespace, like $style
|
|
style Json?
|
|
|
|
/// This represents all span attributes in the $output namespace, like $output
|
|
output Json?
|
|
|
|
/// This represents the mimetype of the output, such as application/json or application/super+json
|
|
outputType String?
|
|
|
|
payload Json?
|
|
payloadType String?
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
// This represents the amount of "usage time" the event took, e.g. the CPU time
|
|
usageDurationMs Int @default(0)
|
|
usageCostInCents Float @default(0)
|
|
|
|
machinePreset String?
|
|
machinePresetCpu Float?
|
|
machinePresetMemory Float?
|
|
machinePresetCentsPerMs Float?
|
|
|
|
@@id([id, createdAt])
|
|
/// Used on the run page
|
|
@@index([traceId])
|
|
/// Used when looking up span events to complete when a run completes
|
|
@@index([spanId])
|
|
// Used for getting all logs for a run
|
|
@@index([runId])
|
|
}
|
|
|
|
enum GithubRepositorySelection {
|
|
ALL
|
|
SELECTED
|
|
}
|
|
|
|
model GithubAppInstallation {
|
|
id String @id @default(cuid())
|
|
|
|
appInstallationId BigInt @unique
|
|
targetId BigInt
|
|
targetType String
|
|
accountHandle String
|
|
permissions Json?
|
|
repositorySelection GithubRepositorySelection
|
|
installedBy String?
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id])
|
|
organizationId String
|
|
|
|
repositories GithubRepository[]
|
|
|
|
deletedAt DateTime?
|
|
suspendedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([organizationId])
|
|
}
|
|
|
|
model GithubRepository {
|
|
id String @id @default(cuid())
|
|
|
|
githubId BigInt
|
|
name String
|
|
fullName String
|
|
htmlUrl String
|
|
private Boolean
|
|
defaultBranch String
|
|
|
|
installation GithubAppInstallation @relation(fields: [installationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
installationId String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
ConnectedGithubRepository ConnectedGithubRepository[]
|
|
|
|
@@unique([installationId, githubId])
|
|
@@index([installationId])
|
|
}
|
|
|
|
model ConnectedGithubRepository {
|
|
id String @id @default(cuid())
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
repository GithubRepository @relation(fields: [repositoryId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
repositoryId String
|
|
|
|
// Branch configuration by environment slug, stored as JSON
|
|
// Example: {
|
|
// "prod": { "branch": "main" },
|
|
// "staging": { "branch": "staging" },
|
|
// }
|
|
// We could alternatively store tracking branch configurations in a separate table and reference the runtime environments properly.
|
|
// We don't need that functionality currently so it's simpler to store it here.
|
|
// Should we need to introduce such functionality in the future, e.g., supporting custom environments, the migration should be straightforward.
|
|
branchTracking Json
|
|
|
|
previewDeploymentsEnabled Boolean @default(true)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// A project can only be connected to one repository
|
|
@@unique([projectId])
|
|
@@index([repositoryId])
|
|
}
|
|
|
|
enum ImpersonationAuditLogAction {
|
|
START
|
|
STOP
|
|
}
|
|
|
|
model ImpersonationAuditLog {
|
|
id String @id @default(cuid())
|
|
|
|
action ImpersonationAuditLogAction
|
|
|
|
/// The admin user who initiated/ended the impersonation
|
|
admin User @relation("ImpersonationAdmin", fields: [adminId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
adminId String
|
|
|
|
/// The user being impersonated
|
|
target User @relation("ImpersonationTarget", fields: [targetId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
targetId String
|
|
|
|
ipAddress String?
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([adminId])
|
|
@@index([targetId])
|
|
@@index([createdAt])
|
|
}
|
|
|
|
enum CustomerQuerySource {
|
|
DASHBOARD
|
|
API
|
|
}
|
|
|
|
enum CustomerQueryScope {
|
|
ORGANIZATION
|
|
PROJECT
|
|
ENVIRONMENT
|
|
}
|
|
|
|
model CustomerQuery {
|
|
id String @id @default(cuid())
|
|
|
|
/// The TSQL query text that was executed
|
|
query String
|
|
|
|
/// The scope of the query (determines which tenant IDs were used)
|
|
scope CustomerQueryScope
|
|
|
|
/// Query execution statistics from ClickHouse
|
|
stats Json
|
|
|
|
/// AI-generated title summarizing the query
|
|
title String?
|
|
|
|
/// Where the query originated from
|
|
source CustomerQuerySource @default(DASHBOARD)
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
organizationId String
|
|
|
|
project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String?
|
|
|
|
environment RuntimeEnvironment? @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
environmentId String?
|
|
|
|
/// Optional user who executed the query (null for API calls)
|
|
user User? @relation(fields: [userId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
userId String?
|
|
|
|
/// Time filter settings used when the query was executed
|
|
/// Period like "7d", "24h", etc.
|
|
filterPeriod String?
|
|
/// Custom start date (ISO 8601)
|
|
filterFrom DateTime?
|
|
/// Custom end date (ISO 8601)
|
|
filterTo DateTime?
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
/// Fast lookup for history menu (most recent 20 per org)
|
|
@@index([organizationId, createdAt(sort: Desc)])
|
|
/// For Stripe metering job - find unprocessed queries
|
|
@@index([createdAt])
|
|
}
|
|
|
|
model IntegrationDeployment {
|
|
id String @id @default(cuid())
|
|
|
|
integrationName String /// For example Vercel
|
|
integrationDeploymentId String /// External ID
|
|
commitSHA String
|
|
deploymentId String?
|
|
status String? /// External deployment status
|
|
|
|
workerDeployment WorkerDeployment? @relation(fields: [deploymentId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([commitSHA])
|
|
@@index([deploymentId])
|
|
}
|
|
|
|
/// A user-defined metrics dashboard
|
|
model MetricsDashboard {
|
|
id String @id @default(cuid())
|
|
|
|
friendlyId String @unique
|
|
|
|
title String
|
|
description String @default("")
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
organizationId String
|
|
|
|
project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String?
|
|
|
|
/// Who created the dashboard
|
|
owner User? @relation(fields: [ownerId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
ownerId String?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
/// JSON that defines the config, queries, layout and config of all widgets.
|
|
/// There will be a version field for the format.
|
|
layout String
|
|
|
|
/// Fast lookup for the list
|
|
@@index([projectId, createdAt(sort: Desc)])
|
|
}
|
|
|
|
// ====================================================
|
|
// LLM Pricing Models
|
|
// ====================================================
|
|
|
|
/// A known LLM model or model pattern for cost tracking
|
|
model LlmModel {
|
|
id String @id @default(cuid())
|
|
friendlyId String @unique @map("friendly_id")
|
|
projectId String? @map("project_id")
|
|
project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
modelName String @map("model_name")
|
|
matchPattern String @map("match_pattern")
|
|
startDate DateTime? @map("start_date")
|
|
source String @default("default") // "default", "admin", "project"
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Catalog metadata for model registry
|
|
provider String? @map("provider")
|
|
description String? @map("description")
|
|
contextWindow Int? @map("context_window")
|
|
maxOutputTokens Int? @map("max_output_tokens")
|
|
capabilities String[] @default([]) @map("capabilities")
|
|
isHidden Boolean @default(false) @map("is_hidden")
|
|
baseModelName String? @map("base_model_name")
|
|
// "tokens", "images", "characters", "minutes", "requests", "free", "not_findable"; null until researched
|
|
pricingUnit String? @map("pricing_unit")
|
|
|
|
pricingTiers LlmPricingTier[]
|
|
prices LlmPrice[]
|
|
|
|
@@unique([projectId, modelName, startDate])
|
|
@@index([projectId])
|
|
@@map("llm_models")
|
|
}
|
|
|
|
/// A pricing tier for a model (supports volume-based or conditional pricing)
|
|
model LlmPricingTier {
|
|
id String @id @default(cuid())
|
|
modelId String @map("model_id")
|
|
model LlmModel @relation(fields: [modelId], references: [id], onDelete: Cascade)
|
|
name String
|
|
isDefault Boolean @default(true) @map("is_default")
|
|
priority Int @default(0)
|
|
conditions Json @default("[]") @db.JsonB
|
|
|
|
prices LlmPrice[]
|
|
|
|
@@unique([modelId, priority])
|
|
@@unique([modelId, name])
|
|
@@map("llm_pricing_tiers")
|
|
}
|
|
|
|
/// A price point for a usage type within a pricing tier
|
|
model LlmPrice {
|
|
id String @id @default(cuid())
|
|
modelId String @map("model_id")
|
|
model LlmModel @relation(fields: [modelId], references: [id], onDelete: Cascade)
|
|
pricingTierId String @map("pricing_tier_id")
|
|
pricingTier LlmPricingTier @relation(fields: [pricingTierId], references: [id], onDelete: Cascade)
|
|
usageType String @map("usage_type")
|
|
price Decimal @db.Decimal(20, 12)
|
|
|
|
@@unique([modelId, usageType, pricingTierId])
|
|
@@map("llm_prices")
|
|
}
|
|
|
|
enum PlatformNotificationSurface {
|
|
WEBAPP
|
|
CLI
|
|
}
|
|
|
|
enum PlatformNotificationScope {
|
|
USER
|
|
PROJECT
|
|
ORGANIZATION
|
|
GLOBAL
|
|
}
|
|
|
|
/// Admin-created notification definitions
|
|
model PlatformNotification {
|
|
id String @id @default(cuid())
|
|
|
|
friendlyId String @unique @default(cuid())
|
|
|
|
/// Admin-facing title for identification in admin tools
|
|
title String
|
|
|
|
/// Versioned JSON rendering content (see payload schema in spec)
|
|
payload Json
|
|
|
|
surface PlatformNotificationSurface
|
|
scope PlatformNotificationScope
|
|
|
|
/// Set when scope = USER
|
|
user User? @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
userId String?
|
|
|
|
/// Set when scope = ORGANIZATION
|
|
organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
organizationId String?
|
|
|
|
/// Set when scope = PROJECT
|
|
project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String?
|
|
|
|
/// When notification becomes active
|
|
startsAt DateTime
|
|
|
|
/// When notification expires
|
|
endsAt DateTime
|
|
|
|
/// CLI: auto-expire N days after user first saw it
|
|
cliMaxDaysAfterFirstSeen Int?
|
|
|
|
/// CLI: auto-expire after shown N times to user
|
|
cliMaxShowCount Int?
|
|
|
|
/// CLI: only show every N-th request (e.g. cliShowEvery=3 means show on 3rd, 6th, 9th…)
|
|
cliShowEvery Int?
|
|
|
|
/// Ordering within same scope level (higher = more important)
|
|
priority Int @default(0)
|
|
|
|
/// Soft delete
|
|
archivedAt DateTime?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
interactions PlatformNotificationInteraction[]
|
|
|
|
@@index([surface, scope, startsAt])
|
|
}
|
|
|
|
/// Per-user tracking of notification views and dismissals
|
|
model PlatformNotificationInteraction {
|
|
id String @id @default(cuid())
|
|
|
|
notification PlatformNotification @relation(fields: [notificationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
notificationId String
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
userId String
|
|
|
|
/// Set by beacon/CLI GET on first impression
|
|
firstSeenAt DateTime @default(now())
|
|
|
|
/// Times shown (incremented per beacon/CLI view)
|
|
showCount Int @default(1)
|
|
|
|
/// User dismissed in webapp
|
|
webappDismissedAt DateTime?
|
|
|
|
/// User clicked a link in webapp
|
|
webappClickedAt DateTime?
|
|
|
|
/// Auto-dismissed or expired in CLI
|
|
cliDismissedAt DateTime?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([notificationId, userId])
|
|
}
|
|
|
|
enum ErrorGroupStatus {
|
|
UNRESOLVED
|
|
RESOLVED
|
|
IGNORED
|
|
}
|
|
|
|
/**
|
|
* Error group state is used to track when a user has interacted with an error (ignored/resolved)
|
|
* The actual error data is in ClickHouse.
|
|
*/
|
|
model ErrorGroupState {
|
|
id String @id @default(cuid())
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
organizationId String
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
/**
|
|
* You can ignore/resolve an error across all environments, or specific ones
|
|
*/
|
|
environment RuntimeEnvironment? @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
environmentId String?
|
|
|
|
taskIdentifier String
|
|
errorFingerprint String
|
|
|
|
status ErrorGroupStatus @default(UNRESOLVED)
|
|
|
|
/**
|
|
* Error is ignored until this date
|
|
*/
|
|
ignoredUntil DateTime?
|
|
/**
|
|
* Error is ignored until this occurrence rate
|
|
*/
|
|
ignoredUntilOccurrenceRate Int?
|
|
/**
|
|
* Error is ignored until this total occurrences
|
|
*/
|
|
ignoredUntilTotalOccurrences Int?
|
|
|
|
/// Total occurrence count at the time the error was ignored (from ClickHouse).
|
|
/// Used with ignoredUntilTotalOccurrences to compute occurrences since ignoring.
|
|
ignoredAtOccurrenceCount BigInt?
|
|
|
|
/**
|
|
* Error was ignored at this date
|
|
*/
|
|
ignoredAt DateTime?
|
|
/**
|
|
* Reason for ignoring the error
|
|
*/
|
|
ignoredReason String?
|
|
/**
|
|
* User who ignored the error
|
|
*/
|
|
ignoredByUserId String?
|
|
|
|
/**
|
|
* Error was resolved at this date
|
|
*/
|
|
resolvedAt DateTime?
|
|
/**
|
|
* Error was resolved in this version
|
|
*/
|
|
resolvedInVersion String?
|
|
/**
|
|
* User who resolved the error
|
|
*/
|
|
resolvedBy String?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([environmentId, taskIdentifier, errorFingerprint])
|
|
@@index([environmentId, status])
|
|
}
|
|
|
|
model TaskIdentifier {
|
|
id String @id @default(cuid())
|
|
|
|
runtimeEnvironment RuntimeEnvironment @relation(fields: [runtimeEnvironmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
runtimeEnvironmentId String
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
projectId String
|
|
|
|
slug String
|
|
|
|
currentTriggerSource TaskTriggerSource @default(STANDARD)
|
|
|
|
currentWorker BackgroundWorker? @relation(fields: [currentWorkerId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
currentWorkerId String?
|
|
|
|
firstSeenAt DateTime @default(now())
|
|
lastSeenAt DateTime @default(now())
|
|
isInLatestDeployment Boolean @default(true)
|
|
|
|
@@unique([runtimeEnvironmentId, slug])
|
|
@@index([runtimeEnvironmentId, isInLatestDeployment])
|
|
}
|
|
|
|
enum DataStoreKind {
|
|
CLICKHOUSE
|
|
}
|
|
|
|
/// Defines org-scoped data store overrides (e.g. dedicated ClickHouse for HIPAA orgs).
|
|
/// Multiple organizations can share a single data store row via organizationIds.
|
|
model OrganizationDataStore {
|
|
id String @id @default(cuid())
|
|
/// Human-readable unique key (e.g. "hipaa-clickhouse-us-east")
|
|
key String @unique
|
|
/// Organization IDs that use this data store
|
|
organizationIds String[]
|
|
kind DataStoreKind
|
|
/// Versioned config JSON. Structure is discriminated by the top-level `version` field.
|
|
config Json
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([kind])
|
|
}
|