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? 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? 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("") proxyMode String @default("direct") llmProvider String? llmModel String? ownerId String version Int @default(1) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade) servers ProjectServer[] @@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 } // ── 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]) }