// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema // Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init generator client { provider = "prisma-client" output = "../generated/prisma" } datasource db { provider = "postgresql" } model Category { id BigInt @id @default(autoincrement()) name String @unique @db.VarChar(100) description String? tickets Ticket[] @@map("categories") } model Role { id BigInt @id @default(autoincrement()) name String @unique @db.VarChar(50) description String? users User[] @@map("roles") } model User { id BigInt @id @default(autoincrement()) external_uid String @unique @db.VarChar(255) role_id BigInt is_active Boolean @default(true) created_at DateTime @default(now()) @db.Timestamptz role Role @relation(fields: [role_id], references: [id]) tickets_created Ticket[] @relation("CreatedBy") tickets_assigned Ticket[] @relation("AssignedTo") messages TicketMessage[] attachments_uploaded TicketAttachment[] invitations_sent TicketInvitation[] @relation("Inviter") invitations_received TicketInvitation[] @relation("Invitee") participants TicketParticipant[] @relation("Participant") participants_added TicketParticipant[] @relation("AddedBy") status_history_changed TicketStatusHistory[] @@index([external_uid], name: "idx_users_external_uid") @@map("users") } model Ticket { id BigInt @id @default(autoincrement()) title String @db.VarChar(255) description String? status String @db.VarChar(30) priority String? @db.VarChar(30) category_id BigInt? created_by_user_id BigInt assigned_to_user_id BigInt? created_at DateTime @default(now()) @db.Timestamptz updated_at DateTime @default(now()) @db.Timestamptz closed_at DateTime? @db.Timestamptz /// Número de ticket legible para usuarios y APIs públicas (formato: TCK-YYYY-NNNNN). Este identificador se usa en lugar del ID interno en todas las comunicaciones externas. ticket_number String @unique @db.VarChar(30) category Category? @relation(fields: [category_id], references: [id]) created_by User @relation("CreatedBy", fields: [created_by_user_id], references: [id]) assigned_to User? @relation("AssignedTo", fields: [assigned_to_user_id], references: [id]) messages TicketMessage[] attachments TicketAttachment[] invitations TicketInvitation[] participants TicketParticipant[] status_history TicketStatusHistory[] @@index([assigned_to_user_id], name: "idx_tickets_assigned_to") @@index([created_at], name: "idx_tickets_created_at") @@index([created_by_user_id], name: "idx_tickets_created_by") @@index([status], name: "idx_tickets_status") @@index([ticket_number], name: "idx_tickets_ticket_number") @@map("tickets") } model TicketMessage { id BigInt @id @default(autoincrement()) ticket_id BigInt author_id BigInt message String is_internal Boolean @default(false) created_at DateTime @default(now()) @db.Timestamptz ticket Ticket @relation(fields: [ticket_id], references: [id], onDelete: Cascade) author User @relation(fields: [author_id], references: [id]) attachments TicketAttachment[] @@index([ticket_id], name: "idx_messages_ticket_id") @@map("ticket_messages") } model TicketAttachment { id BigInt @id @default(autoincrement()) ticket_id BigInt message_id BigInt? uploaded_by BigInt file_name String? @db.VarChar(255) file_url String file_size BigInt? created_at DateTime @default(now()) @db.Timestamptz ticket Ticket @relation(fields: [ticket_id], references: [id], onDelete: Cascade) message TicketMessage? @relation(fields: [message_id], references: [id]) uploader User @relation(fields: [uploaded_by], references: [id]) @@map("ticket_attachments") } /// Invitaciones pendientes, aceptadas o rechazadas para unirse a un ticket model TicketInvitation { id BigInt @id @default(autoincrement()) ticket_id BigInt inviter_id BigInt invitee_id BigInt /// Estado de la invitación: pending, accepted, rejected, cancelled status String @default("pending") @db.VarChar(20) message String? created_at DateTime @default(now()) @db.Timestamptz responded_at DateTime? @db.Timestamptz ticket Ticket @relation(fields: [ticket_id], references: [id], onDelete: Cascade) inviter User @relation("Inviter", fields: [inviter_id], references: [id]) invitee User @relation("Invitee", fields: [invitee_id], references: [id]) @@unique([ticket_id, invitee_id, status], name: "unique_pending_invitation") @@index([created_at], name: "idx_invitations_created_at") @@index([invitee_id], name: "idx_invitations_invitee_id") @@index([inviter_id], name: "idx_invitations_inviter_id") @@index([status], name: "idx_invitations_status") @@index([ticket_id], name: "idx_invitations_ticket_id") @@map("ticket_invitations") } /// Usuarios que tienen acceso a un ticket específico model TicketParticipant { id BigInt @id @default(autoincrement()) ticket_id BigInt user_id BigInt added_by BigInt /// Método de adición: creator, invitation, direct_add, assignment, staff_access added_via String @db.VarChar(20) can_edit Boolean @default(false) can_comment Boolean @default(true) joined_at DateTime @default(now()) @db.Timestamptz ticket Ticket @relation(fields: [ticket_id], references: [id], onDelete: Cascade) user User @relation("Participant", fields: [user_id], references: [id]) added_by_user User @relation("AddedBy", fields: [added_by], references: [id]) @@unique([ticket_id, user_id]) @@index([added_by], name: "idx_participants_added_by") @@index([ticket_id], name: "idx_participants_ticket_id") @@index([user_id], name: "idx_participants_user_id") @@map("ticket_participants") } model TicketStatusHistory { id BigInt @id @default(autoincrement()) ticket_id BigInt old_status String? @db.VarChar(30) new_status String @db.VarChar(30) changed_by BigInt changed_at DateTime @default(now()) @db.Timestamptz ticket Ticket @relation(fields: [ticket_id], references: [id], onDelete: Cascade) changed_by_user User @relation(fields: [changed_by], references: [id]) @@index([ticket_id], name: "idx_history_ticket_id") @@map("ticket_status_history") }