first commit
This commit is contained in:
682
prisma/schema.prisma
Normal file
682
prisma/schema.prisma
Normal file
@@ -0,0 +1,682 @@
|
||||
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]) // هر کاربر در هر زبان فقط یک ترجمه دارد
|
||||
}
|
||||
Reference in New Issue
Block a user