| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- model Customer {
- id String @id @default(cuid())
- /// Human-facing customer number: auto-assigned sequentially on create,
- /// editable afterwards. Unique per organization (nulls allowed for
- /// legacy customers).
- customerNumber String?
- name String
- email String?
- phone String?
- address String?
- company String?
- taxId String?
- taxExempt Boolean @default(false)
- /// Asked not to receive reminders and campaigns. Honoured by every outreach flow.
- reminderOptOut Boolean @default(false)
- notes String?
- telegramChatId String?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- userId String
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
- organizationId String?
- organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade)
- vehicles Vehicle[]
- quotes Quote[]
- smsMessages SmsMessage[]
- telegramMessages TelegramMessage[]
- whatsappMessages WhatsappMessage[]
- customerSessions CustomerSession[]
- scheduledMessages ScheduledMessage[]
- serviceRequests ServiceRequest[]
- inspectionReminders InspectionReminderSend[]
- serviceRecords ServiceRecord[]
- reminders Reminder[]
- tireSets TireSet[]
- aiChats AiChat[]
- /// The invoice design this customer's invoices use in place of the
- /// workshop's default: a fleet account that wants its own paper. An
- /// invoice's own choice wins over it. SetNull: a deleted design falls
- /// back to the default.
- invoiceDesignId String?
- invoiceDesign DocumentDesign? @relation(fields: [invoiceDesignId], references: [id], onDelete: SetNull)
- importBatchId String?
- importBatch ImportBatch? @relation(fields: [importBatchId], references: [id], onDelete: SetNull)
- @@unique([organizationId, customerNumber])
- @@index([organizationId])
- @@index([importBatchId])
- @@index([invoiceDesignId])
- @@map("customers")
- }
- model CustomerSession {
- id String @id @default(cuid())
- token String @unique
- expiresAt DateTime
- createdAt DateTime @default(now())
- customerId String
- customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade)
- organizationId String
- @@index([token])
- @@index([customerId, organizationId])
- @@map("customer_sessions")
- }
- model CustomerMagicLink {
- id String @id @default(cuid())
- token String @unique
- email String
- organizationId String
- expiresAt DateTime
- usedAt DateTime?
- createdAt DateTime @default(now())
- @@index([token])
- @@map("customer_magic_links")
- }
- model CustomerSmsCode {
- id String @id @default(cuid())
- /// SHA-256 of the digits, not the digits.
- ///
- /// The code reaches the customer in a text message and lives in their head
- /// for a minute. It has no business also sitting in a table where reading a
- /// row hands over somebody's portal session.
- code String
- /// Wrong guesses so far. Six digits is a million, which sounds like plenty
- /// and is not: limiting by address does nothing about a hundred machines
- /// sharing the work. Five attempts against one code makes the space
- /// irrelevant, because the code is gone long before the guessing arrives.
- attempts Int @default(0)
- phone String
- organizationId String
- expiresAt DateTime
- usedAt DateTime?
- createdAt DateTime @default(now())
- @@index([phone, organizationId])
- @@index([organizationId])
- @@map("customer_sms_codes")
- }
- model ServiceRequest {
- id String @id @default(cuid())
- description String
- preferredDate DateTime?
- status String @default("pending")
- adminNotes String?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- customerId String
- customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade)
- vehicleId String
- vehicle Vehicle @relation(fields: [vehicleId], references: [id], onDelete: Cascade)
- organizationId String
- @@index([organizationId, status])
- @@index([customerId])
- @@map("service_requests")
- }
|