messaging.prisma 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. model Notification {
  2. id String @id @default(cuid())
  3. type String
  4. title String
  5. message String
  6. entityType String
  7. entityId String
  8. entityUrl String
  9. read Boolean @default(false)
  10. organizationId String
  11. createdAt DateTime @default(now())
  12. @@index([organizationId, createdAt(sort: Desc)])
  13. @@index([organizationId, read])
  14. @@map("notifications")
  15. }
  16. model SmsMessage {
  17. id String @id @default(cuid())
  18. direction String // "inbound" | "outbound"
  19. fromNumber String
  20. toNumber String
  21. body String
  22. status String @default("queued") // queued | sent | delivered | failed | received
  23. providerMsgId String?
  24. errorMessage String?
  25. relatedEntityType String?
  26. relatedEntityId String?
  27. /// When the workshop first opened the thread this arrived in. Null on an
  28. /// inbound message nobody has read yet; never set on an outbound row.
  29. readAt DateTime?
  30. createdAt DateTime @default(now())
  31. updatedAt DateTime @updatedAt
  32. organizationId String
  33. organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
  34. customerId String?
  35. customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull)
  36. @@index([organizationId, customerId, createdAt(sort: Desc)])
  37. @@index([organizationId, createdAt(sort: Desc)])
  38. @@index([toNumber, organizationId])
  39. @@index([organizationId, readAt])
  40. @@map("sms_messages")
  41. }
  42. model TelegramMessage {
  43. id String @id @default(cuid())
  44. direction String // "inbound" | "outbound"
  45. chatId String // Telegram chat ID
  46. body String
  47. status String @default("queued") // queued | sent | delivered | failed | received
  48. telegramMessageId String? // Telegram's message ID for tracking
  49. errorMessage String?
  50. relatedEntityType String?
  51. relatedEntityId String?
  52. /// When the workshop first opened the thread this arrived in. Null on an
  53. /// inbound message nobody has read yet; never set on an outbound row.
  54. readAt DateTime?
  55. createdAt DateTime @default(now())
  56. updatedAt DateTime @updatedAt
  57. organizationId String
  58. organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
  59. customerId String?
  60. customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull)
  61. @@index([organizationId, customerId, createdAt(sort: Desc)])
  62. @@index([organizationId, chatId, createdAt(sort: Desc)])
  63. @@index([organizationId, readAt])
  64. @@map("telegram_messages")
  65. }
  66. /// One WhatsApp message in either direction.
  67. ///
  68. /// `provider` records which adapter carried it, because a workshop can switch
  69. /// provider without its history becoming unreadable, and a status callback
  70. /// arriving later has to find the row it belongs to.
  71. model WhatsappMessage {
  72. id String @id @default(cuid())
  73. direction String // "inbound" | "outbound"
  74. provider String // "meta" | "twilio" | any adapter registered later
  75. /// E.164 without the "whatsapp:" prefix a provider may use on the wire.
  76. fromNumber String
  77. toNumber String
  78. body String?
  79. /// Media the message carried. Inbound URLs may need the provider's
  80. /// credentials to fetch, so they are not necessarily public.
  81. mediaUrl String?
  82. mediaType String? // image | document | video | audio | sticker
  83. mediaFilename String?
  84. /// Set when the message had to go out as an approved template, which is the
  85. /// only thing WhatsApp allows outside the 24 hour service window.
  86. templateName String?
  87. status String @default("queued") // queued | sent | delivered | read | failed | received
  88. providerMessageId String?
  89. errorMessage String?
  90. relatedEntityType String?
  91. relatedEntityId String?
  92. /// When the workshop first opened the thread this arrived in. Null on an
  93. /// inbound message nobody has read yet; never set on an outbound row.
  94. readAt DateTime?
  95. createdAt DateTime @default(now())
  96. updatedAt DateTime @updatedAt
  97. organizationId String
  98. organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
  99. customerId String?
  100. customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull)
  101. @@index([organizationId, customerId, createdAt(sort: Desc)])
  102. @@index([organizationId, createdAt(sort: Desc)])
  103. @@index([providerMessageId])
  104. @@index([organizationId, readAt])
  105. @@map("whatsapp_messages")
  106. }
  107. /// A message the workshop lines up to go out on a given day and time, through
  108. /// whichever channel suits the customer. One-off by default; a frequency other
  109. /// than "once" reschedules itself after each send, the way ReportSchedule does.
  110. model ScheduledMessage {
  111. id String @id @default(cuid())
  112. channel String // "email" | "sms" | "telegram" | "in_app"
  113. subject String? // email only
  114. body String
  115. /// Where it goes when no customer is attached, or when the workshop typed an
  116. /// address by hand. Falls back to the customer's email/phone/chat id.
  117. recipient String?
  118. status String @default("scheduled") // scheduled | sent | failed | cancelled
  119. sendAt DateTime
  120. frequency String @default("once") // once | daily | weekly | biweekly | monthly | yearly
  121. endDate DateTime?
  122. lastRunAt DateTime?
  123. sentAt DateTime?
  124. runCount Int @default(0)
  125. errorMessage String?
  126. createdAt DateTime @default(now())
  127. updatedAt DateTime @updatedAt
  128. organizationId String
  129. organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
  130. customerId String?
  131. customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull)
  132. vehicleId String?
  133. vehicle Vehicle? @relation(fields: [vehicleId], references: [id], onDelete: SetNull)
  134. createdById String
  135. inspectionReminder InspectionReminderSend?
  136. @@index([organizationId, sendAt])
  137. @@index([status, sendAt])
  138. @@map("scheduled_messages")
  139. }