Files
2026-03-26 08:14:56 +03:30

683 lines
18 KiB
Plaintext

generator client {
provider = "prisma-client"
output = "../src/generated/prisma"
}
datasource db {
provider = "postgresql"
}
enum CaseStatus {
NEW
CONTACTED
DOCS_PENDING
REVIEWING
PRE_APPROVED
REJECTED
CLOSED
CONVERTED_TO_HIS
}
// enum DocumentType {
// PASSPORT
// MEDICAL_RECORD
// IMAGING
// LAB_RESULT
// OTHER
// }
enum InteractionType {
PHONE
WHATSAPP
EMAIL
SYSTEM
}
model Patient {
id String @id @default(uuid())
pid String @unique @db.VarChar(10)
// -------- Identity --------
firstName String @db.VarChar(100)
lastName String @db.VarChar(100)
birthDate DateTime?
sex Sex?
age Int?
// -------- Nationality --------
nationality Countries? @relation(fields: [nationalityId], references: [id])
nationalityId Int?
nationalityCode String? @db.Char(3)
passportCode String? @db.VarChar(20)
// -------- Contact --------
phone String? @db.VarChar(20)
email String? @db.VarChar(255)
preferredLanguage String? @db.VarChar(10)
// -------- Address --------
address String? @db.VarChar(500)
postalCode String? @db.VarChar(20)
// -------- System --------
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
// -------- Relations --------
cases OnlineCase[]
documents Document[]
// -------- Indexes & Constraints --------
@@unique([nationalityCode]) // کد ملی
@@unique([passportCode, nationalityId]) // پاسپورت
@@unique([phone])
@@unique([email])
@@unique([firstName, lastName, birthDate])
@@index([pid])
}
model Document {
id String @id @default(uuid())
caseId String?
patientId String?
uploadedById String?
type DocumentType
filename String
fileUrl String
fileKey String
mimeType String?
size Int?
checksum String?
status DocStatus @default(NEW)
is_deleted Boolean @default(false)
createdAt DateTime @default(now())
case OnlineCase? @relation(fields: [caseId], references: [id])
patient Patient? @relation(fields: [patientId], references: [id])
uploadedBy Staff? @relation(fields: [uploadedById], references: [id])
}
enum DocumentType {
MEDICAL_IMAGE
LAB_RESULT
PRESCRIPTION
PASSPORT
NATIONAL_ID
OTHER
OTHER_FILE
}
enum DocStatus {
NEW
PENDING_SCAN
SAFE
INFECTED
INVALID
}
enum Sex {
male
female
other
}
model OnlineCase {
id String @id @default(uuid())
patientId String
trackingCode String @unique
message String?
specialty String?
formData Json?
status CaseStatus @default(NEW)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
patient Patient @relation(fields: [patientId], references: [id])
documents Document[]
// interactions Interaction[]
reviews Review[]
statusHistory CaseStatusHistory[]
}
model Review {
id String @id @default(uuid())
caseId String
doctorId String?
createdAt DateTime @default(now())
deletedAt DateTime?
case OnlineCase @relation(fields: [caseId], references: [id])
doctor Staff? @relation(fields: [doctorId], references: [id])
translations ReviewTranslation[]
}
model ReviewTranslation {
id Int @id @default(autoincrement())
reviewId String
lang Language? @relation(fields: [lang_id], references: [id])
lang_id Int?
note String?
result String? // eligible, needs more docs, not eligible (می‌تونه ترجمه شود)
review Review @relation(fields: [reviewId], references: [id])
@@unique([reviewId, lang_id]) // هر Review در هر زبان فقط یک ترجمه دارد
}
model CaseStatusHistory {
id String @id @default(uuid())
caseId String
from CaseStatus?
to CaseStatus?
changedBy String?
createdAt DateTime @default(now())
case OnlineCase @relation(fields: [caseId], references: [id])
@@index([id, caseId])
}
model UploadSession {
id String @id @default(uuid())
uploadKey String @unique // path/key to store file on CDN (e.g. documents/{uuid}.pdf)
nonce String @unique
used Boolean @default(false)
createdById String? // user id
purpose String // "document" | "image"
allowedTypes String? // JSON string array
maxSize Int?
status String @default("PENDING")
createdAt DateTime @default(now())
expiresAt DateTime
// indexes
@@index([createdById])
@@index([status])
}
enum UploadStatus {
PENDING
UPLOADING
UPLOADED
VERIFIED
FAILED
EXPIRED
}
enum StaffRoles {
developer
admin
doctor
coordinator
}
model Staff {
id String @id @default(uuid())
username String @unique
password String
email String? @unique
role StaffRoles
is_verified Boolean @default(false)
send_notif_with_email Boolean @default(false)
resetPasswordToken String?
resetPasswordExpires DateTime?
status StaffStatus @default(ACTIVE)
trustScore Int @default(100)
strikes Int @default(0)
restrictions Restriction[]
violations Violation[]
documents Document[]
reviews Review[]
profilePicture Image? @relation(fields: [profilePictureID],references: [id])
profilePictureID Int?
translations StaffTranslation[]
tokens RefreshToken[]
}
enum StaffStatus {
ACTIVE
WARNED
RESTRICTED
BANNED
}
model Violation {
id String @id @default(uuid())
userId String
type ViolationType
severity Int
reason String
user Staff @relation(fields: [userId], references: [id])
createdAt DateTime @default(now())
}
enum ViolationType {
SPAM
RATE_LIMIT
CONTENT
ABUSE
}
model Restriction {
id String @id @default(uuid())
userId String
type RestrictionType
expiresAt DateTime?
user Staff @relation(fields: [userId], references: [id])
}
enum RestrictionType {
TEMP
SHADOW
PERMANENT
}
model StaffTranslation {
id Int @id @default(autoincrement())
staffId String
lang Language? @relation(fields: [lang_id], references: [id])
lang_id Int?
// فیلدهایی که نیاز به ترجمه دارند
displayName String?
position String?
description String?
staff Staff @relation(fields: [staffId], references: [id])
@@unique([staffId, lang_id]) // هر کارمند در هر زبان فقط یک ترجمه دارد
}
model Image {
id Int @id @default(autoincrement())
fileKey String
filename String?
fileUrl String?
mimeType String?
size Int?
usersProfile Users[]
countriesCover Countries[]
medicalPackagesThumbnails MedicalPackage[]
transferPackageLocationImages TransferPackage[] @relation(name: "TransferPackageLocationImages")
transferPackageGalleryImages TransferPackage[] @relation(name: "TransferPackageGalleryImages")
staffProfilePictures Staff[]
}
model Users {
id Int @id @default(autoincrement())
slug String @unique
type UsersType @default(DOCTOR)
displayInMainPage Boolean @default(false)
phone String?
email String?
teamName String?
medicalNumber String?
expertise Expertise? @relation(fields: [expertiseId], references: [id])
expertiseId Int?
image Image? @relation(fields: [imageId], references: [id])
imageId Int?
createdAt DateTime @default(now())
translations UserTranslation[]
transerTeamMembers TransferTeam[]
@@index([id, slug])
}
model UserTranslation {
id Int @id @default(autoincrement())
userId Int
lang Language? @relation(fields: [lang_id], references: [id])
lang_id Int?
firstName String?
lastName String?
position String?
bio String?
excerpt String?
user Users @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([userId, lang_id]) // هر کاربر در هر زبان فقط یک ترجمه دارد
}
model Expertise {
id Int @id @default(autoincrement())
slug String @db.VarChar(100)
users Users[]
translations ExpertiseTranslation[]
}
model ExpertiseTranslation {
id Int @id @default(autoincrement())
expertiseId Int
lang Language? @relation(fields: [lang_id], references: [id])
lang_id Int?
displayName String?
level EducationLevel?
expertise Expertise @relation(fields: [expertiseId], references: [id])
@@unique([expertiseId, lang_id]) // هر کاربر در هر زبان فقط یک ترجمه دارد
}
enum EducationLevel {
GP
SPECIALIST
SUBSPECIALIST
FELLOWSHIP
}
enum UsersType {
DOCTOR
TRANSFER_TEAM
DEPARTMENT
}
model PanelConfig {
id String @id @default(uuid())
key String @unique
value String // مقدار خام (string)
type ConfigType // نوع داده
description String?
updatedAt DateTime @updatedAt
createdAt DateTime @default(now())
}
model Default {
id String @id @default("SITE_DEFAULTS")
email String
hospitalPhone String
logoUrl String?
mapAddress String
instagramLink String?
linkedinLink String?
ipdNumber String?
updatedAt DateTime @updatedAt
translations DefaultTranslation[]
}
model DefaultTranslation {
id Int @id @default(autoincrement())
default Default @relation(fields: [defaultId], references: [id])
defaultId String
language Language @relation(fields: [languageId], references: [id])
languageId Int
address String
underLogoText String?
aboutUsText String?
patientsRights String?
@@unique([defaultId, languageId])
}
model Statics {
id String @id @default(uuid())
key String @unique @db.VarChar(191)
group String @db.VarChar(100)
description String? @db.Text
translations StaticsTranslation[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([group])
}
model StaticsTranslation {
id String @id @default(uuid())
languageId Int
staticsKeyId String
value String @db.Text
language Language @relation(fields: [languageId], references: [id], onDelete: Cascade)
staticsKey Statics @relation(fields: [staticsKeyId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([languageId, staticsKeyId])
@@index([languageId])
@@index([staticsKeyId])
}
enum ConfigType {
BOOLEAN
NUMBER
STRING
JSON
STRING_ARRAY
}
model Page {
id Int @id @default(autoincrement())
slug String @unique
createdAt DateTime @default(now())
pageBlocks PageBlock[]
}
model PageBlock {
id Int @id @default(autoincrement())
pageId Int
type String // hero, text, image, faq, etc
sort Int
page Page @relation(fields: [pageId], references: [id])
pageBlockTranslations PageBlockTranslation[]
}
model PageBlockTranslation {
id Int @id @default(autoincrement())
blockId Int
lang Language? @relation(fields: [lang_id], references: [id])
lang_id Int?
field String // title, subtitle, description, button_text
value String
block PageBlock @relation(fields: [blockId], references: [id])
}
model Language {
id Int @id @default(autoincrement())
title String
slug String @unique
pageBlockTranslations PageBlockTranslation[]
// translations Translation[]
reviewTranslations ReviewTranslation[]
staffTranslations StaffTranslation[]
userTranslations UserTranslation[]
expertiseTranslations ExpertiseTranslation[]
defaultTranslations DefaultTranslation[]
medicalPackagesTranslations MedicalPackagesTranslation[]
transferPackageTranslations TransferPackageTranslations[]
transferTeamTranslations TransferTeamTranslation[]
staticsTranslations StaticsTranslation[]
@@index([id, slug])
}
model RefreshToken {
id Int @id @default(autoincrement())
token String @unique
staff Staff @relation(fields: [staffId], references: [id])
staffId String
expiresAt DateTime
createdAt DateTime @default(now())
}
model Countries {
id Int @id @default(autoincrement())
name String
callCode String
cover Image? @relation(fields: [coverId], references: [id])
coverId Int?
createdAt DateTime @default(now())
patients Patient[]
}
enum AuditAction {
CREATE
UPDATE
DELETE
READ
}
model AuditLog {
id Int @id @default(autoincrement())
actorId String?
actorRole StaffRoles?
action AuditAction
entity String
entityId Int?
before Json?
after Json?
ip String?
createdAt DateTime @default(now())
@@index([entity, entityId])
}
model AccessLog {
id Int @id @default(autoincrement())
userId String
userRole StaffRoles
resource String
resourceId Int?
reason String?
ip String?
createdAt DateTime @default(now())
}
model DecisionLog {
id Int @id @default(autoincrement())
decisionType String
input Json
output Json
algorithmVersion String
actorId String?
createdAt DateTime @default(now())
}
model TermsOfService {
id String @id @default(uuid()) // شناسه یکتا
title String // عنوان سند، مثلا "Terms of Service"
content String // متن کامل TOS (Markdown یا HTML)
version String @unique // نسخه سند، مثلا "v1.0.0"
isActive Boolean @default(true) // آیا این نسخه فعال است؟
createdAt DateTime @default(now()) // زمان ایجاد نسخه
updatedAt DateTime @updatedAt // زمان آخرین آپدیت
/// روابط اختیاری، اگر بخواهید لاگ پذیرش کاربران را نگه دارید
acceptances TosAcceptanceLog[] // ثبت کاربرانی که این نسخه را پذیرفته‌اند
}
model TosAcceptanceLog {
id Int @id @default(autoincrement())
userId String // شناسه کاربر
policyType String // نوع سند (TOS یا Privacy Policy)
policyVersion String // نسخه سند پذیرفته شده
acceptedAt DateTime @default(now()) // زمان پذیرش
ip String? // آی‌پی کاربر برای ثبت لاگ
tos TermsOfService? @relation(fields: [policyVersion], references: [version])
}
model PrivacyPolicy {
id Int @id @default(autoincrement()) // شناسه یکتا
content String // متن کامل TOS (Markdown یا HTML)
createdAt DateTime @default(now()) // زمان ایجاد نسخه
updatedAt DateTime @updatedAt // زمان آخرین آپدیت
}
model MedicalPackage {
id Int @id @default(autoincrement())
thumbnail Image? @relation(fields: [thumbnail_id], references: [id])
thumbnail_id Int?
icon String?
priority Int?
price String
parent MedicalPackage? @relation("MedicalPackageHierarchy", fields: [parent_id], references: [id], onDelete: SetNull)
parent_id Int? // برای اشاره به دسته‌بندی والد
children MedicalPackage[] @relation("MedicalPackageHierarchy")
translations MedicalPackagesTranslation[]
}
model MedicalPackagesTranslation {
id Int @id @default(autoincrement())
title String @db.VarChar(50)
content String?
lang Language? @relation(fields: [lang_id], references: [id])
lang_id Int?
medicalPackage MedicalPackage? @relation(fields: [medicalPackageId], references: [id])
medicalPackageId Int?
@@unique([medicalPackageId, lang_id]) // هر کاربر در هر زبان فقط یک ترجمه دارد
}
model TransferPackage {
id Int @id @default(autoincrement())
location String
price String
locationImages Image[] @relation(name: "TransferPackageLocationImages")
galleryImages Image[] @relation(name: "TransferPackageGalleryImages")
transferTeam TransferTeam[]
translations TransferPackageTranslations[]
}
model TransferPackageTranslations {
id Int @id @default(autoincrement())
name String
content String
lang Language? @relation(fields: [lang_id], references: [id])
lang_id Int?
transferPackage TransferPackage? @relation(fields: [transferPackageId], references: [id])
transferPackageId Int?
@@unique([transferPackageId, lang_id]) // هر کاربر در هر زبان فقط یک ترجمه دارد
}
model TransferTeam {
id Int @id @default(autoincrement())
members Users[]
packages TransferPackage[]
translations TransferTeamTranslation[]
}
model TransferTeamTranslation {
id Int @id @default(autoincrement())
lang Language? @relation(fields: [lang_id], references: [id])
lang_id Int?
transferTeam TransferTeam? @relation(fields: [transferTeamId], references: [id])
transferTeamId Int?
name String @db.VarChar(50)
introduction String
duties String
services String
@@unique([transferTeamId, lang_id]) // هر کاربر در هر زبان فقط یک ترجمه دارد
}