canina/backend/prisma/schema.prisma
parsa aghaei 2fca778930
All checks were successful
Deploy Canina / deploy (push) Successful in 1m48s
feat: complete payment retry, reviews system, catalog mode enforcement, and UI text defaults
2026-08-17 09:01:33 +03:30

699 lines
27 KiB
Plaintext

generator client {
provider = "prisma-client-js"
binaryTargets = ["native", "linux-musl-openssl-3.0.x"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(uuid()) @db.Uuid
firstName String @map("first_name") @db.VarChar(100)
lastName String @map("last_name") @db.VarChar(100)
email String? @unique @db.VarChar(150)
mobile String @unique @db.VarChar(15)
password String? @db.VarChar(255)
role String @default("User_PetOwner") @db.VarChar(30)
walletBalance Decimal @default(0.00) @map("wallet_balance") @db.Decimal(15, 2)
charityDonationTotal Decimal @default(0.00) @map("charity_donation_total") @db.Decimal(15, 2)
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
updatedAt DateTime @default(now()) @map("updated_at") @db.Timestamptz()
addresses UserAddress[]
walletTransactions WalletTransaction[]
pets Pet[]
orders Order[]
blogs Blog[]
prescriptions Prescription[]
partnerAccount PartnerAccount?
paymentTransactions PaymentTransaction[]
tickets Ticket[]
reviews ProductReview[]
@@map("users")
}
model UserAddress {
id String @id @default(uuid()) @db.Uuid
userId String @map("user_id") @db.Uuid
title String @db.VarChar(100)
receptorName String @map("receptor_name") @db.VarChar(150)
phone String @db.VarChar(15)
province String @db.VarChar(100)
city String @db.VarChar(100)
detail String @db.Text
zipCode String @map("zip_code") @db.VarChar(10)
isDefault Boolean @default(false) @map("is_default")
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@map("user_addresses")
}
model WalletTransaction {
id String @id @default(uuid()) @db.Uuid
userId String @map("user_id") @db.Uuid
amount Decimal @db.Decimal(15, 2)
type String @db.VarChar(20) // deposit, withdrawal
status String @db.VarChar(20) // pending, completed, failed
transactionReference String? @unique @map("transaction_reference") @db.VarChar(100)
description String? @db.Text
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("wallet_transactions")
}
model Media {
id String @id @default(uuid()) @db.Uuid
filename String @db.VarChar(200)
url String @db.Text
mimetype String @db.VarChar(50)
size Int
altText String? @map("alt_text") @db.VarChar(250)
title String? @db.VarChar(250)
description String? @db.Text
caption String? @db.Text
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
@@map("media")
}
model Category {
id String @id @default(uuid()) @db.Uuid
name String @db.VarChar(150)
slug String @unique @db.VarChar(150)
description String? @db.Text
parentId String? @map("parent_id") @db.Uuid
metaTitle String? @map("meta_title") @db.VarChar(200)
metaDescription String? @map("meta_description") @db.Text
keywords String? @db.Text
imageUrl String? @map("image_url") @db.Text
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
parent Category? @relation("SubCategories", fields: [parentId], references: [id])
children Category[] @relation("SubCategories")
products Product[]
@@map("categories")
}
model Blog {
id String @id @default(uuid()) @db.Uuid
title String @db.VarChar(200)
slug String @unique @db.VarChar(200)
content String @db.Text
authorId String @map("author_id") @db.Uuid
imageUrl String? @map("image_url") @db.Text
metaTitle String? @map("meta_title") @db.VarChar(200)
metaDescription String? @map("meta_description") @db.Text
keywords String? @db.Text
isPublished Boolean @default(true) @map("is_published")
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
updatedAt DateTime @default(now()) @map("updated_at") @db.Timestamptz()
author User @relation(fields: [authorId], references: [id])
@@map("blogs")
}
model Product {
id String @id @default(uuid()) @db.Uuid
artNo String @unique @map("art_no") @db.VarChar(20)
barcode String? @unique @db.VarChar(30)
slug String @unique @db.VarChar(150)
productGroup String? @map("product_group") @db.VarChar(100)
nameFa String @map("name_fa") @db.VarChar(200)
nameEn String @map("name_en") @db.VarChar(200)
scientificTagline String? @map("scientific_tagline") @db.VarChar(250)
description String @db.Text
shortDescription String? @map("short_description") @db.Text
ingredients String? @db.Text
categoryId String @map("category_id") @db.Uuid
categorySlug String @map("category_slug") @db.VarChar(100)
priceValue Decimal @map("price_value") @db.Decimal(15, 2)
wholesalePrice Decimal? @map("wholesale_price") @db.Decimal(15, 2)
requiresRx Boolean @default(false) @map("requires_rx")
buyPrice Decimal @default(0) @map("buy_price") @db.Decimal(15, 2)
priceDisplay String @map("price_display") @db.VarChar(50)
unit String @db.VarChar(50)
packageSize Decimal @map("package_size") @db.Decimal(10, 2)
dosageLogic String? @map("dosage_logic") @db.Text
dosageConfig Json? @map("dosage_config")
suitableFor String @map("suitable_for") @db.VarChar(15) // سگ, گربه, هر دو
imageUrl String @map("image_url") @db.Text
images String[] @default([])
podcastUrl String? @map("podcast_url") @db.Text
videoUrl String? @map("video_url") @db.Text
pdfUrl String? @map("pdf_url") @db.Text
metaTitle String? @map("meta_title") @db.VarChar(200)
metaDescription String? @map("meta_description") @db.Text
canonicalUrl String? @map("canonical_url") @db.Text
keywords String? @db.Text
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
category Category @relation(fields: [categoryId], references: [id])
ingredientList ProductIngredient[]
symptoms ProductSymptom[]
reminders Reminder[]
orderItems OrderItem[]
advisorRules SmartAdvisorRule[]
inventoryReservations InventoryReservation[]
reviews ProductReview[]
@@index([categorySlug])
@@index([suitableFor])
@@index([productGroup])
@@index([requiresRx])
@@index([categorySlug, suitableFor])
@@map("products")
}
model Doctor {
id String @id @default(uuid()) @db.Uuid
name String @db.VarChar(150)
title String @db.VarChar(150)
avatarUrl String? @map("avatar_url") @db.Text
bio String? @db.Text
clinic String? @db.VarChar(200)
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
@@map("doctors")
}
model ProductIngredient {
productId String @map("product_id") @db.Uuid
ingredient String @db.VarChar(150)
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
@@id([productId, ingredient])
@@map("product_ingredients")
}
model ProductSymptom {
productId String @map("product_id") @db.Uuid
symptom String @db.VarChar(150)
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
@@id([productId, symptom])
@@map("product_symptoms")
}
model Pet {
id String @id @default(uuid()) @db.Uuid
userId String @map("user_id") @db.Uuid
name String @db.VarChar(100)
type String @db.VarChar(10) // سگ, گربه
breed String @db.VarChar(100)
age Int
weight Decimal @db.Decimal(5, 2)
activityLevel String @map("activity_level") @db.VarChar(15) // کم, متوسط, زیاد
imageUrl String? @map("image_url") @db.Text
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
medicalConditions PetMedicalCondition[]
reminders Reminder[]
healthLogs HealthLog[]
prescriptions Prescription[]
tickets Ticket[]
@@map("pets")
}
model PetMedicalCondition {
petId String @map("pet_id") @db.Uuid
condition String @db.VarChar(150)
pet Pet @relation(fields: [petId], references: [id], onDelete: Cascade)
@@id([petId, condition])
@@map("pet_medical_conditions")
}
model Reminder {
id String @id @default(uuid()) @db.Uuid
petId String @map("pet_id") @db.Uuid
productId String? @map("product_id") @db.Uuid
title String @db.VarChar(150)
time String @db.VarChar(5) // 08:30
frequency String @db.VarChar(20) // روزانه, هفتگی
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
pet Pet @relation(fields: [petId], references: [id], onDelete: Cascade)
product Product? @relation(fields: [productId], references: [id], onDelete: SetNull)
completions ReminderCompletion[]
@@index([petId])
@@map("reminders")
}
model ReminderCompletion {
id String @id @default(uuid()) @db.Uuid
reminderId String @map("reminder_id") @db.Uuid
completedDate DateTime @map("completed_date") @db.Date
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
reminder Reminder @relation(fields: [reminderId], references: [id], onDelete: Cascade)
@@unique([reminderId, completedDate])
@@index([reminderId, completedDate])
@@map("reminder_completions")
}
model HealthLog {
id String @id @default(uuid()) @db.Uuid
petId String @map("pet_id") @db.Uuid
appetite String @db.VarChar(15)
energy String @db.VarChar(15)
digestion String @db.VarChar(15)
note String? @db.Text
loggedDate DateTime @default(now()) @map("logged_date") @db.Date
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
pet Pet @relation(fields: [petId], references: [id], onDelete: Cascade)
@@map("health_logs")
}
model Coupon {
id String @id @default(uuid()) @db.Uuid
code String @unique @db.VarChar(50)
type String @default("percent") @db.VarChar(20) // fixed, percent
value Decimal @db.Decimal(15, 2)
minCartValue Decimal? @map("min_cart_value") @db.Decimal(15, 2)
maxCartValue Decimal? @map("max_cart_value") @db.Decimal(15, 2)
maxUses Int? @map("max_uses")
usedCount Int @default(0) @map("used_count")
expiresAt DateTime? @map("expires_at") @db.Timestamptz()
isActive Boolean @default(true) @map("is_active")
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
orders Order[]
targets CouponTarget[]
@@map("coupons")
}
model CouponTarget {
id String @id @default(uuid()) @db.Uuid
couponId String @map("coupon_id") @db.Uuid
targetType String @map("target_type") @db.VarChar(50) // USER, PET, ROLE, PRODUCT, CATEGORY
targetId String @map("target_id") @db.VarChar(100) // UUID or role name
modifierType String @default("override") @map("modifier_type") @db.VarChar(20) // override, add, subtract
modifierValue Decimal? @map("modifier_value") @db.Decimal(15, 2)
coupon Coupon @relation(fields: [couponId], references: [id], onDelete: Cascade)
@@index([targetType, targetId])
@@map("coupon_targets")
}
model Order {
id String @id @default(uuid()) @db.Uuid
userId String @map("user_id") @db.Uuid
couponId String? @map("coupon_id") @db.Uuid
totalAmount Decimal @map("total_amount") @db.Decimal(15, 2)
charityDonation Decimal @default(0.00) @map("charity_donation") @db.Decimal(15, 2)
isRefill Boolean @default(false) @map("is_refill")
refillIntervalDays Int? @map("refill_interval_days")
status String @default("processing") @db.VarChar(30) // pending_payment, processing, shipped, delivered, cancelled
paymentMethod String? @default("card") @map("payment_method") @db.VarChar(30)
shippingAddress String? @map("shipping_address") @db.Text
trackingNumber String? @unique @map("tracking_number") @db.VarChar(100)
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
coupon Coupon? @relation(fields: [couponId], references: [id])
orderItems OrderItem[]
paymentTransactions PaymentTransaction[]
inventoryReservations InventoryReservation[]
@@map("orders")
}
model PaymentTransaction {
id String @id @default(uuid()) @db.Uuid
userId String @map("user_id") @db.Uuid
orderId String? @map("order_id") @db.Uuid
amount Decimal @db.Decimal(15, 2) // in Tomans
amountRials BigInt? @map("amount_rials")
gateway String @default("zibal") @db.VarChar(50)
trackId String? @unique @map("track_id") @db.VarChar(100)
refNumber String? @map("ref_number") @db.VarChar(100)
cardNumber String? @map("card_number") @db.VarChar(30)
hashedCardNumber String? @map("hashed_card_number") @db.VarChar(100)
status String @default("PENDING") @db.VarChar(30) // PENDING, PAID, FAILED, VERIFIED
resultCode Int? @map("result_code")
message String? @db.Text
description String? @db.Text
type String @default("ORDER") @db.VarChar(30) // ORDER, WALLET_TOPUP
ipAddress String? @map("ip_address") @db.VarChar(50)
userAgent String? @map("user_agent") @db.Text
rawRequest Json? @map("raw_request")
rawResponse Json? @map("raw_response")
paidAt DateTime? @map("paid_at") @db.Timestamptz()
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
updatedAt DateTime @default(now()) @updatedAt @map("updated_at") @db.Timestamptz()
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
order Order? @relation(fields: [orderId], references: [id], onDelete: SetNull)
@@index([userId])
@@index([orderId])
@@index([trackId])
@@map("payment_transactions")
}
model InventoryReservation {
id String @id @default(uuid()) @db.Uuid
orderId String @map("order_id") @db.Uuid
productId String @map("product_id") @db.Uuid
quantity Int @default(1)
expiresAt DateTime @map("expires_at") @db.Timestamptz()
status String @default("ACTIVE") @db.VarChar(20) // ACTIVE, CONSUMED, RELEASED
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
updatedAt DateTime @default(now()) @updatedAt @map("updated_at") @db.Timestamptz()
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
@@index([orderId])
@@index([productId])
@@index([status])
@@index([expiresAt])
@@map("inventory_reservations")
}
model OrderItem {
id String @id @default(uuid()) @db.Uuid
orderId String @map("order_id") @db.Uuid
productId String? @map("product_id") @db.Uuid
quantity Int
doseQty Decimal? @map("dose_qty") @db.Decimal(10, 2)
doseUnit String? @map("dose_unit") @db.VarChar(50)
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
product Product? @relation(fields: [productId], references: [id], onDelete: SetNull)
@@map("order_items")
}
model UiText {
key String @id @db.VarChar(100)
value String @db.Text
@@map("ui_texts")
}
model ScientificTerm {
key String @id @db.VarChar(100)
term String @db.VarChar(150)
definition String @db.Text
wikiId String @map("wiki_id") @db.VarChar(50)
metaTitle String? @map("meta_title") @db.VarChar(200)
metaDescription String? @map("meta_description") @db.Text
keywords String? @db.Text
@@map("scientific_terms")
}
model HeroBanner {
id String @id @default(uuid()) @db.Uuid
title String @db.VarChar(200)
subtitle String? @db.Text
imageUrl String @map("image_url") @db.Text
buttonText String? @map("button_text") @db.VarChar(100)
buttonLink String? @map("button_link") @db.Text
isActive Boolean @default(true) @map("is_active")
order Int @default(0)
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
@@map("hero_banners")
}
model VetTestimonial {
id String @id @default(uuid()) @db.Uuid
vetName String @map("vet_name") @db.VarChar(150)
clinicName String? @map("clinic_name") @db.VarChar(150)
imageUrl String? @map("image_url") @db.Text
quote String @db.Text
rating Int @default(5)
isActive Boolean @default(true) @map("is_active")
order Int @default(0)
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
@@map("vet_testimonials")
}
model SmartAdvisorRule {
id String @id @default(uuid()) @db.Uuid
condition String @db.VarChar(200)
targetPetType String? @map("target_pet_type") @db.VarChar(50)
recommendedProduct String @map("recommended_product_id") @db.Uuid
reason String @db.Text
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
product Product @relation(fields: [recommendedProduct], references: [id], onDelete: Cascade)
@@map("smart_advisor_rules")
}
model Video {
id String @id @default(uuid()) @db.Uuid
title String @db.VarChar(200)
doctor String @db.VarChar(150)
duration String @default("02:00") @db.VarChar(20)
thumbnail String? @db.Text
videoUrl String @map("video_url") @db.Text
description String? @db.Text
viewsCount Int @default(0) @map("views_count")
isFeatured Boolean @default(false) @map("is_featured")
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz()
@@map("videos")
}
model ContactSubmission {
id String @id @default(uuid()) @db.Uuid
name String @db.VarChar(100)
phone String @db.VarChar(20)
email String? @db.VarChar(150)
subject String? @db.VarChar(200)
message String @db.Text
status String @default("PENDING") @db.VarChar(20) // PENDING, IN_PROGRESS, RESOLVED
adminNotes String? @map("admin_notes") @db.Text
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
@@map("contact_submissions")
}
model ContactInfo {
id String @id @default(uuid()) @db.Uuid
key String @unique @db.VarChar(100)
title String @db.VarChar(200)
value String @db.Text
icon String? @db.VarChar(100)
order Int @default(0)
updatedAt DateTime @default(now()) @updatedAt @map("updated_at") @db.Timestamptz()
@@map("contact_info")
}
model Banner {
id String @id @default(uuid()) @db.Uuid
title String @db.VarChar(200)
subtitle String? @db.Text
imageUrl String @map("image_url") @db.Text
linkUrl String? @map("link_url") @db.Text
position String @default("home_hero") @db.VarChar(50)
isActive Boolean @default(true) @map("is_active")
order Int @default(0)
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz()
@@map("banners")
}
model Testimonial {
id String @id @default(uuid()) @db.Uuid
authorName String @map("author_name") @db.VarChar(150)
roleTitle String? @map("role_title") @db.VarChar(150)
avatarUrl String? @map("avatar_url") @db.Text
content String @db.Text
rating Int @default(5)
isFeatured Boolean @default(false) @map("is_featured")
isActive Boolean @default(true) @map("is_active")
order Int @default(0)
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz()
@@map("testimonials")
}
model Ingredient {
id String @id @default(uuid()) @db.Uuid
nameFa String @map("name_fa") @db.VarChar(150)
nameEn String @map("name_en") @db.VarChar(150)
slug String @unique @db.VarChar(150)
description String? @db.Text
scientificName String? @map("scientific_name") @db.VarChar(200)
imageUrl String? @map("image_url") @db.Text
benefits String[] @default([])
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz()
@@map("ingredients")
}
model Prescription {
id String @id @default(uuid()) @db.Uuid
userId String? @map("user_id") @db.Uuid
petId String? @map("pet_id") @db.Uuid
fileUrl String @map("file_url") @db.Text
status String @default("PENDING") @db.VarChar(30)
notes String? @db.Text
adminNotes String? @map("admin_notes") @db.Text
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz()
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
pet Pet? @relation(fields: [petId], references: [id], onDelete: SetNull)
@@index([userId])
@@map("prescriptions")
}
model B2BInquiry {
id String @id @default(uuid()) @db.Uuid
companyName String @map("company_name") @db.VarChar(200)
contactName String @map("contact_name") @db.VarChar(150)
email String @db.VarChar(150)
phone String @db.VarChar(20)
businessType String @map("business_type") @db.VarChar(50)
estimatedVolume String? @map("estimated_volume") @db.VarChar(100)
message String @db.Text
status String @default("PENDING") @db.VarChar(30)
adminNotes String? @map("admin_notes") @db.Text
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz()
@@map("b2b_inquiries")
}
model PartnerAccount {
id String @id @default(uuid()) @db.Uuid
userId String @unique @map("user_id") @db.Uuid
companyName String @map("company_name") @db.VarChar(200)
taxId String? @map("tax_id") @db.VarChar(50)
creditLimit Decimal @default(0.00) @map("credit_limit") @db.Decimal(15, 2)
discountTier String @default("STANDARD") @map("discount_tier") @db.VarChar(30)
status String @default("ACTIVE") @db.VarChar(30)
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz()
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("partner_accounts")
}
model Setting {
id String @id @default(uuid()) @db.Uuid
category String @db.VarChar(50)
key String @unique @db.VarChar(100)
value Json
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz()
@@index([category])
@@map("settings")
}
model SmsLog {
id String @id @default(uuid()) @db.Uuid
receptor String @db.VarChar(20)
type String @db.VarChar(50) // OTP, ORDER_CONFIRMATION, SHIPPING_TRACKING, B2B_NOTIFICATION, PET_CARE_REMINDER, TEST, GENERIC
patternId Int? @map("pattern_id")
args String[] @default([])
messageText String? @map("message_text") @db.Text
status String @db.VarChar(20) // SUCCESS, FAILED, DISABLED
recId String? @map("rec_id") @db.VarChar(50)
errorMessage String? @map("error_message") @db.Text
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
@@index([receptor])
@@index([type])
@@index([status])
@@index([createdAt])
@@map("sms_logs")
}
model Ticket {
id String @id @default(uuid()) @db.Uuid
ticketNumber String @unique @map("ticket_number") @db.VarChar(50)
userId String @map("user_id") @db.Uuid
petId String? @map("pet_id") @db.Uuid
subject String @db.VarChar(255)
category String @default("VET_CONSULTATION") @db.VarChar(50) // VET_CONSULTATION, ORDER_SUPPORT, PRODUCT_INQUIRY, GENERAL
priority String @default("MEDIUM") @db.VarChar(20) // LOW, MEDIUM, HIGH, URGENT
status String @default("OPEN") @db.VarChar(30) // OPEN, ANSWERED, IN_PROGRESS, CLOSED
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
updatedAt DateTime @default(now()) @updatedAt @map("updated_at") @db.Timestamptz()
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
pet Pet? @relation(fields: [petId], references: [id], onDelete: SetNull)
messages TicketMessage[]
@@index([userId])
@@index([status])
@@index([category])
@@index([createdAt])
@@map("tickets")
}
model TicketMessage {
id String @id @default(uuid()) @db.Uuid
ticketId String @map("ticket_id") @db.Uuid
senderId String? @map("sender_id") @db.Uuid
senderRole String @default("USER") @map("sender_role") @db.VarChar(30) // USER, ADMIN, VET_DOCTOR
senderName String @map("sender_name") @db.VarChar(100)
message String @db.Text
attachment String? @db.Text
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
@@index([ticketId])
@@index([createdAt])
@@map("ticket_messages")
}
model ProductReview {
id String @id @default(uuid()) @db.Uuid
productId String @map("product_id") @db.Uuid
userId String? @map("user_id") @db.Uuid
userName String @map("user_name") @db.VarChar(100)
userPhone String? @map("user_phone") @db.VarChar(20)
rating Int @default(5)
comment String @db.Text
status String @default("PENDING") @db.VarChar(20) // PENDING, APPROVED, REJECTED
adminReply String? @map("admin_reply") @db.Text
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz()
updatedAt DateTime @default(now()) @updatedAt @map("updated_at") @db.Timestamptz()
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
@@index([productId])
@@index([status])
@@index([createdAt])
@@map("product_reviews")
}