schema.prisma 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // This is your Prisma schema file,
  2. // learn more about it in the docs: https://pris.ly/d/prisma-schema
  3. generator client {
  4. provider = "prisma-client-js"
  5. }
  6. datasource db {
  7. provider = "postgresql"
  8. url = env("DATABASE_URL")
  9. }
  10. model User {
  11. id String @id @default(cuid())
  12. email String @unique
  13. name String
  14. password String
  15. avatarUrl String?
  16. globalRole GlobalRole @default(MEMBER)
  17. active Boolean @default(true)
  18. storageQuota Int @default(524288000) // 500 MB in bytes
  19. storageUsed Int @default(0) // bytes consumed
  20. createdAt DateTime @default(now())
  21. updatedAt DateTime @updatedAt
  22. memberships ProjectMember[] @relation("ProjectMembers")
  23. comments Comment[]
  24. projects Project[] @relation("ProjectOwner")
  25. resolvedComments Comment[] @relation("ResolvedBy")
  26. requestedComments Comment[] @relation("RequestedBy")
  27. assets Asset[]
  28. }
  29. model Project {
  30. id String @id @default(cuid())
  31. name String
  32. description String?
  33. ownerId String
  34. createdAt DateTime @default(now())
  35. updatedAt DateTime @updatedAt
  36. assets Asset[]
  37. members ProjectMember[] @relation("ProjectMembers")
  38. invitations Invitation[]
  39. owner User @relation("ProjectOwner", fields: [ownerId], references: [id])
  40. }
  41. model SiteSetting {
  42. id String @id @default(cuid())
  43. name String @unique
  44. value String
  45. }
  46. model ProjectMember {
  47. id String @id @default(cuid())
  48. userId String
  49. projectId String
  50. role Role @default(REVIEWER)
  51. joinedAt DateTime @default(now())
  52. invitedBy String? // userId who sent the invite
  53. user User @relation("ProjectMembers", fields: [userId], references: [id], onDelete: Cascade)
  54. project Project @relation("ProjectMembers", fields: [projectId], references: [id], onDelete: Cascade)
  55. @@unique([userId, projectId])
  56. @@index([projectId])
  57. @@index([userId])
  58. }
  59. model Asset {
  60. id String @id @default(cuid())
  61. projectId String
  62. uploaderId String? // null for legacy assets before this feature
  63. title String
  64. filename String
  65. filePath String
  66. thumbnail String?
  67. hlsPath String?
  68. duration Float?
  69. fps Float @default(30)
  70. codec String?
  71. mimeType String
  72. fileSize Int @default(0) // raw video file size in bytes
  73. status AssetStatus @default(PENDING_REVIEW)
  74. transcodeStatus TranscodeStatus @default(PENDING)
  75. transcodeProgress Int @default(0)
  76. transcodeError String?
  77. createdAt DateTime @default(now())
  78. updatedAt DateTime @updatedAt
  79. project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
  80. uploader User? @relation(fields: [uploaderId], references: [id], onDelete: SetNull)
  81. comments Comment[]
  82. }
  83. model Comment {
  84. id String @id @default(cuid())
  85. assetId String
  86. userId String
  87. content String
  88. timestamp Float?
  89. annotations Json?
  90. resolved Boolean @default(false)
  91. resolveStatus ResolveStatus @default(UNRESOLVED)
  92. resolvedById String?
  93. resolvedByAt DateTime?
  94. requestedById String?
  95. requestedByAt DateTime?
  96. parentId String?
  97. createdAt DateTime @default(now())
  98. updatedAt DateTime @updatedAt
  99. asset Asset @relation(fields: [assetId], references: [id], onDelete: Cascade)
  100. user User @relation(fields: [userId], references: [id], onDelete: Cascade)
  101. parent Comment? @relation("Replies", fields: [parentId], references: [id], onDelete: Cascade)
  102. replies Comment[] @relation("Replies")
  103. resolvedBy User? @relation("ResolvedBy", fields: [resolvedById], references: [id])
  104. requestedBy User? @relation("RequestedBy", fields: [requestedById], references: [id])
  105. }
  106. enum Role {
  107. ADMIN
  108. EDITOR
  109. REVIEWER
  110. VIEWER
  111. }
  112. enum GlobalRole {
  113. ADMIN // system-wide admin: manage users, all projects, quotas
  114. MEMBER // registered user: create own projects, invite members
  115. PROJECT_USER // invited user: no project creation, workspace visibility only via invite
  116. }
  117. enum InvitationStatus {
  118. PENDING
  119. ACCEPTED
  120. EXPIRED
  121. REVOKED
  122. }
  123. model Invitation {
  124. id String @id @default(cuid())
  125. email String // invitee email
  126. projectId String? // null = workspace invite (creates MEMBER); set = project invite (creates PROJECT_USER)
  127. type InvitationType @default(PROJECT)
  128. role Role @default(REVIEWER)
  129. token String @unique
  130. status InvitationStatus @default(PENDING)
  131. invitedBy String? // userId who sent the invite
  132. expiresAt DateTime
  133. createdAt DateTime @default(now())
  134. project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade)
  135. @@index([projectId])
  136. @@index([email])
  137. @@index([token])
  138. }
  139. enum InvitationType {
  140. WORKSPACE // admin invites MEMBER — no project attached, user registers as MEMBER
  141. PROJECT // admin/project member invites PROJECT_USER — attached to a project
  142. }
  143. enum AssetStatus {
  144. PENDING_REVIEW
  145. CHANGES_REQUESTED
  146. APPROVED
  147. REJECTED
  148. }
  149. enum ResolveStatus {
  150. UNRESOLVED // no request made
  151. PENDING_APPROVAL // someone requested resolve, awaiting approval
  152. RESOLVED // approved and closed
  153. }
  154. enum TranscodeStatus {
  155. PENDING
  156. UPLOADING
  157. PROCESSING
  158. COMPLETED
  159. FAILED
  160. UNSUPPORTED_CODEC
  161. }