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]) }