datasource db { provider = "postgresql" url = env("RUN_OPS_DATABASE_URL") } generator client { provider = "prisma-client-js" output = "../generated/run-ops" binaryTargets = ["native", "debian-openssl-1.1.x"] previewFeatures = ["metrics"] } // ───────────────────────────────────────────────────────────────────────────── // Dedicated run-ops database schema. // // This schema holds the subset of the control-plane `@trigger.dev/database` // models that describe a run's lifecycle. Each model reproduces its // control-plane counterpart column-for-column; the only differences are in how // relations are handled, according to three rules: // // 1. Relations that point at control-plane-owned models (organization, // project, environment, background worker, queue, and the like) are not // reproduced. Their foreign-key columns are kept as plain scalars, with no // `@relation` and no database foreign key, because the referenced rows live // in the control-plane database. // // 2. Waitpoint block and completion relations are foreign-key-free. A block or // completion edge can connect a run and a waitpoint that live in different // databases, so it must never be enforced by a foreign key here. These // relations are represented by scalar columns plus the explicit join models // `TaskRunWaitpoint`, `WaitpointRunConnection`, and `CompletedWaitpoint`. // The join models replace implicit many-to-many relations that exist in the // control-plane schema. // // 3. Relations that stay entirely within this database (run to root/parent // run, run to attempt, run to batch, checkpoints, dependencies, and so on) // are kept as real foreign keys, exactly as in the control plane. // // Relation-only back-references to models outside this subset are dropped; the // per-model notes below call out where that happens. // ───────────────────────────────────────────────────────────────────────────── enum RuntimeEnvironmentType { PRODUCTION STAGING DEVELOPMENT PREVIEW } /// Same columns and indexes as the control-plane `TaskRun`. The environment, /// project, `lockedBy`, and `lockedToVersion` relations are scalar-only foreign /// keys here. The waitpoint completion/block relations /// (`associatedWaitpoint`, `blockedByWaitpoints`, `connectedWaitpoints`) are /// foreign-key-free: completion lives on `Waitpoint.completedByTaskRunId`, block /// edges are rows of `TaskRunWaitpoint`, and connections are rows of /// `WaitpointRunConnection`. The root/parent-run, parent-attempt, and batch /// relations are kept as real foreign keys. Control-plane back-references to /// tags, alerts, bulk-action items, and playground conversations are dropped. 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 /// scalar FK (control-plane `runtimeEnvironment` relation) runtimeEnvironmentId String environmentType RuntimeEnvironmentType? /// scalar FK (control-plane `project` relation) 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") /// 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? /// scalar FK (control-plane `lockedBy` relation) lockedById String? /// scalar FK (control-plane `lockedToVersion` relation) 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? // The control-plane waitpoint relations (associatedWaitpoint, blockedByWaitpoints, // connectedWaitpoints) are foreign-key-free here: completion is stored on // Waitpoint.completedByTaskRunId, block edges are rows of TaskRunWaitpoint, and // connections are rows of WaitpointRunConnection. /// Where the logs are stored taskEventStore String @default("taskEvent") queueTimestamp DateTime? batchItems BatchTaskRunItem[] dependency TaskRunDependency? CheckpointRestoreEvent CheckpointRestoreEvent[] executionSnapshots TaskRunExecutionSnapshot[] scheduleInstanceId String? scheduleId String? bulkActionGroupIds String[] @default([]) logsDeletedAt DateTime? replayedFromTaskRunFriendlyId String? /// This represents the original task 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? @@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) } 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. /// /// Same columns and indexes as the control-plane version. The `run` and /// `checkpoint` relations are kept as real foreign keys. The `completedWaitpoints` /// relation is foreign-key-free: it is represented by rows of the `CompletedWaitpoint` /// join model instead. 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 // The control-plane `completedWaitpoints` relation (waitpoints completed for this // execution) is foreign-key-free here, stored as rows of CompletedWaitpoint. /// 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 } /// Same columns as the control-plane version, with the project and environment /// relations kept as scalar-only foreign keys. model TaskRunCheckpoint { id String @id @default(cuid()) friendlyId String @unique type TaskRunCheckpointType location String imageRef String? reason String? metadata String? /// scalar FK (control-plane `project` relation) projectId String /// scalar FK (control-plane `runtimeEnvironment` relation) 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 /// /// Same columns and indexes as the control-plane version. Every relation is /// foreign-key-free, because a waitpoint and the run or batch it references may /// live in different databases: `completedByTaskRunId` and `completedByBatchId` /// are scalar-only, and the `blockingTaskRuns`, `connectedRuns`, and /// `completedExecutionSnapshots` back-references are represented by the /// `TaskRunWaitpoint`, `WaitpointRunConnection`, and `CompletedWaitpoint` join /// models. The project and environment relations are scalar-only foreign keys. 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. /// scalar FK (control-plane `completedByTaskRun` relation) completedByTaskRunId String? @unique /// 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. /// scalar FK (control-plane `completedByBatch` relation) completedByBatchId String? /// When completed, an output can be stored here output String? outputType String @default("application/json") outputIsError Boolean @default(false) /// scalar FK (control-plane `project` relation) projectId String /// scalar FK (control-plane `environment` relation) 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 } /// The block edge between a run and a waitpoint. Same columns and indexes as the /// control-plane version, but the run, waitpoint, project, and batch relations /// are all scalar-only foreign keys: a block edge can connect a run and a /// waitpoint that live in different databases, so it is never enforced by a /// foreign key here. model TaskRunWaitpoint { id String @id @default(cuid()) /// scalar FK (control-plane `taskRun` relation) taskRunId String /// scalar FK (control-plane `waitpoint` relation) waitpointId String /// scalar FK (control-plane `project` relation) projectId String /// This span id is completed when the waitpoint is completed. This is used with cached runs (idempotent) spanIdToComplete String? /// scalar FK (control-plane `batch` relation) batchId String? //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]) } /// Explicit join model for the connection between a run and every waitpoint that /// blocked it (kept for display). This has no control-plane counterpart table: it /// replaces the implicit many-to-many relation between `TaskRun.connectedWaitpoints` /// and `Waitpoint.connectedRuns`. Scalar columns only, no foreign keys, so a /// connection can span both databases. model WaitpointRunConnection { id String @id @default(cuid()) taskRunId String waitpointId String @@unique([taskRunId, waitpointId]) @@index([taskRunId]) @@index([waitpointId]) } /// Explicit join model recording which waitpoints an execution snapshot completed. /// This has no control-plane counterpart table: it replaces the implicit /// many-to-many relation between `TaskRunExecutionSnapshot.completedWaitpoints` /// and `Waitpoint`. Scalar columns only, no foreign keys, so a snapshot may record /// a waitpoint that lives in the other database. model CompletedWaitpoint { id String @id @default(cuid()) snapshotId String waitpointId String @@unique([snapshotId, waitpointId]) @@index([snapshotId]) @@index([waitpointId]) } /// Same columns and indexes as the control-plane version, with the environment /// and project relations kept as scalar-only foreign keys. model WaitpointTag { id String @id @default(cuid()) name String /// scalar FK (control-plane `environment` relation) environmentId String /// scalar FK (control-plane `project` relation) projectId String createdAt DateTime @default(now()) @@unique([environmentId, name]) } /// Same columns and indexes as the control-plane version, with the project /// relation kept as a scalar-only foreign key. The control-plane `runs` back- /// reference (the tag-to-run many-to-many) is dropped. model TaskRunTag { id String @id @default(cuid()) name String friendlyId String @unique /// scalar FK (control-plane `project` relation) 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 /// /// Identical to the control-plane version: every relation stays within this /// database and is kept as a real foreign key. 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]) } /// Same columns and indexes as the control-plane version. The owning-run relation /// is kept as a real foreign key. The background-worker, background-worker-task, /// environment, and queue relations are scalar-only foreign keys. The control- /// plane `alerts` back-reference is dropped. model TaskRunAttempt { id String @id @default(cuid()) number Int @default(0) friendlyId String @unique /// The owning run taskRun TaskRun @relation("attempts", fields: [taskRunId], references: [id], onDelete: Cascade, onUpdate: Cascade) taskRunId String /// scalar FK (control-plane `backgroundWorker` relation) backgroundWorkerId String /// scalar FK (control-plane `backgroundWorkerTask` relation) backgroundWorkerTaskId String /// scalar FK (control-plane `runtimeEnvironment` relation) runtimeEnvironmentId String /// scalar FK (control-plane `queue` relation) 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[] childRuns TaskRun[] @relation("TaskParentRunAttempt") @@unique([taskRunId, number]) @@index([taskRunId]) } enum TaskRunAttemptStatus { /// NON-FINAL PENDING EXECUTING PAUSED /// FINAL FAILED CANCELED COMPLETED } /// Same columns and indexes as the control-plane version. The environment /// relation is a scalar-only foreign key. The `runsBlocked` and `waitpoints` /// back-references are foreign-key-free: block edges are rows of /// `TaskRunWaitpoint`, and batch-completed waitpoints are found via /// `Waitpoint.completedByBatchId`. The `runs`, `errors`, `items`, /// `checkpointEvent`, `dependentTaskAttempt`, and `runDependencies` relations /// stay within this database and are kept as real foreign keys. model BatchTaskRun { id String @id @default(cuid()) friendlyId String @unique idempotencyKey String? idempotencyKeyExpiresAt DateTime? status BatchTaskRunStatus @default(PENDING) /// scalar FK (control-plane `runtimeEnvironment` relation) 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 // The control-plane `runsBlocked` and `waitpoints` back-references are foreign- // key-free here: block edges are rows of TaskRunWaitpoint keyed by batchId, and // batch-completed waitpoints are found via Waitpoint.completedByBatchId. // 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 /// /// Identical to the control-plane version: every relation stays within this /// database and is kept as a real foreign key. 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) /// /// Identical to the control-plane version: the batch relation stays within this /// database and is kept as a real foreign key. 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]) } /// Same columns and indexes as the control-plane version. The run and attempt /// relations are kept as real foreign keys; the project and environment relations /// are scalar-only foreign keys. 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? /// scalar FK (control-plane `project` relation) projectId String /// scalar FK (control-plane `runtimeEnvironment` relation) runtimeEnvironmentId String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([attemptId]) @@index([runId]) } enum CheckpointType { DOCKER KUBERNETES } /// Same columns and indexes as the control-plane version. The checkpoint, run, /// and attempt relations are kept as real foreign keys; the project and /// environment relations are scalar-only foreign keys. 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 /// scalar FK (control-plane `project` relation) projectId String /// scalar FK (control-plane `runtimeEnvironment` relation) runtimeEnvironmentId String taskRunDependency TaskRunDependency? batchTaskRunDependency BatchTaskRun? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([checkpointId]) @@index([runId]) } enum CheckpointRestoreEventType { CHECKPOINT RESTORE }