// Prisma schema for RayLab Core - Phase 1 // PostgreSQL datasource. DATABASE_URL must be set in environment. generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model User { id String @id @default(uuid()) @db.Uuid authentikId String? @unique authentikUserId String? @unique authentikSubject String? @unique username String? @unique @db.VarChar(255) email String? @unique @db.VarChar(320) name String? @db.VarChar(255) picture String? isActive Boolean @default(true) deletedAt DateTime? lastSeenAt DateTime? lastSyncedAt DateTime? syncStatus String? storageQuota BigInt? @default(10737418240) storageUsed BigInt? @default(0) metadata Json? roles UserRole[] permissions UserPermission[] auditLogs AuditLog[] mediaObjects MediaObject[] lastGroupHash String? @db.Text createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([authentikId]) @@index([username]) @@index([email]) } model Role { id String @id @default(uuid()) @db.Uuid code String @unique @db.VarChar(100) name String @db.VarChar(255) displayName String? @db.VarChar(255) description String? isDefault Boolean @default(false) permissions RolePermission[] userRoles UserRole[] mappings AuthGroupRoleMapping[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Permission { id String @id @default(uuid()) @db.Uuid code String @unique @db.VarChar(150) name String @db.VarChar(255) displayName String? @db.VarChar(255) description String? rolePermissions RolePermission[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt UserPermission UserPermission[] } model RolePermission { id String @id @default(uuid()) @db.Uuid role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) roleId String @db.Uuid permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade) permissionId String @db.Uuid createdAt DateTime @default(now()) @@unique([roleId, permissionId]) @@index([roleId]) @@index([permissionId]) } model UserPermission { id String @id @default(uuid()) @db.Uuid user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId String @db.Uuid permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade) permissionId String @db.Uuid assignedBy String? @db.VarChar(100) createdAt DateTime @default(now()) @@unique([userId, permissionId]) @@index([userId]) @@index([permissionId]) } enum UserRoleSource { AUTHENTIK SYSTEM } model UserRole { id String @id @default(uuid()) @db.Uuid user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId String @db.Uuid role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) roleId String @db.Uuid source UserRoleSource @default(AUTHENTIK) syncedAt DateTime @default(now()) createdAt DateTime @default(now()) @@unique([userId, roleId]) @@index([userId]) @@index([roleId]) } model AuthGroupRoleMapping { id String @id @default(uuid()) @db.Uuid authGroup String @db.VarChar(255) role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) roleId String @db.Uuid createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([authGroup]) } model AuditLog { id String @id @default(uuid()) @db.Uuid user User? @relation(fields: [userId], references: [id], onDelete: SetNull) userId String? @db.Uuid action String @db.VarChar(200) resource String? @db.VarChar(200) resourceId String? details Json? createdAt DateTime @default(now()) @@index([userId]) @@index([action]) } model ScheduledJob { id String @id @default(uuid()) @db.Uuid name String @db.VarChar(255) payload Json? cron String? runAt DateTime? status String @default("pending") @db.VarChar(50) attempts Int @default(0) lastRunAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([name]) @@index([status]) } model MediaObject { id String @id @default(uuid()) @db.Uuid ownerUserId String? @db.Uuid owner User? @relation(fields: [ownerUserId], references: [id], onDelete: SetNull) storageKey String @db.VarChar(1024) filename String? @db.VarChar(1024) mimeType String? @db.VarChar(255) size BigInt? isPublic Boolean @default(false) metadata Json? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([ownerUserId]) @@index([storageKey]) } model Application { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid @map("id") code String @unique @db.VarChar(100) @map("code") name String @db.VarChar(255) @map("name") description String? @db.Text @map("description") icon String? @db.Text @map("icon") url String? @db.Text @map("url") applicationsClaim String @unique @db.VarChar(255) @map("applicationsClaim") isActive Boolean @default(true) @map("isActive") displayOrder Int @default(0) @db.Integer @map("displayOrder") createdAt DateTime @default(dbgenerated("now()")) @db.Timestamptz @map("createdAt") updatedAt DateTime @default(dbgenerated("now()")) @db.Timestamptz @map("updatedAt") @@index([code], name: "Application_code_idx") @@index([applicationsClaim], name: "Application_applicationsClaim_idx") @@map("Application") }