- Backend: Node.js/TypeScript with Prisma ORM - Frontend: Vite + TypeScript - Project configuration and documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
710 lines
16 KiB
Plaintext
710 lines
16 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// ==================== USER ROLES (dynamicke) ====================
|
|
|
|
model UserRole {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
description String?
|
|
|
|
permissions Json
|
|
|
|
level Int
|
|
order Int @default(0)
|
|
active Boolean @default(true)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
users User[]
|
|
|
|
@@index([active])
|
|
@@index([level])
|
|
}
|
|
|
|
// ==================== USERS ====================
|
|
|
|
model User {
|
|
id String @id @default(cuid())
|
|
email String @unique
|
|
password String
|
|
name String
|
|
|
|
roleId String
|
|
role UserRole @relation(fields: [roleId], references: [id])
|
|
|
|
active Boolean @default(true)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
ownedProjects Project[] @relation("ProjectOwner")
|
|
assignedProjects ProjectMember[]
|
|
createdTasks Task[] @relation("TaskCreator")
|
|
assignedTasks TaskAssignee[]
|
|
reminders Reminder[]
|
|
activityLogs ActivityLog[]
|
|
|
|
createdEquipment Equipment[] @relation("EquipmentCreator")
|
|
performedRevisions Revision[]
|
|
uploadedEquipmentFiles EquipmentAttachment[]
|
|
|
|
assignedRMAs RMA[] @relation("RMAAssignee")
|
|
createdRMAs RMA[] @relation("RMACreator")
|
|
approvedRMAs RMA[] @relation("RMAApprover")
|
|
rmaAttachments RMAAttachment[]
|
|
rmaStatusChanges RMAStatusHistory[]
|
|
rmaComments RMAComment[]
|
|
taskComments Comment[]
|
|
|
|
createdCustomers Customer[]
|
|
|
|
@@index([email])
|
|
@@index([roleId])
|
|
@@index([active])
|
|
}
|
|
|
|
// ==================== CONFIGURATION TABLES ====================
|
|
|
|
model EquipmentType {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
description String?
|
|
color String?
|
|
icon String?
|
|
order Int @default(0)
|
|
active Boolean @default(true)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
equipment Equipment[]
|
|
|
|
@@index([active])
|
|
@@index([order])
|
|
}
|
|
|
|
model RevisionType {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
intervalDays Int
|
|
reminderDays Int @default(14)
|
|
color String?
|
|
description String?
|
|
order Int @default(0)
|
|
active Boolean @default(true)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
revisions Revision[]
|
|
|
|
@@index([active])
|
|
@@index([order])
|
|
}
|
|
|
|
model RMAStatus {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
description String?
|
|
color String?
|
|
icon String?
|
|
order Int @default(0)
|
|
|
|
isInitial Boolean @default(false)
|
|
isFinal Boolean @default(false)
|
|
canTransitionTo Json?
|
|
|
|
active Boolean @default(true)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
rmas RMA[]
|
|
|
|
@@index([active])
|
|
@@index([order])
|
|
@@index([isInitial])
|
|
@@index([isFinal])
|
|
}
|
|
|
|
model RMASolution {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
description String?
|
|
color String?
|
|
order Int @default(0)
|
|
active Boolean @default(true)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
rmas RMA[]
|
|
|
|
@@index([active])
|
|
@@index([order])
|
|
}
|
|
|
|
model TaskStatus {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
description String?
|
|
color String?
|
|
icon String?
|
|
order Int @default(0)
|
|
|
|
swimlaneColumn String?
|
|
|
|
isInitial Boolean @default(false)
|
|
isFinal Boolean @default(false)
|
|
canTransitionTo Json?
|
|
|
|
active Boolean @default(true)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tasks Task[]
|
|
projects Project[]
|
|
|
|
@@index([active])
|
|
@@index([swimlaneColumn])
|
|
@@index([order])
|
|
}
|
|
|
|
model Priority {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
description String?
|
|
color String?
|
|
icon String?
|
|
level Int
|
|
order Int @default(0)
|
|
active Boolean @default(true)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tasks Task[]
|
|
|
|
@@index([active])
|
|
@@index([level])
|
|
@@index([order])
|
|
}
|
|
|
|
model Tag {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
description String?
|
|
color String?
|
|
|
|
entityType String
|
|
|
|
order Int @default(0)
|
|
active Boolean @default(true)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
projectTags ProjectTag[]
|
|
taskTags TaskTag[]
|
|
equipmentTags EquipmentTag[]
|
|
rmaTags RMATag[]
|
|
|
|
@@index([entityType])
|
|
@@index([active])
|
|
}
|
|
|
|
model SystemSetting {
|
|
id String @id @default(cuid())
|
|
|
|
key String @unique
|
|
value Json
|
|
|
|
category String
|
|
label String
|
|
description String?
|
|
dataType String
|
|
|
|
validation Json?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([category])
|
|
}
|
|
|
|
// ==================== CUSTOMERS ====================
|
|
|
|
model Customer {
|
|
id String @id @default(cuid())
|
|
|
|
name String
|
|
address String?
|
|
email String?
|
|
phone String?
|
|
ico String?
|
|
dic String?
|
|
icdph String?
|
|
|
|
contactPerson String?
|
|
contactEmail String?
|
|
contactPhone String?
|
|
|
|
externalId String? @unique
|
|
externalSource String?
|
|
|
|
notes String?
|
|
active Boolean @default(true)
|
|
|
|
createdById String
|
|
createdBy User @relation(fields: [createdById], references: [id])
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
projects Project[]
|
|
equipment Equipment[]
|
|
rmas RMA[]
|
|
|
|
@@index([name])
|
|
@@index([ico])
|
|
@@index([externalId])
|
|
@@index([active])
|
|
}
|
|
|
|
// ==================== PROJECTS ====================
|
|
|
|
model Project {
|
|
id String @id @default(cuid())
|
|
name String
|
|
description String?
|
|
|
|
customerId String?
|
|
customer Customer? @relation(fields: [customerId], references: [id])
|
|
|
|
ownerId String
|
|
owner User @relation("ProjectOwner", fields: [ownerId], references: [id])
|
|
|
|
statusId String
|
|
status TaskStatus @relation(fields: [statusId], references: [id])
|
|
|
|
softDeadline DateTime?
|
|
hardDeadline DateTime?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
completedAt DateTime?
|
|
|
|
tasks Task[]
|
|
members ProjectMember[]
|
|
tags ProjectTag[]
|
|
|
|
@@index([ownerId])
|
|
@@index([statusId])
|
|
@@index([customerId])
|
|
@@index([hardDeadline])
|
|
}
|
|
|
|
model ProjectMember {
|
|
id String @id @default(cuid())
|
|
projectId String
|
|
userId String
|
|
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
addedAt DateTime @default(now())
|
|
|
|
@@unique([projectId, userId])
|
|
@@index([projectId])
|
|
@@index([userId])
|
|
}
|
|
|
|
model ProjectTag {
|
|
projectId String
|
|
tagId String
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([projectId, tagId])
|
|
}
|
|
|
|
// ==================== TASKS ====================
|
|
|
|
model Task {
|
|
id String @id @default(cuid())
|
|
title String
|
|
description String?
|
|
|
|
projectId String?
|
|
project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
|
|
parentId String?
|
|
parent Task? @relation("SubTasks", fields: [parentId], references: [id], onDelete: Cascade)
|
|
subTasks Task[] @relation("SubTasks")
|
|
|
|
statusId String
|
|
status TaskStatus @relation(fields: [statusId], references: [id])
|
|
|
|
priorityId String
|
|
priority Priority @relation(fields: [priorityId], references: [id])
|
|
|
|
deadline DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
completedAt DateTime?
|
|
|
|
createdById String
|
|
createdBy User @relation("TaskCreator", fields: [createdById], references: [id])
|
|
|
|
assignees TaskAssignee[]
|
|
reminders Reminder[]
|
|
comments Comment[]
|
|
tags TaskTag[]
|
|
|
|
@@index([projectId])
|
|
@@index([parentId])
|
|
@@index([statusId])
|
|
@@index([priorityId])
|
|
@@index([deadline])
|
|
@@index([createdById])
|
|
}
|
|
|
|
model TaskAssignee {
|
|
id String @id @default(cuid())
|
|
taskId String
|
|
userId String
|
|
|
|
task Task @relation(fields: [taskId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
assignedAt DateTime @default(now())
|
|
|
|
@@unique([taskId, userId])
|
|
@@index([taskId])
|
|
@@index([userId])
|
|
}
|
|
|
|
model TaskTag {
|
|
taskId String
|
|
tagId String
|
|
task Task @relation(fields: [taskId], references: [id], onDelete: Cascade)
|
|
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([taskId, tagId])
|
|
}
|
|
|
|
model Reminder {
|
|
id String @id @default(cuid())
|
|
taskId String
|
|
userId String
|
|
|
|
task Task @relation(fields: [taskId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
remindAt DateTime
|
|
snoozedUntil DateTime?
|
|
dismissed Boolean @default(false)
|
|
|
|
message String?
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([userId, remindAt])
|
|
@@index([taskId])
|
|
}
|
|
|
|
model Comment {
|
|
id String @id @default(cuid())
|
|
taskId String
|
|
userId String
|
|
|
|
task Task @relation(fields: [taskId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id])
|
|
|
|
content String
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([taskId])
|
|
@@index([userId])
|
|
@@index([createdAt])
|
|
}
|
|
|
|
// ==================== EQUIPMENT MANAGEMENT ====================
|
|
|
|
model Equipment {
|
|
id String @id @default(cuid())
|
|
|
|
name String
|
|
|
|
typeId String
|
|
type EquipmentType @relation(fields: [typeId], references: [id])
|
|
|
|
brand String?
|
|
model String?
|
|
|
|
customerId String?
|
|
customer Customer? @relation(fields: [customerId], references: [id])
|
|
|
|
address String
|
|
location String?
|
|
|
|
partNumber String?
|
|
serialNumber String?
|
|
|
|
installDate DateTime?
|
|
warrantyEnd DateTime?
|
|
warrantyStatus String?
|
|
|
|
description String?
|
|
notes String?
|
|
|
|
active Boolean @default(true)
|
|
|
|
createdById String
|
|
createdBy User @relation("EquipmentCreator", fields: [createdById], references: [id])
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
revisions Revision[]
|
|
attachments EquipmentAttachment[]
|
|
tags EquipmentTag[]
|
|
|
|
@@index([typeId])
|
|
@@index([customerId])
|
|
@@index([warrantyEnd])
|
|
@@index([active])
|
|
@@index([createdById])
|
|
}
|
|
|
|
model Revision {
|
|
id String @id @default(cuid())
|
|
|
|
equipmentId String
|
|
equipment Equipment @relation(fields: [equipmentId], references: [id], onDelete: Cascade)
|
|
|
|
typeId String
|
|
type RevisionType @relation(fields: [typeId], references: [id])
|
|
|
|
performedDate DateTime
|
|
nextDueDate DateTime?
|
|
|
|
performedById String
|
|
performedBy User @relation(fields: [performedById], references: [id])
|
|
|
|
findings String?
|
|
result String?
|
|
notes String?
|
|
|
|
reminderSent Boolean @default(false)
|
|
reminderDate DateTime?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([equipmentId])
|
|
@@index([typeId])
|
|
@@index([performedById])
|
|
@@index([nextDueDate])
|
|
@@index([reminderDate])
|
|
}
|
|
|
|
model EquipmentAttachment {
|
|
id String @id @default(cuid())
|
|
equipmentId String
|
|
equipment Equipment @relation(fields: [equipmentId], references: [id], onDelete: Cascade)
|
|
|
|
filename String
|
|
filepath String
|
|
mimetype String
|
|
size Int
|
|
|
|
uploadedById String
|
|
uploadedBy User @relation(fields: [uploadedById], references: [id])
|
|
|
|
uploadedAt DateTime @default(now())
|
|
|
|
@@index([equipmentId])
|
|
}
|
|
|
|
model EquipmentTag {
|
|
equipmentId String
|
|
tagId String
|
|
equipment Equipment @relation(fields: [equipmentId], references: [id], onDelete: Cascade)
|
|
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([equipmentId, tagId])
|
|
}
|
|
|
|
// ==================== RMA (REKLAMACIE) ====================
|
|
|
|
model RMA {
|
|
id String @id @default(cuid())
|
|
|
|
rmaNumber String @unique
|
|
|
|
customerId String?
|
|
customer Customer? @relation(fields: [customerId], references: [id])
|
|
|
|
customerName String?
|
|
customerAddress String?
|
|
customerEmail String?
|
|
customerPhone String?
|
|
customerICO String?
|
|
submittedBy String
|
|
|
|
productName String
|
|
invoiceNumber String?
|
|
purchaseDate DateTime?
|
|
productNumber String?
|
|
serialNumber String?
|
|
accessories String?
|
|
|
|
issueDescription String
|
|
|
|
statusId String
|
|
status RMAStatus @relation(fields: [statusId], references: [id])
|
|
|
|
proposedSolutionId String?
|
|
proposedSolution RMASolution? @relation(fields: [proposedSolutionId], references: [id])
|
|
|
|
requiresApproval Boolean @default(false)
|
|
approvedById String?
|
|
approvedBy User? @relation("RMAApprover", fields: [approvedById], references: [id])
|
|
approvedAt DateTime?
|
|
|
|
receivedDate DateTime?
|
|
receivedLocation String?
|
|
internalNotes String?
|
|
|
|
resolutionDate DateTime?
|
|
resolutionNotes String?
|
|
|
|
assignedToId String?
|
|
assignedTo User? @relation("RMAAssignee", fields: [assignedToId], references: [id])
|
|
|
|
createdById String
|
|
createdBy User @relation("RMACreator", fields: [createdById], references: [id])
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
closedAt DateTime?
|
|
|
|
attachments RMAAttachment[]
|
|
statusHistory RMAStatusHistory[]
|
|
comments RMAComment[]
|
|
tags RMATag[]
|
|
|
|
@@index([rmaNumber])
|
|
@@index([customerId])
|
|
@@index([statusId])
|
|
@@index([proposedSolutionId])
|
|
@@index([assignedToId])
|
|
@@index([createdById])
|
|
@@index([purchaseDate])
|
|
@@index([receivedDate])
|
|
}
|
|
|
|
model RMAAttachment {
|
|
id String @id @default(cuid())
|
|
rmaId String
|
|
rma RMA @relation(fields: [rmaId], references: [id], onDelete: Cascade)
|
|
|
|
filename String
|
|
filepath String
|
|
mimetype String
|
|
size Int
|
|
|
|
uploadedById String
|
|
uploadedBy User @relation(fields: [uploadedById], references: [id])
|
|
|
|
uploadedAt DateTime @default(now())
|
|
|
|
@@index([rmaId])
|
|
}
|
|
|
|
model RMAStatusHistory {
|
|
id String @id @default(cuid())
|
|
rmaId String
|
|
rma RMA @relation(fields: [rmaId], references: [id], onDelete: Cascade)
|
|
|
|
fromStatusId String?
|
|
toStatusId String
|
|
|
|
changedById String
|
|
changedBy User @relation(fields: [changedById], references: [id])
|
|
|
|
notes String?
|
|
changedAt DateTime @default(now())
|
|
|
|
@@index([rmaId])
|
|
@@index([changedAt])
|
|
}
|
|
|
|
model RMAComment {
|
|
id String @id @default(cuid())
|
|
rmaId String
|
|
rma RMA @relation(fields: [rmaId], references: [id], onDelete: Cascade)
|
|
|
|
content String
|
|
|
|
userId String
|
|
user User @relation(fields: [userId], references: [id])
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([rmaId])
|
|
@@index([createdAt])
|
|
}
|
|
|
|
model RMATag {
|
|
rmaId String
|
|
tagId String
|
|
rma RMA @relation(fields: [rmaId], references: [id], onDelete: Cascade)
|
|
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([rmaId, tagId])
|
|
}
|
|
|
|
// ==================== ACTIVITY LOG ====================
|
|
|
|
model ActivityLog {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
user User @relation(fields: [userId], references: [id])
|
|
|
|
action String
|
|
entity String
|
|
entityId String
|
|
|
|
changes Json?
|
|
ipAddress String?
|
|
userAgent String?
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([userId])
|
|
@@index([entity, entityId])
|
|
@@index([createdAt])
|
|
}
|