Initial commit: Helpdesk application setup
- Backend: Node.js/TypeScript with Prisma ORM - Frontend: Vite + TypeScript - Project configuration and documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
709
backend/prisma/schema.prisma
Normal file
709
backend/prisma/schema.prisma
Normal file
@@ -0,0 +1,709 @@
|
||||
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])
|
||||
}
|
||||
260
backend/prisma/seed.ts
Normal file
260
backend/prisma/seed.ts
Normal file
@@ -0,0 +1,260 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import bcrypt from 'bcryptjs';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function seed() {
|
||||
console.log('Seeding database...');
|
||||
|
||||
// ===== USER ROLES =====
|
||||
console.log('Creating user roles...');
|
||||
const roles = await Promise.all([
|
||||
prisma.userRole.upsert({
|
||||
where: { code: 'ROOT' },
|
||||
update: {},
|
||||
create: {
|
||||
code: 'ROOT',
|
||||
name: 'Root Správca',
|
||||
level: 1,
|
||||
order: 1,
|
||||
permissions: {
|
||||
projects: ['*'],
|
||||
tasks: ['*'],
|
||||
equipment: ['*'],
|
||||
rma: ['*'],
|
||||
customers: ['*'],
|
||||
settings: ['*'],
|
||||
users: ['*'],
|
||||
logs: ['*'],
|
||||
},
|
||||
},
|
||||
}),
|
||||
prisma.userRole.upsert({
|
||||
where: { code: 'ADMIN' },
|
||||
update: {},
|
||||
create: {
|
||||
code: 'ADMIN',
|
||||
name: 'Administrátor',
|
||||
level: 2,
|
||||
order: 2,
|
||||
permissions: {
|
||||
projects: ['create', 'read', 'update', 'delete', 'all'],
|
||||
tasks: ['create', 'read', 'update', 'delete', 'all'],
|
||||
equipment: ['create', 'read', 'update', 'delete', 'all'],
|
||||
rma: ['create', 'read', 'update', 'delete', 'approve'],
|
||||
customers: ['create', 'read', 'update', 'delete'],
|
||||
users: ['read'],
|
||||
},
|
||||
},
|
||||
}),
|
||||
prisma.userRole.upsert({
|
||||
where: { code: 'USER' },
|
||||
update: {},
|
||||
create: {
|
||||
code: 'USER',
|
||||
name: 'Používateľ',
|
||||
level: 3,
|
||||
order: 3,
|
||||
permissions: {
|
||||
projects: ['read', 'update'],
|
||||
tasks: ['create', 'read', 'update'],
|
||||
equipment: ['read', 'update'],
|
||||
rma: ['create', 'read', 'update'],
|
||||
customers: ['read'],
|
||||
},
|
||||
},
|
||||
}),
|
||||
prisma.userRole.upsert({
|
||||
where: { code: 'CUSTOMER' },
|
||||
update: {},
|
||||
create: {
|
||||
code: 'CUSTOMER',
|
||||
name: 'Zákazník',
|
||||
level: 4,
|
||||
order: 4,
|
||||
permissions: {
|
||||
projects: ['read'],
|
||||
tasks: ['read'],
|
||||
equipment: ['read'],
|
||||
rma: ['create', 'read'],
|
||||
},
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
// ===== EQUIPMENT TYPES =====
|
||||
console.log('Creating equipment types...');
|
||||
await prisma.equipmentType.createMany({
|
||||
skipDuplicates: true,
|
||||
data: [
|
||||
{ code: 'EPS', name: 'Elektrická požiarna signalizácia', color: '#3B82F6', order: 1 },
|
||||
{ code: 'HSP', name: 'Hasiaci systém', color: '#EF4444', order: 2 },
|
||||
{ code: 'CAMERA', name: 'Kamerový systém', color: '#10B981', order: 3 },
|
||||
{ code: 'ACCESS', name: 'Prístupový systém', color: '#F59E0B', order: 4 },
|
||||
{ code: 'OTHER', name: 'Iné zariadenie', color: '#6B7280', order: 5 },
|
||||
],
|
||||
});
|
||||
|
||||
// ===== REVISION TYPES =====
|
||||
console.log('Creating revision types...');
|
||||
await prisma.revisionType.createMany({
|
||||
skipDuplicates: true,
|
||||
data: [
|
||||
{ code: 'QUARTERLY', name: 'Štvrťročná revízia', intervalDays: 90, reminderDays: 14, color: '#FFA500', order: 1 },
|
||||
{ code: 'BIANNUAL', name: 'Polročná revízia', intervalDays: 180, reminderDays: 21, color: '#FBBF24', order: 2 },
|
||||
{ code: 'ANNUAL', name: 'Ročná revízia', intervalDays: 365, reminderDays: 30, color: '#DC2626', order: 3 },
|
||||
{ code: 'EMERGENCY', name: 'Mimoriadna revízia', intervalDays: 0, reminderDays: 0, color: '#DC2626', order: 4 },
|
||||
],
|
||||
});
|
||||
|
||||
// ===== RMA STATUSES =====
|
||||
console.log('Creating RMA statuses...');
|
||||
await prisma.rMAStatus.createMany({
|
||||
skipDuplicates: true,
|
||||
data: [
|
||||
{ code: 'NEW', name: 'Nová reklamácia', color: '#10B981', isInitial: true, canTransitionTo: ['IN_ASSESSMENT', 'REJECTED'], order: 1 },
|
||||
{ code: 'IN_ASSESSMENT', name: 'V posúdzovaní', color: '#F59E0B', canTransitionTo: ['APPROVED', 'REJECTED'], order: 2 },
|
||||
{ code: 'APPROVED', name: 'Schválená', color: '#3B82F6', canTransitionTo: ['IN_REPAIR', 'REPLACED', 'REFUNDED'], order: 3 },
|
||||
{ code: 'REJECTED', name: 'Zamietnutá', color: '#EF4444', isFinal: true, order: 4 },
|
||||
{ code: 'IN_REPAIR', name: 'V oprave', color: '#8B5CF6', canTransitionTo: ['REPAIRED', 'COMPLETED'], order: 5 },
|
||||
{ code: 'REPAIRED', name: 'Opravené', color: '#059669', canTransitionTo: ['COMPLETED'], order: 6 },
|
||||
{ code: 'REPLACED', name: 'Vymenené', color: '#059669', canTransitionTo: ['COMPLETED'], order: 7 },
|
||||
{ code: 'REFUNDED', name: 'Vrátené peniaze', color: '#059669', canTransitionTo: ['COMPLETED'], order: 8 },
|
||||
{ code: 'COMPLETED', name: 'Uzatvorená', color: '#059669', isFinal: true, order: 9 },
|
||||
],
|
||||
});
|
||||
|
||||
// ===== RMA SOLUTIONS =====
|
||||
console.log('Creating RMA solutions...');
|
||||
await prisma.rMASolution.createMany({
|
||||
skipDuplicates: true,
|
||||
data: [
|
||||
{ code: 'ASSESSMENT', name: 'Posúdzovanie', color: '#F59E0B', order: 1 },
|
||||
{ code: 'REPAIR', name: 'Oprava', color: '#3B82F6', order: 2 },
|
||||
{ code: 'REPLACEMENT', name: 'Výmena', color: '#10B981', order: 3 },
|
||||
{ code: 'REFUND', name: 'Vrátenie peňazí', color: '#8B5CF6', order: 4 },
|
||||
{ code: 'REJECTED', name: 'Zamietnutie', color: '#EF4444', order: 5 },
|
||||
{ code: 'OTHER', name: 'Iné riešenie', color: '#6B7280', order: 6 },
|
||||
],
|
||||
});
|
||||
|
||||
// ===== TASK STATUSES =====
|
||||
console.log('Creating task statuses...');
|
||||
await prisma.taskStatus.createMany({
|
||||
skipDuplicates: true,
|
||||
data: [
|
||||
{ code: 'NEW', name: 'Nová úloha', swimlaneColumn: 'NEW', color: '#10B981', isInitial: true, order: 1 },
|
||||
{ code: 'IN_PROGRESS', name: 'V riešení', swimlaneColumn: 'DOING', color: '#F59E0B', order: 2 },
|
||||
{ code: 'REVIEW', name: 'Na kontrolu', swimlaneColumn: 'DOING', color: '#8B5CF6', order: 3 },
|
||||
{ code: 'COMPLETED', name: 'Dokončená', swimlaneColumn: 'DONE', color: '#059669', isFinal: true, order: 4 },
|
||||
],
|
||||
});
|
||||
|
||||
// ===== PRIORITIES =====
|
||||
console.log('Creating priorities...');
|
||||
await prisma.priority.createMany({
|
||||
skipDuplicates: true,
|
||||
data: [
|
||||
{ code: 'LOW', name: 'Nízka priorita', color: '#10B981', level: 1, order: 1 },
|
||||
{ code: 'MEDIUM', name: 'Stredná priorita', color: '#F59E0B', level: 5, order: 2 },
|
||||
{ code: 'HIGH', name: 'Vysoká priorita', color: '#EF4444', level: 8, order: 3 },
|
||||
{ code: 'URGENT', name: 'Urgentná', color: '#DC2626', level: 10, order: 4 },
|
||||
],
|
||||
});
|
||||
|
||||
// ===== SYSTEM SETTINGS =====
|
||||
console.log('Creating system settings...');
|
||||
await prisma.systemSetting.createMany({
|
||||
skipDuplicates: true,
|
||||
data: [
|
||||
{
|
||||
key: 'REVISION_REMINDER_DAYS',
|
||||
value: 14,
|
||||
category: 'NOTIFICATIONS',
|
||||
label: 'Pripomenúť revíziu X dní dopredu',
|
||||
dataType: 'number',
|
||||
validation: { min: 1, max: 365 },
|
||||
},
|
||||
{
|
||||
key: 'RMA_NUMBER_FORMAT',
|
||||
value: 'RMA-{YYYY}{MM}{DD}{XXX}',
|
||||
category: 'RMA',
|
||||
label: 'Formát RMA čísla',
|
||||
dataType: 'string',
|
||||
},
|
||||
{
|
||||
key: 'RMA_CUSTOMER_REQUIRES_APPROVAL',
|
||||
value: true,
|
||||
category: 'RMA',
|
||||
label: 'Reklamácie od zákazníkov vyžadujú schválenie',
|
||||
dataType: 'boolean',
|
||||
},
|
||||
{
|
||||
key: 'ADMIN_NOTIFICATION_EMAILS',
|
||||
value: ['admin@firma.sk'],
|
||||
category: 'NOTIFICATIONS',
|
||||
label: 'Email adresy pre admin notifikácie',
|
||||
dataType: 'json',
|
||||
},
|
||||
{
|
||||
key: 'ENABLE_WEBSOCKET',
|
||||
value: false,
|
||||
category: 'GENERAL',
|
||||
label: 'Zapnúť real-time aktualizácie (WebSocket)',
|
||||
dataType: 'boolean',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// ===== DEMO USERS =====
|
||||
console.log('Creating demo users...');
|
||||
const rootRole = roles.find(r => r.code === 'ROOT');
|
||||
const adminRole = roles.find(r => r.code === 'ADMIN');
|
||||
const userRole = roles.find(r => r.code === 'USER');
|
||||
|
||||
if (rootRole && adminRole && userRole) {
|
||||
await prisma.user.upsert({
|
||||
where: { email: 'root@helpdesk.sk' },
|
||||
update: { password: await bcrypt.hash('root123', 10) },
|
||||
create: {
|
||||
email: 'root@helpdesk.sk',
|
||||
password: await bcrypt.hash('root123', 10),
|
||||
name: 'Root Admin',
|
||||
roleId: rootRole.id,
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.user.upsert({
|
||||
where: { email: 'admin@helpdesk.sk' },
|
||||
update: { password: await bcrypt.hash('admin123', 10) },
|
||||
create: {
|
||||
email: 'admin@helpdesk.sk',
|
||||
password: await bcrypt.hash('admin123', 10),
|
||||
name: 'Peter Admin',
|
||||
roleId: adminRole.id,
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.user.upsert({
|
||||
where: { email: 'user@helpdesk.sk' },
|
||||
update: { password: await bcrypt.hash('user123', 10) },
|
||||
create: {
|
||||
email: 'user@helpdesk.sk',
|
||||
password: await bcrypt.hash('user123', 10),
|
||||
name: 'Martin Používateľ',
|
||||
roleId: userRole.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Seeding completed!');
|
||||
}
|
||||
|
||||
seed()
|
||||
.catch((error) => {
|
||||
console.error('Seeding failed:', error);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
Reference in New Issue
Block a user