generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } enum RoleScope { SYSTEM ROOM } enum FriendStatus { PENDING ACCEPTED DECLINED BLOCKED } enum RoomVisibility { PUBLIC FRIENDS ROLE_RESTRICTED EXPLICIT } enum MediaProvider { YOUTUBE TWITCH DIRECT UNKNOWN } enum InviteStatus { ACTIVE REVOKED USED EXPIRED } model User { id String @id @default(cuid()) username String @unique passwordHash String displayName String? avatarUrl String? disabledAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt roles UserRole[] ownedRooms Room[] @relation("RoomOwner") sentFriends Friendship[] @relation("FriendRequester") gotFriends Friendship[] @relation("FriendReceiver") roomMembers RoomMember[] submitted MediaSource[] messages RoomMessage[] auditEvents AuditEvent[] invites Invite[] } model AppSetting { key String @id value String updatedAt DateTime @updatedAt } model Role { id String @id @default(cuid()) name String @unique description String? scope RoleScope @default(SYSTEM) createdAt DateTime @default(now()) users UserRole[] permissions RolePermission[] } model Permission { id String @id @default(cuid()) key String @unique description String? roles RolePermission[] } model UserRole { userId String roleId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) @@id([userId, roleId]) } model RolePermission { roleId String permissionId String role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade) @@id([roleId, permissionId]) } model Friendship { id String @id @default(cuid()) requesterId String receiverId String status FriendStatus @default(PENDING) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt requester User @relation("FriendRequester", fields: [requesterId], references: [id], onDelete: Cascade) receiver User @relation("FriendReceiver", fields: [receiverId], references: [id], onDelete: Cascade) @@unique([requesterId, receiverId]) } model Room { id String @id @default(cuid()) slug String @unique name String ownerId String? isPersonal Boolean @default(false) visibility RoomVisibility @default(FRIENDS) currentState Json? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt owner User? @relation("RoomOwner", fields: [ownerId], references: [id], onDelete: SetNull) members RoomMember[] mediaSources MediaSource[] messages RoomMessage[] auditEvents AuditEvent[] invites Invite[] } model RoomMember { roomId String userId String canManage Boolean @default(false) room Room @relation(fields: [roomId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@id([roomId, userId]) } model MediaSource { id String @id @default(cuid()) roomId String submitterId String? provider MediaProvider originalUrl String playbackUrl String thumbnailUrl String? title String? queuePosition Int @default(0) createdAt DateTime @default(now()) room Room @relation(fields: [roomId], references: [id], onDelete: Cascade) submitter User? @relation(fields: [submitterId], references: [id], onDelete: SetNull) } model RoomMessage { id String @id @default(cuid()) roomId String userId String? body String createdAt DateTime @default(now()) room Room @relation(fields: [roomId], references: [id], onDelete: Cascade) user User? @relation(fields: [userId], references: [id], onDelete: SetNull) @@index([roomId, createdAt]) } model AuditEvent { id String @id @default(cuid()) actorId String? roomId String? action String metadata Json? createdAt DateTime @default(now()) actor User? @relation(fields: [actorId], references: [id], onDelete: SetNull) room Room? @relation(fields: [roomId], references: [id], onDelete: SetNull) @@index([roomId, createdAt]) @@index([actorId, createdAt]) } model Invite { id String @id @default(cuid()) code String @unique roomId String? creatorId String? status InviteStatus @default(ACTIVE) expiresAt DateTime? usedById String? usedAt DateTime? createdAt DateTime @default(now()) room Room? @relation(fields: [roomId], references: [id], onDelete: Cascade) creator User? @relation(fields: [creatorId], references: [id], onDelete: SetNull) @@index([roomId, status]) }