| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- 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")
- }
- /// A user-defined dashboard card: a named, filtered table over one entity.
- /// The config shape (entity, filters, columns, limit) is validated against
- /// the field registry in customCardActions — nothing here reaches SQL raw.
- model DashboardWidget {
- id String @id @default(cuid())
- name String
- config Json
- userId String
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
- organizationId String
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- @@index([userId, organizationId])
- @@map("dashboard_widgets")
- }
- 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[]
- serviceRecords ServiceRecord[]
- reminders Reminder[]
- customers Customer[]
- quotes Quote[]
- inventoryParts InventoryPart[]
- laborPresets LaborPreset[]
- customFieldDefinitions CustomFieldDefinition[]
- settings AppSetting[]
- emailTemplates EmailTemplate[]
- subscription Subscription?
- invitations TeamInvitation[]
- inspectionTemplates InspectionTemplate[]
- conditionMarks ConditionMark[]
- smsMessages SmsMessage[]
- telegramMessages TelegramMessage[]
- whatsappMessages WhatsappMessage[]
- technicians Technician[]
- workBays WorkBay[]
- timeEntries TimeEntry[]
- pushDevices PushDevice[]
- appSetupCodes TechnicianSetupCode[]
- technicianLoginCodes TechnicianLoginCode[]
- auditLogs AuditLog[]
- statusReports StatusReport[]
- reportSchedules ReportSchedule[]
- scheduledMessages ScheduledMessage[]
- webhooks Webhook[]
- stockMovements StockMovement[]
- tireWarehouses TireWarehouse[]
- tireLocations TireLocation[]
- tireSets TireSet[]
- workOrderStatuses WorkOrderStatus[]
- tireSetAttachments TireSetAttachment[]
- tireMovements TireMovement[]
- tireTreatments TireTreatment[]
- integrationConnections IntegrationConnection[]
- externalCalendarEvents ExternalCalendarEvent[]
- importBatches ImportBatch[]
- vehicleInspectionStatuses VehicleInspectionStatus[]
- inspectionReminderCampaigns InspectionReminderCampaign[]
- inspectionReminderSends InspectionReminderSend[]
- documentDesigns DocumentDesign[]
- documentDesignSnapshots DocumentDesignSnapshot[]
- documentAssetSnapshots DocumentAssetSnapshot[]
- @@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)
- signature MemberSignature?
- @@unique([userId, organizationId])
- @@map("organization_members")
- }
- /// A member's handwritten signature, drawn or uploaded in account settings,
- /// for the Signature section of the documents they issue.
- ///
- /// Kept per workshop rather than per person: a mechanic who works for two
- /// shops signs each one's paper, and leaving a workshop takes the signature
- /// with the membership. The image is held in the row (a PNG or JPEG of a few
- /// kilobytes) so a document can print it without the upload folder, and so
- /// replacing it never touches a file an issued invoice still needs; issued
- /// documents keep their own copy in DocumentAssetSnapshot.
- model MemberSignature {
- id String @id @default(cuid())
- memberId String @unique
- member OrganizationMember @relation(fields: [memberId], references: [id], onDelete: Cascade)
- mimeType String
- data Bytes
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- @@map("member_signatures")
- }
- 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")
- }
|