| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- model Notification {
- id String @id @default(cuid())
- type String
- title String
- message String
- entityType String
- entityId String
- entityUrl String
- read Boolean @default(false)
- organizationId String
- createdAt DateTime @default(now())
- @@index([organizationId, createdAt(sort: Desc)])
- @@index([organizationId, read])
- @@map("notifications")
- }
- model SmsMessage {
- id String @id @default(cuid())
- direction String // "inbound" | "outbound"
- fromNumber String
- toNumber String
- body String
- status String @default("queued") // queued | sent | delivered | failed | received
- providerMsgId String?
- errorMessage String?
- relatedEntityType String?
- relatedEntityId String?
- /// When the workshop first opened the thread this arrived in. Null on an
- /// inbound message nobody has read yet; never set on an outbound row.
- readAt DateTime?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- organizationId String
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
- customerId String?
- customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull)
- @@index([organizationId, customerId, createdAt(sort: Desc)])
- @@index([organizationId, createdAt(sort: Desc)])
- @@index([toNumber, organizationId])
- @@index([organizationId, readAt])
- @@map("sms_messages")
- }
- model TelegramMessage {
- id String @id @default(cuid())
- direction String // "inbound" | "outbound"
- chatId String // Telegram chat ID
- body String
- status String @default("queued") // queued | sent | delivered | failed | received
- telegramMessageId String? // Telegram's message ID for tracking
- errorMessage String?
- relatedEntityType String?
- relatedEntityId String?
- /// When the workshop first opened the thread this arrived in. Null on an
- /// inbound message nobody has read yet; never set on an outbound row.
- readAt DateTime?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- organizationId String
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
- customerId String?
- customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull)
- @@index([organizationId, customerId, createdAt(sort: Desc)])
- @@index([organizationId, chatId, createdAt(sort: Desc)])
- @@index([organizationId, readAt])
- @@map("telegram_messages")
- }
- /// One WhatsApp message in either direction.
- ///
- /// `provider` records which adapter carried it, because a workshop can switch
- /// provider without its history becoming unreadable, and a status callback
- /// arriving later has to find the row it belongs to.
- model WhatsappMessage {
- id String @id @default(cuid())
- direction String // "inbound" | "outbound"
- provider String // "meta" | "twilio" | any adapter registered later
- /// E.164 without the "whatsapp:" prefix a provider may use on the wire.
- fromNumber String
- toNumber String
- body String?
- /// Media the message carried. Inbound URLs may need the provider's
- /// credentials to fetch, so they are not necessarily public.
- mediaUrl String?
- mediaType String? // image | document | video | audio | sticker
- mediaFilename String?
- /// Set when the message had to go out as an approved template, which is the
- /// only thing WhatsApp allows outside the 24 hour service window.
- templateName String?
- status String @default("queued") // queued | sent | delivered | read | failed | received
- providerMessageId String?
- errorMessage String?
- relatedEntityType String?
- relatedEntityId String?
- /// When the workshop first opened the thread this arrived in. Null on an
- /// inbound message nobody has read yet; never set on an outbound row.
- readAt DateTime?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- organizationId String
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
- customerId String?
- customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull)
- @@index([organizationId, customerId, createdAt(sort: Desc)])
- @@index([organizationId, createdAt(sort: Desc)])
- @@index([providerMessageId])
- @@index([organizationId, readAt])
- @@map("whatsapp_messages")
- }
- /// A message the workshop lines up to go out on a given day and time, through
- /// whichever channel suits the customer. One-off by default; a frequency other
- /// than "once" reschedules itself after each send, the way ReportSchedule does.
- model ScheduledMessage {
- id String @id @default(cuid())
- channel String // "email" | "sms" | "telegram" | "in_app"
- subject String? // email only
- body String
- /// Where it goes when no customer is attached, or when the workshop typed an
- /// address by hand. Falls back to the customer's email/phone/chat id.
- recipient String?
- status String @default("scheduled") // scheduled | sent | failed | cancelled
- sendAt DateTime
- frequency String @default("once") // once | daily | weekly | biweekly | monthly | yearly
- endDate DateTime?
- lastRunAt DateTime?
- sentAt DateTime?
- runCount Int @default(0)
- errorMessage String?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- organizationId String
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
- customerId String?
- customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull)
- vehicleId String?
- vehicle Vehicle? @relation(fields: [vehicleId], references: [id], onDelete: SetNull)
- createdById String
- inspectionReminder InspectionReminderSend?
- @@index([organizationId, sendAt])
- @@index([status, sendAt])
- @@map("scheduled_messages")
- }
|