| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105 |
- generator client {
- provider = "prisma-client-js"
- }
- datasource db {
- provider = "postgresql"
- url = env("DATABASE_URL")
- }
- model User {
- id String @id @default(cuid())
- name String
- email String @unique
- emailVerified Boolean @default(false)
- image String?
- isSuperAdmin Boolean @default(false)
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- twoFactorEnabled Boolean @default(false)
- termsAcceptedAt DateTime?
- lastLogin DateTime?
- lastSeen DateTime?
- sessions Session[]
- accounts Account[]
- vehicles Vehicle[]
- customers Customer[]
- settings AppSetting[]
- inventoryParts InventoryPart[]
- quotes Quote[]
- customFieldDefinitions CustomFieldDefinition[]
- twoFactor TwoFactor?
- passkeys Passkey[]
- organizationMembers OrganizationMember[]
- auditLogs AuditLog[]
- technicians Technician[]
- @@map("users")
- }
- model AppSetting {
- id String @id @default(cuid())
- key String
- value String
- userId String
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
- organizationId String?
- organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade)
- @@unique([organizationId, key])
- @@index([organizationId])
- @@map("app_settings")
- }
- model Session {
- id String @id @default(cuid())
- expiresAt DateTime
- token String @unique
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- ipAddress String?
- userAgent String?
- userId String
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
- @@index([userId])
- @@map("sessions")
- }
- model Account {
- id String @id @default(cuid())
- accountId String
- providerId String
- userId String
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
- accessToken String?
- refreshToken String?
- idToken String?
- accessTokenExpiresAt DateTime?
- refreshTokenExpiresAt DateTime?
- scope String?
- password String?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- @@index([userId])
- @@map("accounts")
- }
- model Verification {
- id String @id @default(cuid())
- identifier String @unique
- value String
- expiresAt DateTime
- createdAt DateTime? @default(now())
- updatedAt DateTime? @updatedAt
- @@map("verifications")
- }
- model TwoFactor {
- id String @id @default(cuid())
- secret String
- backupCodes String
- userId String @unique
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
- @@map("two_factor")
- }
- model Passkey {
- id String @id @default(cuid())
- name String?
- publicKey String
- userId String
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
- credentialID String @unique
- counter Int
- deviceType String
- backedUp Boolean
- transports String?
- aaguid String?
- createdAt DateTime @default(now())
- @@index([userId])
- @@map("passkeys")
- }
- model Vehicle {
- id String @id @default(cuid())
- make String
- model String
- year Int
- vin String?
- licensePlate String?
- color String?
- mileage Int @default(0)
- fuelType String? @default("gasoline")
- transmission String? @default("automatic")
- engineSize String?
- purchaseDate DateTime?
- purchasePrice Float?
- imageUrl String?
- isArchived Boolean @default(false)
- archiveReason String?
- maintenanceDismissed Boolean @default(false)
- maintenanceDismissedAt DateTime?
- aiMessages AiGeneratedMessage[]
- 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)
- customerId String?
- customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull)
- serviceRecords ServiceRecord[]
- notes Note[]
- fuelLogs FuelLog[]
- reminders Reminder[]
- quotes Quote[]
- recurringInvoices RecurringInvoice[]
- inspections Inspection[]
- serviceRequests ServiceRequest[]
- @@index([organizationId])
- @@map("vehicles")
- }
- model ServiceRecord {
- id String @id @default(cuid())
- title String
- description String?
- type String @default("maintenance")
- status String @default("completed")
- cost Float @default(0)
- mileage Int?
- serviceDate DateTime @default(now())
- startDateTime DateTime?
- endDateTime DateTime?
- shopName String?
- techName String?
- parts String?
- laborHours Float?
- diagnosticNotes String?
- invoiceNotes String?
- subtotal Float @default(0)
- taxRate Float @default(0)
- taxAmount Float @default(0)
- totalAmount Float @default(0)
- invoiceNumber String?
- invoiceDate DateTime?
- invoiceDueDate DateTime?
- discountType String?
- discountValue Float @default(0)
- discountAmount Float @default(0)
- manuallyPaid Boolean @default(false)
- publicToken String? @unique
- sharedAt DateTime?
- viewCount Int @default(0)
- lastViewedAt DateTime?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- vehicleId String
- vehicle Vehicle @relation(fields: [vehicleId], references: [id], onDelete: Cascade)
- technicianId String?
- technician Technician? @relation(fields: [technicianId], references: [id], onDelete: SetNull)
- sortOrder Int @default(0)
- partItems ServicePart[]
- laborItems ServiceLabor[]
- attachments ServiceAttachment[]
- payments Payment[]
- @@index([vehicleId])
- @@index([technicianId])
- @@map("service_records")
- }
- model Note {
- id String @id @default(cuid())
- title String
- content String
- isPinned Boolean @default(false)
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- vehicleId String
- vehicle Vehicle @relation(fields: [vehicleId], references: [id], onDelete: Cascade)
- @@index([vehicleId])
- @@map("notes")
- }
- model FuelLog {
- id String @id @default(cuid())
- date DateTime @default(now())
- mileage Int
- gallons Float
- pricePerGallon Float
- totalCost Float
- isFillUp Boolean @default(true)
- station String?
- notes String?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- vehicleId String
- vehicle Vehicle @relation(fields: [vehicleId], references: [id], onDelete: Cascade)
- @@index([vehicleId])
- @@map("fuel_logs")
- }
- model Reminder {
- id String @id @default(cuid())
- title String
- description String?
- dueDate DateTime?
- dueMileage Int?
- isCompleted Boolean @default(false)
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- vehicleId String
- vehicle Vehicle @relation(fields: [vehicleId], references: [id], onDelete: Cascade)
- @@index([vehicleId])
- @@map("reminders")
- }
- model Customer {
- id String @id @default(cuid())
- name String
- email String?
- phone String?
- address String?
- company String?
- 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[]
- customerSessions CustomerSession[]
- serviceRequests ServiceRequest[]
- @@index([organizationId])
- @@map("customers")
- }
- model Payment {
- id String @id @default(cuid())
- amount Float
- date DateTime @default(now())
- method String @default("other")
- note String?
- provider String?
- externalId String?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- serviceRecordId String
- serviceRecord ServiceRecord @relation(fields: [serviceRecordId], references: [id], onDelete: Cascade)
- @@index([serviceRecordId])
- @@map("payments")
- }
- model ServiceAttachment {
- id String @id @default(cuid())
- fileName String
- fileUrl String
- fileType String
- fileSize Int
- category String @default("diagnostic")
- description String?
- includeInInvoice Boolean @default(true)
- createdAt DateTime @default(now())
- serviceRecordId String
- serviceRecord ServiceRecord @relation(fields: [serviceRecordId], references: [id], onDelete: Cascade)
- @@index([serviceRecordId])
- @@map("service_attachments")
- }
- model ServicePart {
- id String @id @default(cuid())
- partNumber String?
- name String
- quantity Float @default(1)
- unitPrice Float @default(0)
- total Float @default(0)
- unitCost Float @default(0)
- inventoryPartId String?
- serviceRecordId String
- serviceRecord ServiceRecord @relation(fields: [serviceRecordId], references: [id], onDelete: Cascade)
- @@index([serviceRecordId])
- @@map("service_parts")
- }
- model ServiceLabor {
- id String @id @default(cuid())
- description String
- hours Float @default(0)
- rate Float @default(0)
- total Float @default(0)
- pricingType String @default("hourly")
- serviceRecordId String
- serviceRecord ServiceRecord @relation(fields: [serviceRecordId], references: [id], onDelete: Cascade)
- @@index([serviceRecordId])
- @@map("service_labor")
- }
- model LaborPreset {
- id String @id @default(cuid())
- name String
- description String?
- isArchived Boolean @default(false)
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- userId String
- organizationId String
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
- items LaborPresetItem[]
- @@index([organizationId])
- @@map("labor_presets")
- }
- model LaborPresetItem {
- id String @id @default(cuid())
- description String
- hours Float @default(0)
- rate Float @default(0)
- pricingType String @default("hourly")
- sortOrder Int @default(0)
- presetId String
- preset LaborPreset @relation(fields: [presetId], references: [id], onDelete: Cascade)
- @@index([presetId])
- @@map("labor_preset_items")
- }
- model InventoryPart {
- id String @id @default(cuid())
- partNumber String?
- barcode String?
- name String
- description String?
- category String?
- quantity Int @default(0)
- minQuantity Int @default(0)
- unitCost Float @default(0)
- sellPrice Float @default(0)
- supplier String?
- supplierPhone String?
- supplierEmail String?
- supplierUrl String?
- imageUrl String?
- location String?
- isArchived Boolean @default(false)
- 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)
- gallery StoredImage[] @relation("InventoryPartImages")
- @@index([organizationId])
- @@map("inventory_parts")
- }
- model StoredImage {
- id String @id @default(cuid())
- url String
- fileName String?
- description String?
- sortOrder Int @default(0)
- createdAt DateTime @default(now())
- inventoryPartId String?
- inventoryPart InventoryPart? @relation("InventoryPartImages", fields: [inventoryPartId], references: [id], onDelete: Cascade)
- @@index([inventoryPartId])
- @@map("stored_images")
- }
- model Quote {
- id String @id @default(cuid())
- quoteNumber String?
- title String
- description String?
- status String @default("draft")
- validUntil DateTime?
- subtotal Float @default(0)
- taxRate Float @default(0)
- taxAmount Float @default(0)
- discountType String?
- discountValue Float @default(0)
- discountAmount Float @default(0)
- totalAmount Float @default(0)
- notes String?
- publicToken String?
- sharedAt DateTime?
- viewCount Int @default(0)
- lastViewedAt DateTime?
- customerMessage String?
- convertedToId 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)
- customerId String?
- customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull)
- vehicleId String?
- vehicle Vehicle? @relation(fields: [vehicleId], references: [id], onDelete: SetNull)
- inspectionId String?
- inspection Inspection? @relation(fields: [inspectionId], references: [id], onDelete: SetNull)
- partItems QuotePart[]
- laborItems QuoteLabor[]
- attachments QuoteAttachment[]
- @@index([organizationId])
- @@map("quotes")
- }
- model QuoteAttachment {
- id String @id @default(cuid())
- fileName String
- fileUrl String
- fileType String
- fileSize Int
- category String @default("image")
- description String?
- includeInInvoice Boolean @default(true)
- createdAt DateTime @default(now())
- quoteId String
- quote Quote @relation(fields: [quoteId], references: [id], onDelete: Cascade)
- @@index([quoteId])
- @@map("quote_attachments")
- }
- model QuotePart {
- id String @id @default(cuid())
- partNumber String?
- name String
- quantity Float @default(1)
- unitPrice Float @default(0)
- total Float @default(0)
- excluded Boolean @default(false)
- quoteId String
- quote Quote @relation(fields: [quoteId], references: [id], onDelete: Cascade)
- @@index([quoteId])
- @@map("quote_parts")
- }
- model QuoteLabor {
- id String @id @default(cuid())
- description String
- hours Float @default(0)
- rate Float @default(0)
- total Float @default(0)
- pricingType String @default("hourly")
- excluded Boolean @default(false)
- quoteId String
- quote Quote @relation(fields: [quoteId], references: [id], onDelete: Cascade)
- @@index([quoteId])
- @@map("quote_labor")
- }
- model CustomFieldDefinition {
- id String @id @default(cuid())
- name String
- label String
- fieldType String @default("text")
- options String?
- required Boolean @default(false)
- entityType String
- sortOrder Int @default(0)
- isActive Boolean @default(true)
- 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)
- values CustomFieldValue[]
- @@unique([organizationId, name, entityType])
- @@index([organizationId])
- @@map("custom_field_definitions")
- }
- model CustomFieldValue {
- id String @id @default(cuid())
- value String
- entityId String
- entityType String
- fieldId String
- field CustomFieldDefinition @relation(fields: [fieldId], references: [id], onDelete: Cascade)
- @@unique([fieldId, entityId])
- @@index([fieldId])
- @@map("custom_field_values")
- }
- model Organization {
- id String @id @default(cuid())
- name String
- portalSlug String? @unique
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- members OrganizationMember[]
- roles Role[]
- vehicles Vehicle[]
- customers Customer[]
- quotes Quote[]
- inventoryParts InventoryPart[]
- laborPresets LaborPreset[]
- customFieldDefinitions CustomFieldDefinition[]
- settings AppSetting[]
- subscription Subscription?
- invitations TeamInvitation[]
- inspectionTemplates InspectionTemplate[]
- smsMessages SmsMessage[]
- telegramMessages TelegramMessage[]
- technicians Technician[]
- auditLogs AuditLog[]
- @@map("organizations")
- }
- model OrganizationMember {
- id String @id @default(cuid())
- role String @default("member")
- userId String
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
- organizationId String
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
- roleId String?
- customRole Role? @relation(fields: [roleId], references: [id], onDelete: SetNull)
- @@unique([userId, organizationId])
- @@map("organization_members")
- }
- model Role {
- id String @id @default(cuid())
- name String
- isAdmin Boolean @default(false)
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- organizationId String
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
- permissions Permission[]
- members OrganizationMember[]
- teamInvitations TeamInvitation[]
- @@unique([organizationId, name])
- @@map("roles")
- }
- model Permission {
- id String @id @default(cuid())
- action String
- subject String
- roleId String
- role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
- @@unique([roleId, action, subject])
- @@index([roleId])
- @@map("permissions")
- }
- model SystemSetting {
- id String @id @default(cuid())
- key String @unique
- value String
- @@map("system_settings")
- }
- model TeamInvitation {
- id String @id @default(cuid())
- email String
- role String @default("member")
- token String @unique
- status String @default("pending") // pending | accepted | cancelled
- expiresAt DateTime
- createdAt DateTime @default(now())
- organizationId String
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
- invitedById String
- roleId String?
- customRole Role? @relation(fields: [roleId], references: [id], onDelete: SetNull)
- @@unique([email, organizationId])
- @@index([token])
- @@map("team_invitations")
- }
- // Stripe-ready models (implementation in follow-up)
- model SubscriptionPlan {
- id String @id @default(cuid())
- name String
- stripePriceId String? @unique
- price Float @default(0)
- interval String @default("month") // "month" | "year"
- maxMembers Int @default(1)
- features String? // JSON feature flags
- isActive Boolean @default(true)
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- subscriptions Subscription[]
- @@map("subscription_plans")
- }
- model Subscription {
- id String @id @default(cuid())
- status String @default("active") // active | canceled | past_due | trialing
- stripeSubscriptionId String? @unique
- stripeCustomerId String?
- currentPeriodStart DateTime?
- currentPeriodEnd DateTime?
- cancelAtPeriodEnd Boolean @default(false)
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- organizationId String @unique
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
- planId String
- plan SubscriptionPlan @relation(fields: [planId], references: [id])
- @@map("subscriptions")
- }
- model RecurringInvoice {
- id String @id @default(cuid())
- title String
- description String?
- frequency String // "weekly" | "biweekly" | "monthly" | "quarterly" | "yearly"
- nextRunDate DateTime
- endDate DateTime?
- isActive Boolean @default(true)
- lastRunAt DateTime?
- runCount Int @default(0)
- // Template fields (copied to ServiceRecord on generation)
- type String @default("maintenance")
- cost Float @default(0)
- taxRate Float @default(0)
- invoiceNotes String?
- vehicleId String
- vehicle Vehicle @relation(fields: [vehicleId], references: [id], onDelete: Cascade)
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- templateParts RecurringPart[]
- templateLabor RecurringLabor[]
- @@index([vehicleId])
- @@index([nextRunDate, isActive])
- @@map("recurring_invoices")
- }
- model RecurringPart {
- id String @id @default(cuid())
- name String
- partNumber String?
- quantity Int @default(1)
- unitPrice Float @default(0)
- recurringInvoiceId String
- recurringInvoice RecurringInvoice @relation(fields: [recurringInvoiceId], references: [id], onDelete: Cascade)
- @@map("recurring_parts")
- }
- model RecurringLabor {
- id String @id @default(cuid())
- description String
- hours Float @default(0)
- rate Float @default(0)
- pricingType String @default("hourly")
- recurringInvoiceId String
- recurringInvoice RecurringInvoice @relation(fields: [recurringInvoiceId], references: [id], onDelete: Cascade)
- @@map("recurring_labor")
- }
- model InspectionTemplate {
- id String @id @default(cuid())
- name String
- description String?
- isDefault Boolean @default(false)
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- organizationId String
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
- sections InspectionTemplateSection[]
- inspections Inspection[]
- @@index([organizationId])
- @@map("inspection_templates")
- }
- model InspectionTemplateSection {
- id String @id @default(cuid())
- name String
- sortOrder Int @default(0)
- templateId String
- template InspectionTemplate @relation(fields: [templateId], references: [id], onDelete: Cascade)
- items InspectionTemplateItem[]
- @@index([templateId])
- @@map("inspection_template_sections")
- }
- model InspectionTemplateItem {
- id String @id @default(cuid())
- name String
- sortOrder Int @default(0)
- sectionId String
- section InspectionTemplateSection @relation(fields: [sectionId], references: [id], onDelete: Cascade)
- @@index([sectionId])
- @@map("inspection_template_items")
- }
- model Inspection {
- id String @id @default(cuid())
- status String @default("in_progress")
- mileage Int?
- notes String?
- startDateTime DateTime?
- endDateTime DateTime?
- publicToken String? @unique
- completedAt DateTime?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- vehicleId String
- vehicle Vehicle @relation(fields: [vehicleId], references: [id], onDelete: Cascade)
- templateId String
- template InspectionTemplate @relation(fields: [templateId], references: [id])
- technicianId String?
- technician Technician? @relation(fields: [technicianId], references: [id], onDelete: SetNull)
- sortOrder Int @default(0)
- organizationId String
- items InspectionItem[]
- quoteRequests InspectionQuoteRequest[]
- quotes Quote[]
- @@index([vehicleId])
- @@index([organizationId])
- @@index([technicianId])
- @@map("inspections")
- }
- model InspectionItem {
- id String @id @default(cuid())
- name String
- section String
- sortOrder Int @default(0)
- condition String @default("not_inspected")
- notes String?
- imageUrls String[] @default([])
- inspectionId String
- inspection Inspection @relation(fields: [inspectionId], references: [id], onDelete: Cascade)
- @@index([inspectionId])
- @@map("inspection_items")
- }
- model InspectionQuoteRequest {
- id String @id @default(cuid())
- status String @default("pending")
- message String?
- selectedItemIds String[]
- createdAt DateTime @default(now())
- inspectionId String
- inspection Inspection @relation(fields: [inspectionId], references: [id], onDelete: Cascade)
- organizationId String
- @@index([organizationId])
- @@index([inspectionId])
- @@map("inspection_quote_requests")
- }
- 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?
- 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])
- @@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?
- 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)])
- @@map("telegram_messages")
- }
- model Technician {
- id String @id @default(cuid())
- name String
- color String @default("#3b82f6")
- isActive Boolean @default(true)
- sortOrder Int @default(0)
- dailyCapacity Int @default(480)
- userId String?
- user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
- organizationId String
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
- serviceRecords ServiceRecord[]
- inspections Inspection[]
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- @@index([organizationId])
- @@map("technicians")
- }
- model AuditLog {
- id String @id @default(cuid())
- timestamp DateTime @default(now())
- action String
- entity String?
- entityId String?
- message String?
- metadata Json?
- ip String?
- userAgent String?
- userId String?
- user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
- organizationId String?
- organization Organization? @relation(fields: [organizationId], references: [id], onDelete: SetNull)
- @@index([organizationId, timestamp(sort: Desc)])
- @@index([userId, timestamp(sort: Desc)])
- @@index([action, timestamp(sort: Desc)])
- @@map("audit_logs")
- }
- 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 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")
- }
- model AiGeneratedMessage {
- id String @id @default(cuid())
- vehicleId String
- type String // "summary" | "common_issues" | etc.
- content String
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- vehicle Vehicle @relation(fields: [vehicleId], references: [id], onDelete: Cascade)
- @@unique([vehicleId, type])
- @@map("ai_generated_messages")
- }
- model AiChat {
- id String @id @default(cuid())
- title String @default("New chat")
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- userId String
- organizationId String
- messages AiChatMessage[]
- @@index([organizationId, userId, updatedAt(sort: Desc)])
- @@map("ai_chats")
- }
- model AiChatMessage {
- id String @id @default(cuid())
- role String // "user" | "assistant"
- content String
- createdAt DateTime @default(now())
- chatId String
- chat AiChat @relation(fields: [chatId], references: [id], onDelete: Cascade)
- @@index([chatId, createdAt])
- @@map("ai_chat_messages")
- }
|