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)
  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)
}
