model InspectionTemplate { id String @id @default(cuid()) name String description String? isDefault Boolean @default(false) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Regulatory profile. `country` is an ISO-3166 alpha-2 code (or null for a // shop-specific checklist), `standard` names the regime the template follows // (e.g. "eu-2014-45"), and `severityScale` picks which defect vocabulary the // technician grades against — see Lib/conditions.ts. country String? standard String? @default("custom") severityScale String @default("eu") /// Provenance, for templates that came from a package rather than being /// written here. `packageId` is namespaced and stable across renames /// ("torqvoice/eu-roadworthiness"), which is what lets the library tell an /// update from a duplicate. Null on a template the workshop wrote itself. packageId String? packageVersion String? /// Where it came from: "builtin", "file" or "catalogue". packageSource String? organizationId String organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) sections InspectionTemplateSection[] inspections Inspection[] @@index([organizationId]) @@index([organizationId, packageId]) @@map("inspection_templates") } model InspectionTemplateSection { id String @id @default(cuid()) name String description String? // Regulation reference for the section, e.g. "1" for Braking equipment in // Directive 2014/45/EU Annex I. code 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 description String? // Regulation reference for the check, e.g. "1.1.13". code String? sortOrder Int @default(0) // How the technician records the result: "condition" (defect grading only), // "measurement" (numeric value in `unit`, graded against min/max), // "text" (free text) or "choice" (one of `choices`). inputType String @default("condition") unit String? minValue Float? maxValue Float? choices String[] @default([]) required Boolean @default(false) photoRequired Boolean @default(false) /// The check may be graded "not applicable": the vehicle has no such part. allowNotApplicable Boolean @default(true) // Defect severity applied when a measurement falls outside min/max. defaultSeverity String? // Phrases this workshop wants offered when a defect is recorded against the // check, on top of the built-in catalogue. See Lib/defectCatalogue.ts. defectSuggestions String[] @default([]) 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) /// See ServiceRecord.workBayId — an inspection occupies a bay just as a /// repair does, and the work board lanes both the same way. workBayId String? workBay WorkBay? @relation(fields: [workBayId], references: [id], onDelete: SetNull) sortOrder Int @default(0) // Roadworthiness certificate fields required by Directive 2014/45/EU Annex IV. // `inspectorName` and `certificateNumber` are snapshots taken at completion so // the issued certificate stays stable even if staff or settings change later. /// Snapshot of how this inspection was graded, taken when it was created. /// Read in preference to the template's current setting: a workshop that /// later switches a template to the EU scale must not relabel a certificate /// it already issued. Null on inspections that predate the snapshot; those /// fall back to the template, which the migration pinned to its old scale. severityScale String? country String? vehicleCategory String? nextTestDue DateTime? certificateNumber String? inspectorName String? testLocation String? /// The certificate design as it was when the inspection was completed, so a /// design edited later never changes a certificate a customer already has. /// Null on inspections completed before designs existed, or by a workshop /// that has never designed one; those print the built-in sheet. designSnapshotId String? designSnapshot DocumentDesignSnapshot? @relation(fields: [designSnapshotId], references: [id], onDelete: SetNull) /// The inspector's signature as it was at completion, for the same reason: /// a redrawn signature never changes a certificate already issued. signatureSnapshotId String? signatureSnapshot DocumentAssetSnapshot? @relation(fields: [signatureSnapshotId], references: [id], onDelete: SetNull) /// The condition map's kinds of mark as they were named and drawn at /// completion, for the same reason: a kind renamed later never changes a /// certificate already issued. Null before the kinds could be changed. markTypesSnapshot Json? organizationId String items InspectionItem[] attachments InspectionAttachment[] statusReports StatusReport[] quoteRequests InspectionQuoteRequest[] quotes Quote[] serviceRecords ServiceRecord[] conditionMarks ConditionMark[] importBatchId String? importBatch ImportBatch? @relation(fields: [importBatchId], references: [id], onDelete: SetNull) @@index([vehicleId]) @@index([designSnapshotId]) @@index([signatureSnapshotId]) @@index([organizationId]) @@index([technicianId]) @@index([workBayId]) @@map("inspections") } /// Files filed on the inspection as a whole rather than on one check: the /// overview photos, a video of the walk round, the regulator's own paper form /// once it is filled in and signed. A photo that is the evidence for a single /// check stays on that check (InspectionItem.imageUrls), next to its grade. model InspectionAttachment { id String @id @default(cuid()) fileName String fileUrl String fileType String fileSize Int /// "image", "document" or "video". category String @default("image") description String? /// Shown to the customer on the shared inspection link. Photos start shown, /// documents start hidden: paperwork is the workshop's until it says so. includeInReport Boolean @default(true) createdAt DateTime @default(now()) inspectionId String inspection Inspection @relation(fields: [inspectionId], references: [id], onDelete: Cascade) @@index([inspectionId]) @@map("inspection_attachments") } 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([]) // Copied from the template at creation so an inspection stays readable even // after its template is edited or deleted. description String? code String? sectionCode String? inputType String @default("condition") unit String? minValue Float? maxValue Float? choices String[] @default([]) required Boolean @default(false) photoRequired Boolean @default(false) /// The check may be graded "not applicable": the vehicle has no such part. allowNotApplicable Boolean @default(true) defaultSeverity String? defectSuggestions String[] @default([]) measuredValue Float? textValue String? inspectionId String inspection Inspection @relation(fields: [inspectionId], references: [id], onDelete: Cascade) conditionMarks ConditionMark[] @@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") }