Add public catalog APIs, website slots, featured slots, and int category/product IDs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-09-27 18:30:36 +03:30
co-authored by Cursor
parent 15dd3597f0
commit 835c8a0ac1
25 changed files with 1399 additions and 41 deletions
+41 -10
View File
@@ -131,24 +131,27 @@ model Store {
blogs BlogPost[]
orderItems OrderItem[]
fulfillments OrderStoreFulfillment[]
websiteSlots WebsiteSlotItem[]
@@index([status])
}
model Category {
id String @id @default(cuid())
id Int @id @default(autoincrement())
storeId String
store Store @relation(fields: [storeId], references: [id], onDelete: Cascade)
parentId String?
parentId Int?
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[]
colors String[] @default([])
sizes String[] @default([])
packages String[] @default([])
/// Ordered form-builder defs: [{ id, labelFa, labelEn?, type: "text", required? }]
technicalFields Json @default("[]")
products Product[]
@@index([storeId])
@@index([parentId])
@@ -169,10 +172,10 @@ model Brand {
}
model Product {
id String @id @default(cuid())
id Int @id @default(autoincrement())
storeId String
store Store @relation(fields: [storeId], references: [id], onDelete: Cascade)
categoryId String?
categoryId Int?
category Category? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
brandId String?
brand Brand? @relation(fields: [brandId], references: [id], onDelete: SetNull)
@@ -188,10 +191,14 @@ model Product {
galleryKeys String[] @default([])
tags String[] @default([])
published Boolean @default(true)
/// Home carousel featured slot: promo-1 | promo-2 | promo-3
featuredSlot String?
vipEnabled Boolean @default(false)
vipOnly Boolean @default(false)
vipSpecialPrice Boolean @default(false)
vipPrice Int?
/// Values keyed by category technical field id: { [fieldId]: string }
technicalData Json @default("{}")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
variants ProductVariant[]
@@ -202,13 +209,14 @@ model Product {
@@index([brandId])
@@index([price])
@@index([published])
@@index([featuredSlot])
@@index([vipEnabled])
@@index([vipOnly])
}
model ProductVariant {
id String @id @default(cuid())
productId String
productId Int
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
colorId String @default("")
sizeId String @default("")
@@ -289,7 +297,7 @@ model OrderItem {
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
storeId String
store Store @relation(fields: [storeId], references: [id], onDelete: Restrict)
productId String?
productId Int?
product Product? @relation(fields: [productId], references: [id], onDelete: SetNull)
nameFa String
variantLabel String?
@@ -313,3 +321,26 @@ model OrderStoreFulfillment {
@@index([storeId])
@@index([status])
}
/// Homepage / storefront image slots (hero slides, banners, category thumbs, …)
model WebsiteSlotItem {
id String @id @default(cuid())
storeId String
store Store @relation(fields: [storeId], references: [id], onDelete: Cascade)
/// e.g. home.hero | home.category.shirts | home.banner.leather
slotKey String
sortOrder Int @default(0)
nameFa String @default("")
nameEn String @default("")
subtext String @default("")
linkText String @default("")
link String @default("")
imageUrl String?
imageKey String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([storeId])
@@index([storeId, slotKey])
@@index([storeId, slotKey, sortOrder])
}