generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model DbHealthCheck { id String @id @default(uuid()) createdAt DateTime @default(now()) } // ============================================================================= // Пользователи и роли (RBAC) // ============================================================================= enum Role { ADMIN DIRECTOR MECHANIC WORKER OTHER } model User { id String @id @default(uuid()) email String @unique password String // bcrypt hash firstName String lastName String role Role @default(OTHER) isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations assignedToOrders RepairOrderAssignee[] } // ============================================================================= // Контрагенты // ============================================================================= model Contractor { id String @id @default(uuid()) name String inn String? // ИНН (опционально) address String? phone String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations repairOrders RepairOrder[] trips Trip[] serviceObjects ServiceObject[] calculationTemplates CalculationTemplate[] } // ============================================================================= // Агрегаты (оборудование) // ============================================================================= model Unit { id String @id @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations identifiers UnitIdentifier[] repairOrders RepairOrder[] } model UnitIdentifier { id String @id @default(uuid()) unitId String type String // 'SERIAL', 'INTERNAL', 'CUSTOMER' value String validFrom DateTime @default(now()) validTo DateTime? // Relations unit Unit @relation(fields: [unitId], references: [id], onDelete: Cascade) @@unique([unitId, type, value, validFrom]) } // ============================================================================= // Ремонты (RepairOrder) // ============================================================================= enum RepairStatus { RECEIVED DIAGNOSIS WAITING_APPROVAL WAITING_PARTS IN_WORK ISSUED CANCELED } model RepairOrder { id String @id @default(uuid()) unitId String contractorId String status RepairStatus @default(RECEIVED) description String? issuedAt DateTime? // дата выдачи warrantyFrom DateTime? // начало гарантии warrantyTo DateTime? // конец гарантии warrantyDays Int? // срок гарантии в днях version Int @default(1) // optimistic locking isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations unit Unit @relation(fields: [unitId], references: [id]) contractor Contractor @relation(fields: [contractorId], references: [id]) assignees RepairOrderAssignee[] calculation Calculation? @@index([status]) @@index([contractorId]) @@index([unitId]) } model RepairOrderAssignee { id String @id @default(uuid()) repairOrderId String userId String assignedAt DateTime @default(now()) // Relations repairOrder RepairOrder @relation(fields: [repairOrderId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([repairOrderId, userId]) } // ============================================================================= // Выезды // ============================================================================= model Trip { id String @id @default(uuid()) contractorId String serviceObjectId String? description String? scheduledFor DateTime completedAt DateTime? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations contractor Contractor @relation(fields: [contractorId], references: [id]) serviceObject ServiceObject? @relation(fields: [serviceObjectId], references: [id]) @@index([scheduledFor]) } model ServiceObject { id String @id @default(uuid()) contractorId String name String address String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations contractor Contractor @relation(fields: [contractorId], references: [id]) trips Trip[] } // ============================================================================= // Калькуляции (MVP без денег) // ============================================================================= model Calculation { id String @id @default(uuid()) repairOrderId String @unique templateId String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations repairOrder RepairOrder @relation(fields: [repairOrderId], references: [id], onDelete: Cascade) template CalculationTemplate? @relation(fields: [templateId], references: [id]) items CalculationItem[] } model CalculationTemplate { id String @id @default(uuid()) contractorId String? name String isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations contractor Contractor? @relation(fields: [contractorId], references: [id]) calculations Calculation[] } model CalculationItem { id String @id @default(uuid()) calculationId String type String // 'WORK' or 'MATERIAL' name String quantity Float unit String // единицы измерения price Float? // отложено на будущее (MVP без денег) isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations calculation Calculation @relation(fields: [calculationId], references: [id], onDelete: Cascade) @@index([calculationId, type]) }