generator client { provider = "prisma-client-js" binaryTargets = ["native", "debian-openssl-3.0.x", "linux-musl-openssl-3.0.x"] } datasource db { provider = "postgresql" url = env("DATABASE_URL") } enum PreviewStatus { PROVISIONING BUILDING RUNNING FAILED STOPPED IGNORED } enum JobType { DEPLOY STOP INACTIVITY_STOP } enum JobStatus { PENDING RUNNING DONE FAILED } model User { id Int @id @default(autoincrement()) username String @unique @db.VarChar(128) passwordHash String @db.VarChar(256) isAdmin Boolean @default(false) isFounder Boolean @default(false) setupSkipped Boolean @default(false) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt giteaUsername String? @db.VarChar(128) giteaPAT String? @db.Text giteaInstanceUrl String? @db.VarChar(512) awsAccessKeyId String? @db.VarChar(256) awsSecretAccessKey String? @db.Text awsRegion String? @db.VarChar(64) sessions Session[] repoConfigs RepoConfig[] webhookToken WebhookToken? noConfigComments NoConfigComment[] } model Session { id Int @id @default(autoincrement()) hash String @db.VarChar(512) userId Int user User @relation(fields: [userId], references: [id], onDelete: Cascade) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model RepoConfig { id Int @id @default(autoincrement()) userId Int user User @relation(fields: [userId], references: [id], onDelete: Cascade) repoOwner String @db.VarChar(128) repoName String @db.VarChar(128) isEnabled Boolean @default(false) giteaWebhookId String? @db.VarChar(128) denyList String[] // Names of `/pp` commands the operator has switched off for this repo // (e.g. ["stop", "ignore"]). `help` is always available. See routes/webhook.ts. disabledCommands String[] instanceType String @default("t3.medium") @db.VarChar(64) inactivityHours Float @default(12) port Int @default(3000) envVars Json @default("{}") preinstallTools String[] @default([]) nodeVersion String? @db.VarChar(64) useDockerCompose Boolean @default(false) composeFilePath String? @db.VarChar(512) aptPackages String[] setupCommands String[] buildCommands String[] postBuildCommands String[] runCommand String? @db.Text createdAt DateTime @default(now()) updatedAt DateTime @updatedAt previews Preview[] @@unique([repoOwner, repoName]) } model Preview { id Int @id @default(autoincrement()) repoConfigId Int repoConfig RepoConfig @relation(fields: [repoConfigId], references: [id], onDelete: Cascade) prNumber Int prTitle String @db.VarChar(512) commitSha String @db.VarChar(64) instanceId String? @db.VarChar(64) instanceIp String? @db.VarChar(64) port Int @default(3000) // Cost tracking. `instanceType` snapshots the type of the currently- (or // last-) launched instance so pricing is accurate even if the RepoConfig // changes later. `instanceLaunchedAt` marks when the live EC2 started billing // (nulled on stop). `accumulatedCostUsd` holds the finalized cost of all // previously-terminated instance sessions for this preview; the live session's // cost is added on top at read time. See lib/cost.ts. instanceType String? @db.VarChar(64) instanceLaunchedAt DateTime? accumulatedCostUsd Float @default(0) status PreviewStatus @default(PROVISIONING) stopReason String? @db.VarChar(128) logs String @default("") @db.Text pid Int? sshPrivateKey String? @db.Text sshKeyName String? @db.VarChar(128) giteaCommentId Int? lastActivityAt DateTime @default(now()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt stoppedAt DateTime? jobs Job[] } model Job { id Int @id @default(autoincrement()) previewId Int? preview Preview? @relation(fields: [previewId], references: [id], onDelete: Cascade) type JobType status JobStatus @default(PENDING) payload Json @default("{}") error String? @db.Text createdAt DateTime @default(now()) startedAt DateTime? finishedAt DateTime? } model WebhookToken { id Int @id @default(autoincrement()) userId Int @unique user User @relation(fields: [userId], references: [id], onDelete: Cascade) token String @db.VarChar(256) createdAt DateTime @default(now()) } model NoConfigComment { id Int @id @default(autoincrement()) userId Int user User @relation(fields: [userId], references: [id], onDelete: Cascade) repoOwner String @db.VarChar(128) repoName String @db.VarChar(128) prNumber Int createdAt DateTime @default(now()) @@unique([userId, repoOwner, repoName, prNumber]) } model AdminSettings { id Int @id @default(1) defaultInstanceType String @default("t3.medium") @db.VarChar(64) maxConcurrentInstancesPerUser Int @default(5) logSizeLimitBytes Int @default(1048576) previewRetentionDays Int @default(30) webhookRateLimitPerMinute Int @default(10) contactEmail String @default("") @db.VarChar(256) }