Files
backend/prisma/schema.prisma
T

295 lines
7.8 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum UserRole {
CUSTOMER
STORE_ADMIN
SUPER_ADMIN
}
enum StoreStatus {
pending
active
rejected
suspended
}
enum OrderStatus {
pending
confirmed
preparing
shipped
delivered
cancelled
}
enum OrderStoreStatus {
pending
confirmed
preparing
shipped
delivered
cancelled
}
enum SmsOtpPurpose {
register
login
resetPassword
storeRegister
}
model User {
id String @id @default(cuid())
firstName String
lastName String
cellNumber String @unique
passwordHash String
email String?
instagram String?
about String?
avatarUrl String?
avatarKey String?
role UserRole @default(CUSTOMER)
disabled Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
refreshTokens RefreshToken[]
addresses UserAddress[]
ownedStore Store?
orders Order[] @relation("CustomerOrders")
@@index([role])
@@index([disabled])
}
model UserAddress {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
label String @default("")
province String
city String
fullAddress String
landline String?
@@index([userId])
}
model RefreshToken {
id String @id @default(cuid())
tokenHash String
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
expiresAt DateTime
createdAt DateTime @default(now())
@@index([userId])
@@index([tokenHash])
}
model SmsOtp {
id String @id @default(cuid())
cellNumber String
purpose SmsOtpPurpose
codeHash String
payload Json?
attempts Int @default(0)
expiresAt DateTime
createdAt DateTime @default(now())
@@index([cellNumber, purpose])
@@index([expiresAt])
}
model Store {
id String @id @default(cuid())
slug String @unique
nameFa String
nameEn String @default("")
description String?
logoUrl String?
logoKey String?
status StoreStatus @default(pending)
ownerId String @unique
owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
rejectionReason String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
products Product[]
categories Category[]
brands Brand[]
blogs BlogPost[]
orderItems OrderItem[]
fulfillments OrderStoreFulfillment[]
@@index([status])
}
model Category {
id String @id @default(cuid())
storeId String
store Store @relation(fields: [storeId], references: [id], onDelete: Cascade)
parentId String?
parent Category? @relation("CategoryTree", fields: [parentId], references: [id], onDelete: SetNull)
children Category[] @relation("CategoryTree")
nameFa String
nameEn String @default("")
sortOrder Int @default(0)
colors String[] @default([])
sizes String[] @default([])
packages String[] @default([])
products Product[]
@@index([storeId])
@@index([parentId])
@@index([sortOrder])
}
model Brand {
id String @id @default(cuid())
storeId String
store Store @relation(fields: [storeId], references: [id], onDelete: Cascade)
nameFa String
nameEn String @default("")
imageUrl String?
imageKey String?
products Product[]
@@index([storeId])
}
model Product {
id String @id @default(cuid())
storeId String
store Store @relation(fields: [storeId], references: [id], onDelete: Cascade)
categoryId String?
category Category? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
brandId String?
brand Brand? @relation(fields: [brandId], references: [id], onDelete: SetNull)
nameFa String
nameEn String @default("")
summary String @default("")
description String @default("")
price Int @default(0)
discountPrice Int?
imageUrl String?
imageKey String?
galleryUrls String[] @default([])
galleryKeys String[] @default([])
tags String[] @default([])
published Boolean @default(true)
vipEnabled Boolean @default(false)
vipOnly Boolean @default(false)
vipSpecialPrice Boolean @default(false)
vipPrice Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
variants ProductVariant[]
orderItems OrderItem[]
@@index([storeId])
@@index([categoryId])
@@index([brandId])
@@index([price])
@@index([published])
@@index([vipEnabled])
@@index([vipOnly])
}
model ProductVariant {
id String @id @default(cuid())
productId String
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
colorId String @default("")
sizeId String @default("")
packageId String @default("")
price Int @default(0)
discountPrice Int?
vipPrice Int?
@@index([productId])
}
model BlogPost {
id String @id @default(cuid())
storeId String
store Store @relation(fields: [storeId], references: [id], onDelete: Cascade)
title String
summary String @default("")
body String @default("")
author String @default("")
imageUrl String?
imageKey String?
published Boolean @default(true)
metaTitle String?
metaDescription String?
slug String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([storeId])
@@index([published])
@@index([slug])
}
model Order {
id String @id @default(cuid())
customerId String?
customer User? @relation("CustomerOrders", fields: [customerId], references: [id], onDelete: SetNull)
customerName String
customerPhone String
status OrderStatus @default(pending)
itemCount Int @default(0)
totalAmount Int @default(0)
note String @default("")
shippingAddress Json?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
items OrderItem[]
fulfillments OrderStoreFulfillment[]
@@index([customerId])
@@index([status])
@@index([createdAt])
}
model OrderItem {
id String @id @default(cuid())
orderId String
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
storeId String
store Store @relation(fields: [storeId], references: [id], onDelete: Restrict)
productId String?
product Product? @relation(fields: [productId], references: [id], onDelete: SetNull)
nameFa String
variantLabel String?
quantity Int @default(1)
unitPrice Int @default(0)
@@index([orderId])
@@index([storeId])
@@index([productId])
}
model OrderStoreFulfillment {
id String @id @default(cuid())
orderId String
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
storeId String
store Store @relation(fields: [storeId], references: [id], onDelete: Restrict)
status OrderStoreStatus @default(pending)
@@unique([orderId, storeId])
@@index([storeId])
@@index([status])
}