feat(seo): generate slugs for brands, categories and products, add GET /sitemap and the Postman collection
This commit is contained in:
@@ -23,6 +23,8 @@ model Category {
|
||||
name String
|
||||
/// Display order among its siblings (category_position)
|
||||
position Int @default(0)
|
||||
/// URL identifier (SEO): generated once by the sync, never overwritten by it; null until generated
|
||||
slug String? @unique
|
||||
/// Displayed on the website (category_enabled_www)
|
||||
webEnabled Boolean @default(true)
|
||||
|
||||
@@ -31,7 +33,8 @@ model Category {
|
||||
parentId String?
|
||||
children Category[] @relation("CategoryTree")
|
||||
|
||||
products Product[]
|
||||
products Product[]
|
||||
slugRedirects SlugRedirect[]
|
||||
|
||||
@@map("categories")
|
||||
}
|
||||
@@ -44,8 +47,11 @@ model Brand {
|
||||
enabled Boolean @default(true)
|
||||
hiboutikId Int @unique
|
||||
name String
|
||||
/// URL identifier (SEO): generated once by the sync, never overwritten by it; null until generated
|
||||
slug String? @unique
|
||||
|
||||
products Product[]
|
||||
products Product[]
|
||||
slugRedirects SlugRedirect[]
|
||||
|
||||
@@map("brands")
|
||||
}
|
||||
@@ -84,6 +90,8 @@ model Product {
|
||||
hiboutikUpdatedAt DateTime?
|
||||
name String
|
||||
price Decimal @db.Decimal(10, 2)
|
||||
/// URL identifier (SEO): generated once by the sync, never overwritten by it; null until generated
|
||||
slug String? @unique
|
||||
|
||||
brand Brand? @relation(fields: [brandId], references: [id], onDelete: SetNull)
|
||||
brandId String?
|
||||
@@ -92,11 +100,42 @@ model Product {
|
||||
supplier Supplier? @relation(fields: [supplierId], references: [id], onDelete: SetNull)
|
||||
supplierId String?
|
||||
|
||||
versions ProductVersion[]
|
||||
versions ProductVersion[]
|
||||
slugRedirects SlugRedirect[]
|
||||
|
||||
@@map("products")
|
||||
}
|
||||
|
||||
/// Kind of entity a slug identifies. Slugs are unique per kind (each one has its own URL space).
|
||||
enum SlugEntityType {
|
||||
BRAND
|
||||
CATEGORY
|
||||
PRODUCT
|
||||
}
|
||||
|
||||
/// Former slug of a brand, category or product, kept so that its old URL can be answered with a 301 redirect.
|
||||
/// Exactly one of brandId / categoryId / productId is set, matching `entityType`. Deleted with its entity.
|
||||
model SlugRedirect {
|
||||
id String @id @default(uuid())
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
entityType SlugEntityType
|
||||
slug String
|
||||
|
||||
brand Brand? @relation(fields: [brandId], references: [id], onDelete: Cascade)
|
||||
brandId String?
|
||||
category Category? @relation(fields: [categoryId], references: [id], onDelete: Cascade)
|
||||
categoryId String?
|
||||
product Product? @relation(fields: [productId], references: [id], onDelete: Cascade)
|
||||
productId String?
|
||||
|
||||
@@unique([entityType, slug])
|
||||
@@index([brandId])
|
||||
@@index([categoryId])
|
||||
@@index([productId])
|
||||
@@map("slug_redirects")
|
||||
}
|
||||
|
||||
/// Sellable version of a product: one per Hiboutik size, or a single one (hiboutikSizeId 0) for a product without sizes.
|
||||
model ProductVersion {
|
||||
id String @id @default(uuid())
|
||||
|
||||
Reference in New Issue
Block a user