generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

// ── Users ──

model User {
  id           String   @id @default(cuid())
  email        String   @unique
  name         String?
  passwordHash String
  role         Role     @default(USER)
  provider     String?
  externalId   String?
  version      Int      @default(1)
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt

  sessions           Session[]
  auditLogs          AuditLog[]
  ownedProjects      Project[]
  groupMemberships   GroupMember[]

  @@index([email])
}

enum Role {
  USER
  ADMIN
}

// ── Sessions ──

model Session {
  id        String   @id @default(cuid())
  token     String   @unique
  userId    String
  expiresAt DateTime
  createdAt DateTime @default(now())

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([token])
  @@index([userId])
  @@index([expiresAt])
}

// ── MCP Servers ──

model McpServer {
  id            String          @id @default(cuid())
  name          String          @unique
  description   String          @default("")
  packageName   String?
  runtime       String?
  dockerImage   String?
  transport     Transport       @default(STDIO)
  repositoryUrl String?
  externalUrl   String?
  command       Json?
  containerPort Int?
  replicas      Int             @default(1)
  env           Json            @default("[]")
  healthCheck   Json?
  version       Int             @default(1)
  createdAt     DateTime        @default(now())
  updatedAt     DateTime        @updatedAt

  templateName    String?
  templateVersion String?

  instances McpInstance[]
  projects  ProjectServer[]

  @@index([name])
}

enum Transport {
  STDIO
  SSE
  STREAMABLE_HTTP
}

// ── MCP Templates ──

model McpTemplate {
  id            String    @id @default(cuid())
  name          String    @unique
  version       String    @default("1.0.0")
  description   String    @default("")
  packageName   String?
  runtime       String?
  dockerImage   String?
  transport     Transport @default(STDIO)
  repositoryUrl String?
  externalUrl   String?
  command       Json?
  containerPort Int?
  replicas      Int       @default(1)
  env           Json      @default("[]")
  healthCheck   Json?
  createdAt     DateTime  @default(now())
  updatedAt     DateTime  @updatedAt

  @@index([name])
}

// ── Secrets ──

model Secret {
  id        String   @id @default(cuid())
  name      String   @unique
  data      Json     @default("{}")
  version   Int      @default(1)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([name])
}

// ── Groups ──

model Group {
  id          String   @id @default(cuid())
  name        String   @unique
  description String   @default("")
  version     Int      @default(1)
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  members GroupMember[]

  @@index([name])
}

model GroupMember {
  id        String   @id @default(cuid())
  groupId   String
  userId    String
  createdAt DateTime @default(now())

  group Group @relation(fields: [groupId], references: [id], onDelete: Cascade)
  user  User  @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([groupId, userId])
  @@index([groupId])
  @@index([userId])
}

// ── RBAC Definitions ──

model RbacDefinition {
  id           String   @id @default(cuid())
  name         String   @unique
  subjects     Json     @default("[]")
  roleBindings Json     @default("[]")
  version      Int      @default(1)
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt

  @@index([name])
}

// ── Projects ──

model Project {
  id          String   @id @default(cuid())
  name        String   @unique
  description String   @default("")
  prompt      String   @default("")
  proxyModel  String   @default("")
  gated       Boolean  @default(true)
  llmProvider     String?
  llmModel        String?
  serverOverrides Json?
  ownerId         String
  version     Int      @default(1)
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  owner          User            @relation(fields: [ownerId], references: [id], onDelete: Cascade)
  servers        ProjectServer[]
  prompts        Prompt[]
  promptRequests PromptRequest[]

  @@index([name])
  @@index([ownerId])
}

model ProjectServer {
  id        String   @id @default(cuid())
  projectId String
  serverId  String
  createdAt DateTime @default(now())

  project Project   @relation(fields: [projectId], references: [id], onDelete: Cascade)
  server  McpServer @relation(fields: [serverId], references: [id], onDelete: Cascade)

  @@unique([projectId, serverId])
}

// ── MCP Instances (running containers) ──

model McpInstance {
  id          String         @id @default(cuid())
  serverId    String
  containerId String?
  status      InstanceStatus @default(STOPPED)
  port        Int?
  metadata        Json           @default("{}")
  healthStatus    String?
  lastHealthCheck DateTime?
  events          Json           @default("[]")
  version         Int            @default(1)
  createdAt       DateTime       @default(now())
  updatedAt       DateTime       @updatedAt

  server McpServer @relation(fields: [serverId], references: [id], onDelete: Cascade)

  @@index([serverId])
  @@index([status])
}

enum InstanceStatus {
  STARTING
  RUNNING
  STOPPING
  STOPPED
  ERROR
}

// ── Prompts (approved content resources) ──

model Prompt {
  id         String   @id @default(cuid())
  name       String
  content    String   @db.Text
  projectId  String?
  priority   Int      @default(5)
  summary    String?  @db.Text
  chapters   Json?
  linkTarget String?
  version    Int      @default(1)
  createdAt  DateTime @default(now())
  updatedAt  DateTime @updatedAt

  project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade)

  @@unique([name, projectId])
  @@index([projectId])
}

// ── Prompt Requests (pending proposals from LLM sessions) ──

model PromptRequest {
  id               String   @id @default(cuid())
  name             String
  content          String   @db.Text
  projectId        String?
  priority         Int      @default(5)
  createdBySession String?
  createdByUserId  String?
  createdAt        DateTime @default(now())

  project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade)

  @@unique([name, projectId])
  @@index([projectId])
  @@index([createdBySession])
}

// ── Audit Events (pipeline/gate/tool trace from mcplocal) ──

model AuditEvent {
  id             String   @id @default(cuid())
  timestamp      DateTime
  sessionId      String
  projectName    String
  eventKind      String
  source         String
  verified       Boolean  @default(false)
  serverName     String?
  correlationId  String?
  parentEventId  String?
  userName       String?
  payload        Json
  createdAt      DateTime @default(now())

  @@index([sessionId])
  @@index([projectName])
  @@index([correlationId])
  @@index([timestamp])
  @@index([eventKind])
  @@index([userName])
}

// ── Backup Pending Queue ──

model BackupPending {
  id           String   @id @default(cuid())
  resourceKind String
  resourceName String
  action       String   // 'create' | 'update' | 'delete'
  userName     String
  yamlContent  String?  @db.Text
  createdAt    DateTime @default(now())

  @@index([createdAt])
}

// ── Audit Logs ──

model AuditLog {
  id        String   @id @default(cuid())
  userId    String
  action    String
  resource  String
  resourceId String?
  details   Json     @default("{}")
  createdAt DateTime @default(now())

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId])
  @@index([action])
  @@index([resource])
  @@index([createdAt])
}
