diff --git a/src/app/api/public/hero-slider/route.ts b/src/app/api/public/hero-slider/route.ts new file mode 100644 index 0000000..1fb763b --- /dev/null +++ b/src/app/api/public/hero-slider/route.ts @@ -0,0 +1,58 @@ +import { NextRequest, NextResponse } from 'next/server' +import { getPayload } from 'payload' +import config from '@payload-config' +import { getCache, setCache } from '@/lib/redis' + +/** + * GET /api/public/hero-slider + * 获取首页幻灯片数据(带缓存) + */ +export async function GET(req: NextRequest) { + try { + // 生成缓存 key + const cacheKey = 'hero-slider:data' + + // 尝试从缓存获取 + const cached = await getCache(cacheKey) + if (cached) { + return NextResponse.json({ + success: true, + data: cached, + cached: true, + }) + } + + // 从数据库获取 + const payload = await getPayload({ config }) + const result = await payload.findGlobal({ + slug: 'hero-slider' as any, + depth: 2, // 填充图片关联数据 + }) + + // 获取所有幻灯片 + const slides = (result as any).slides || [] + + const responseData = { + slides, + totalSlides: slides.length, + } + + // 缓存结果(1 小时) + await setCache(cacheKey, responseData, 3600) + + return NextResponse.json({ + success: true, + data: responseData, + cached: false, + }) + } catch (error) { + console.error('Hero slider API error:', error) + return NextResponse.json( + { + success: false, + error: error instanceof Error ? error.message : 'Failed to fetch hero slider', + }, + { status: 500 }, + ) + } +} diff --git a/src/app/api/public/homepage/route.ts b/src/app/api/public/homepage/route.ts new file mode 100644 index 0000000..aecc623 --- /dev/null +++ b/src/app/api/public/homepage/route.ts @@ -0,0 +1,131 @@ +import { NextRequest, NextResponse } from 'next/server' +import { getPayload } from 'payload' +import config from '@payload-config' +import { getCache, setCache } from '@/lib/redis' + +/** + * GET /api/public/homepage + * 获取首页所有数据:幻灯片 + 商品推荐列表(带缓存) + * + * 这个 API 组合了多个数据源,提供完整的首页内容 + */ +export async function GET(req: NextRequest) { + try { + // 生成缓存 key + const cacheKey = 'homepage:data' + + // 尝试从缓存获取 + const cached = await getCache(cacheKey) + if (cached) { + return NextResponse.json({ + success: true, + data: cached, + cached: true, + }) + } + + // 从数据库获取数据 + const payload = await getPayload({ config }) + + // 并行获取所有数据 + const [heroSliderResult, productRecommendationsResult] = await Promise.all([ + // 获取幻灯片数据 + payload + .findGlobal({ + slug: 'hero-slider' as any, + depth: 2, + }) + .catch((error) => { + console.error('Failed to fetch hero slider:', error) + return null + }), + + // 获取商品推荐数据 + payload + .findGlobal({ + slug: 'product-recommendations' as any, + depth: 3, + }) + .catch((error) => { + console.error('Failed to fetch product recommendations:', error) + return null + }), + ]) + + // 处理幻灯片数据 + let heroSlider = { + slides: [], + totalSlides: 0, + } + + if (heroSliderResult) { + const slides = (heroSliderResult as any).slides || [] + + heroSlider = { + slides, + totalSlides: slides.length, + } + } + + // 处理商品推荐数据 + let productRecommendations = { + enabled: false, + lists: [], + totalLists: 0, + } + + if (productRecommendationsResult && (productRecommendationsResult as any).enabled) { + // 获取所有列表 + const lists = (productRecommendationsResult as any).lists || [] + + // 处理每个列表 + const processedLists = lists.map((list: any) => { + const products = Array.isArray(list.products) + ? list.products.filter((product: any) => product && product.status === 'published') + : [] + + return { + id: list.id, + title: list.title, + subtitle: list.subtitle, + products, + totalProducts: products.length, + } + }) + + productRecommendations = { + enabled: (productRecommendationsResult as any).enabled, + lists: processedLists, + totalLists: processedLists.length, + } + } + + // 组合响应数据 + const responseData = { + heroSlider, + productRecommendations, + meta: { + timestamp: new Date().toISOString(), + version: '1.0', + }, + } + + // 缓存结果(1 小时) + await setCache(cacheKey, responseData, 3600) + + return NextResponse.json({ + success: true, + data: responseData, + cached: false, + }) + } catch (error) { + console.error('Homepage API error:', error) + return NextResponse.json( + { + success: false, + error: error instanceof Error ? error.message : 'Failed to fetch homepage data', + }, + { status: 500 }, + ) + } +} diff --git a/src/app/api/public/product-recommendations/route.ts b/src/app/api/public/product-recommendations/route.ts new file mode 100644 index 0000000..2a5aa36 --- /dev/null +++ b/src/app/api/public/product-recommendations/route.ts @@ -0,0 +1,91 @@ +import { NextRequest, NextResponse } from 'next/server' +import { getPayload } from 'payload' +import config from '@payload-config' +import { getCache, setCache } from '@/lib/redis' + +/** + * GET /api/public/product-recommendations + * 获取商品推荐列表数据(带缓存) + */ +export async function GET(req: NextRequest) { + try { + // 生成缓存 key + const cacheKey = 'product-recommendations:data' + + // 尝试从缓存获取 + const cached = await getCache(cacheKey) + if (cached) { + return NextResponse.json({ + success: true, + data: cached, + cached: true, + }) + } + + // 从数据库获取 + const payload = await getPayload({ config }) + const result = await payload.findGlobal({ + slug: 'product-recommendations' as any, + depth: 3, // 填充商品和图片关联数据 + }) + + // 如果功能未启用,返回空数据 + if (!(result as any).enabled) { + const emptyData = { + enabled: false, + lists: [], + } + + // 缓存空数据(较短时间) + await setCache(cacheKey, emptyData, 600) // 10 分钟 + + return NextResponse.json({ + success: true, + data: emptyData, + cached: false, + }) + } + + // 获取所有列表 + const lists = (result as any).lists || [] + + // 处理每个列表 + const processedLists = lists.map((list: any) => { + const products = Array.isArray(list.products) + ? list.products.filter((product: any) => product && product.status === 'published') + : [] + + return { + id: list.id, + title: list.title, + subtitle: list.subtitle, + products, + totalProducts: products.length, + } + }) + + const responseData = { + enabled: (result as any).enabled, + lists: processedLists, + totalLists: processedLists.length, + } + + // 缓存结果(1 小时) + await setCache(cacheKey, responseData, 3600) + + return NextResponse.json({ + success: true, + data: responseData, + cached: false, + }) + } catch (error) { + console.error('Product recommendations API error:', error) + return NextResponse.json( + { + success: false, + error: error instanceof Error ? error.message : 'Failed to fetch product recommendations', + }, + { status: 500 }, + ) + } +} diff --git a/src/globals/HeroSlider.ts b/src/globals/HeroSlider.ts new file mode 100644 index 0000000..51bf8fe --- /dev/null +++ b/src/globals/HeroSlider.ts @@ -0,0 +1,139 @@ +import type { GlobalConfig } from 'payload' +import { deleteCachePattern } from '@/lib/redis' + +export const HeroSlider: GlobalConfig = { + slug: 'hero-slider', + label: { + en: 'Hero Slider', + zh: '首页幻灯片', + }, + access: { + read: () => true, // 公开可读 + update: ({ req: { user } }) => { + // 只有 admin 和 editor 可以更新 + if (!user) return false + return user.roles?.includes('admin') || user.roles?.includes('editor') || false + }, + }, + admin: { + group: { + en: 'Content', + zh: '内容管理', + }, + description: { + en: 'Manage homepage hero slider/banner', + zh: '管理首页轮播图/横幅', + }, + }, + fields: [ + { + name: 'slides', + type: 'array', + label: { + en: 'Slides', + zh: '幻灯片', + }, + labels: { + singular: { + en: 'Slide', + zh: '幻灯片', + }, + plural: { + en: 'Slides', + zh: '幻灯片列表', + }, + }, + minRows: 1, + maxRows: 10, + admin: { + description: { + en: 'Add slides to the hero slider (drag to reorder)', + zh: '添加幻灯片(拖动排序)', + }, + initCollapsed: true, + }, + fields: [ + { + name: 'title', + type: 'text', + label: { + en: 'Title', + zh: '标题', + }, + required: true, + }, + { + name: 'subtitle', + type: 'textarea', + label: { + en: 'Subtitle', + zh: '副标题', + }, + maxLength: 200, + admin: { + rows: 2, + }, + }, + { + name: 'image', + type: 'upload', + label: { + en: 'Image', + zh: '图片', + }, + relationTo: 'media', + required: true, + admin: { + description: { + en: 'Recommended: 1920x800px', + zh: '推荐尺寸:1920x800px', + }, + }, + }, + { + name: 'imageMobile', + type: 'upload', + label: { + en: 'Mobile Image', + zh: '移动端图片', + }, + relationTo: 'media', + admin: { + description: { + en: 'Optional. Recommended: 750x1000px', + zh: '可选。推荐尺寸:750x1000px', + }, + }, + }, + { + name: 'link', + type: 'text', + label: { + en: 'Link', + zh: '链接', + }, + admin: { + description: { + en: 'Where to go when clicked (e.g., /products)', + zh: '点击后跳转的链接(如:/products)', + }, + }, + }, + ], + }, + ], + hooks: { + afterChange: [ + async ({ doc }) => { + try { + // 清除 hero-slider 的所有缓存 + const deletedCount = await deleteCachePattern('hero-slider:*') + console.log(`[Cache] Cleared ${deletedCount} cache keys for hero-slider after change`) + } catch (error) { + console.error('[Cache] Failed to clear hero-slider cache:', error) + } + return doc + }, + ], + }, +} diff --git a/src/globals/ProductRecommendations.ts b/src/globals/ProductRecommendations.ts new file mode 100644 index 0000000..26dad69 --- /dev/null +++ b/src/globals/ProductRecommendations.ts @@ -0,0 +1,131 @@ +import type { GlobalConfig } from 'payload' +import { deleteCachePattern } from '@/lib/redis' + +export const ProductRecommendations: GlobalConfig = { + slug: 'product-recommendations', + label: { + en: 'Product Recommendations', + zh: '商品推荐', + }, + access: { + read: () => true, // 公开可读 + update: ({ req: { user } }) => { + // 只有 admin 和 editor 可以更新 + if (!user) return false + return user.roles?.includes('admin') || user.roles?.includes('editor') || false + }, + }, + admin: { + group: { + en: 'Content', + zh: '内容管理', + }, + description: { + en: 'Manage product recommendation lists for homepage and other pages', + zh: '管理首页及其他页面的商品推荐列表', + }, + }, + fields: [ + { + name: 'enabled', + type: 'checkbox', + label: { + en: 'Enable Recommendations', + zh: '启用推荐', + }, + defaultValue: true, + admin: { + description: { + en: 'Toggle to show/hide product recommendations', + zh: '切换显示/隐藏商品推荐', + }, + }, + }, + { + name: 'lists', + type: 'array', + label: { + en: 'Recommendation Lists', + zh: '推荐列表', + }, + labels: { + singular: { + en: 'List', + zh: '列表', + }, + plural: { + en: 'Lists', + zh: '列表集合', + }, + }, + minRows: 0, + maxRows: 10, + admin: { + description: { + en: 'Create multiple product recommendation lists (e.g., Hot Items, New Arrivals, Limited Offers)', + zh: '创建多个商品推荐列表(如:热门商品、新品上架、限时优惠)', + }, + initCollapsed: true, + }, + fields: [ + { + name: 'title', + type: 'text', + label: { + en: 'List Title', + zh: '列表标题', + }, + required: true, + }, + { + name: 'subtitle', + type: 'textarea', + label: { + en: 'Subtitle', + zh: '副标题', + }, + maxLength: 200, + admin: { + rows: 2, + }, + }, + { + name: 'products', + type: 'relationship', + label: { + en: 'Products', + zh: '商品列表', + }, + relationTo: 'products', + hasMany: true, + admin: { + description: { + en: 'Select and drag to reorder products', + zh: '相关商品,支持搜索联想', + }, + components: { + Field: '/components/fields/RelatedProductsField#RelatedProductsField', + }, + }, + }, + ], + }, + ], + hooks: { + afterChange: [ + async ({ doc }) => { + try { + // 清除商品推荐和首页的所有缓存 + const deletedCount = await deleteCachePattern('product-recommendations:*') + const deletedHomepage = await deleteCachePattern('homepage:*') + console.log( + `[Cache] Cleared ${deletedCount} product-recommendations cache keys and ${deletedHomepage} homepage cache keys`, + ) + } catch (error) { + console.error('[Cache] Failed to clear product-recommendations cache:', error) + } + return doc + }, + ], + }, +} diff --git a/src/migrations/20260212_193303.json b/src/migrations/20260212_193303.json new file mode 100644 index 0000000..54e2c49 --- /dev/null +++ b/src/migrations/20260212_193303.json @@ -0,0 +1,3835 @@ +{ + "version": "7", + "dialect": "postgresql", + "tables": { + "public.users_roles": { + "name": "users_roles", + "schema": "", + "columns": { + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "enum_users_roles", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + } + }, + "indexes": { + "users_roles_order_idx": { + "name": "users_roles_order_idx", + "columns": [ + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "users_roles_parent_idx": { + "name": "users_roles_parent_idx", + "columns": [ + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "users_roles_parent_fk": { + "name": "users_roles_parent_fk", + "tableFrom": "users_roles", + "tableTo": "users", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users_sessions": { + "name": "users_sessions", + "schema": "", + "columns": { + "_order": { + "name": "_order", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "_parent_id": { + "name": "_parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "users_sessions_order_idx": { + "name": "users_sessions_order_idx", + "columns": [ + { + "expression": "_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "users_sessions_parent_id_idx": { + "name": "users_sessions_parent_id_idx", + "columns": [ + { + "expression": "_parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "users_sessions_parent_id_fk": { + "name": "users_sessions_parent_id_fk", + "tableFrom": "users_sessions", + "tableTo": "users", + "columnsFrom": [ + "_parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "email": { + "name": "email", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "reset_password_token": { + "name": "reset_password_token", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "reset_password_expiration": { + "name": "reset_password_expiration", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + }, + "salt": { + "name": "salt", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "hash": { + "name": "hash", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "login_attempts": { + "name": "login_attempts", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "lock_until": { + "name": "lock_until", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "users_updated_at_idx": { + "name": "users_updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "users_created_at_idx": { + "name": "users_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "users_email_idx": { + "name": "users_email_idx", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.media": { + "name": "media", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "alt": { + "name": "alt", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "url": { + "name": "url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "thumbnail_u_r_l": { + "name": "thumbnail_u_r_l", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "filename": { + "name": "filename", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "mime_type": { + "name": "mime_type", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "filesize": { + "name": "filesize", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "width": { + "name": "width", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "height": { + "name": "height", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "focal_x": { + "name": "focal_x", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "focal_y": { + "name": "focal_y", + "type": "numeric", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "media_updated_at_idx": { + "name": "media_updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "media_created_at_idx": { + "name": "media_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "media_filename_idx": { + "name": "media_filename_idx", + "columns": [ + { + "expression": "filename", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.products": { + "name": "products", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "medusa_id": { + "name": "medusa_id", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "enum_products_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'draft'" + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "handle": { + "name": "handle", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "thumbnail": { + "name": "thumbnail", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "last_synced_at": { + "name": "last_synced_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "products_medusa_id_idx": { + "name": "products_medusa_id_idx", + "columns": [ + { + "expression": "medusa_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "products_updated_at_idx": { + "name": "products_updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "products_created_at_idx": { + "name": "products_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.products_rels": { + "name": "products_rels", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "parent_id": { + "name": "parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "path": { + "name": "path", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "products_id": { + "name": "products_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "products_rels_order_idx": { + "name": "products_rels_order_idx", + "columns": [ + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "products_rels_parent_idx": { + "name": "products_rels_parent_idx", + "columns": [ + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "products_rels_path_idx": { + "name": "products_rels_path_idx", + "columns": [ + { + "expression": "path", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "products_rels_products_id_idx": { + "name": "products_rels_products_id_idx", + "columns": [ + { + "expression": "products_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "products_rels_parent_fk": { + "name": "products_rels_parent_fk", + "tableFrom": "products_rels", + "tableTo": "products", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "products_rels_products_fk": { + "name": "products_rels_products_fk", + "tableFrom": "products_rels", + "tableTo": "products", + "columnsFrom": [ + "products_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.announcements": { + "name": "announcements", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "enum_announcements_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'info'" + }, + "status": { + "name": "status", + "type": "enum_announcements_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'draft'" + }, + "priority": { + "name": "priority", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "summary": { + "name": "summary", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "published_at": { + "name": "published_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + }, + "show_on_homepage": { + "name": "show_on_homepage", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "author_id": { + "name": "author_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "announcements_author_idx": { + "name": "announcements_author_idx", + "columns": [ + { + "expression": "author_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "announcements_updated_at_idx": { + "name": "announcements_updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "announcements_created_at_idx": { + "name": "announcements_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "announcements_author_id_users_id_fk": { + "name": "announcements_author_id_users_id_fk", + "tableFrom": "announcements", + "tableTo": "users", + "columnsFrom": [ + "author_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.articles": { + "name": "articles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "enum_articles_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'draft'" + }, + "slug": { + "name": "slug", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "featured_image_id": { + "name": "featured_image_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "excerpt": { + "name": "excerpt", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "enum_articles_category", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "featured": { + "name": "featured", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "author_id": { + "name": "author_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "published_at": { + "name": "published_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + }, + "meta_title": { + "name": "meta_title", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "meta_description": { + "name": "meta_description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "_status": { + "name": "_status", + "type": "enum_articles_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'draft'" + } + }, + "indexes": { + "articles_slug_idx": { + "name": "articles_slug_idx", + "columns": [ + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "articles_featured_image_idx": { + "name": "articles_featured_image_idx", + "columns": [ + { + "expression": "featured_image_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "articles_author_idx": { + "name": "articles_author_idx", + "columns": [ + { + "expression": "author_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "articles_updated_at_idx": { + "name": "articles_updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "articles_created_at_idx": { + "name": "articles_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "articles__status_idx": { + "name": "articles__status_idx", + "columns": [ + { + "expression": "_status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "articles_featured_image_id_media_id_fk": { + "name": "articles_featured_image_id_media_id_fk", + "tableFrom": "articles", + "tableTo": "media", + "columnsFrom": [ + "featured_image_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "articles_author_id_users_id_fk": { + "name": "articles_author_id_users_id_fk", + "tableFrom": "articles", + "tableTo": "users", + "columnsFrom": [ + "author_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.articles_texts": { + "name": "articles_texts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "path": { + "name": "path", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "text": { + "name": "text", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "articles_texts_order_parent": { + "name": "articles_texts_order_parent", + "columns": [ + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "articles_texts_parent_fk": { + "name": "articles_texts_parent_fk", + "tableFrom": "articles_texts", + "tableTo": "articles", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.articles_rels": { + "name": "articles_rels", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "parent_id": { + "name": "parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "path": { + "name": "path", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "articles_id": { + "name": "articles_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "products_id": { + "name": "products_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "articles_rels_order_idx": { + "name": "articles_rels_order_idx", + "columns": [ + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "articles_rels_parent_idx": { + "name": "articles_rels_parent_idx", + "columns": [ + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "articles_rels_path_idx": { + "name": "articles_rels_path_idx", + "columns": [ + { + "expression": "path", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "articles_rels_articles_id_idx": { + "name": "articles_rels_articles_id_idx", + "columns": [ + { + "expression": "articles_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "articles_rels_products_id_idx": { + "name": "articles_rels_products_id_idx", + "columns": [ + { + "expression": "products_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "articles_rels_parent_fk": { + "name": "articles_rels_parent_fk", + "tableFrom": "articles_rels", + "tableTo": "articles", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "articles_rels_articles_fk": { + "name": "articles_rels_articles_fk", + "tableFrom": "articles_rels", + "tableTo": "articles", + "columnsFrom": [ + "articles_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "articles_rels_products_fk": { + "name": "articles_rels_products_fk", + "tableFrom": "articles_rels", + "tableTo": "products", + "columnsFrom": [ + "products_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public._articles_v": { + "name": "_articles_v", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "version_title": { + "name": "version_title", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "version_status": { + "name": "version_status", + "type": "enum__articles_v_version_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'draft'" + }, + "version_slug": { + "name": "version_slug", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "version_featured_image_id": { + "name": "version_featured_image_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "version_excerpt": { + "name": "version_excerpt", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "version_content": { + "name": "version_content", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "version_category": { + "name": "version_category", + "type": "enum__articles_v_version_category", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "version_featured": { + "name": "version_featured", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "version_author_id": { + "name": "version_author_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "version_published_at": { + "name": "version_published_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + }, + "version_meta_title": { + "name": "version_meta_title", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "version_meta_description": { + "name": "version_meta_description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "version_updated_at": { + "name": "version_updated_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + }, + "version_created_at": { + "name": "version_created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + }, + "version__status": { + "name": "version__status", + "type": "enum__articles_v_version_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'draft'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "latest": { + "name": "latest", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "autosave": { + "name": "autosave", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "_articles_v_parent_idx": { + "name": "_articles_v_parent_idx", + "columns": [ + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "_articles_v_version_version_slug_idx": { + "name": "_articles_v_version_version_slug_idx", + "columns": [ + { + "expression": "version_slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "_articles_v_version_version_featured_image_idx": { + "name": "_articles_v_version_version_featured_image_idx", + "columns": [ + { + "expression": "version_featured_image_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "_articles_v_version_version_author_idx": { + "name": "_articles_v_version_version_author_idx", + "columns": [ + { + "expression": "version_author_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "_articles_v_version_version_updated_at_idx": { + "name": "_articles_v_version_version_updated_at_idx", + "columns": [ + { + "expression": "version_updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "_articles_v_version_version_created_at_idx": { + "name": "_articles_v_version_version_created_at_idx", + "columns": [ + { + "expression": "version_created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "_articles_v_version_version__status_idx": { + "name": "_articles_v_version_version__status_idx", + "columns": [ + { + "expression": "version__status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "_articles_v_created_at_idx": { + "name": "_articles_v_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "_articles_v_updated_at_idx": { + "name": "_articles_v_updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "_articles_v_latest_idx": { + "name": "_articles_v_latest_idx", + "columns": [ + { + "expression": "latest", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "_articles_v_autosave_idx": { + "name": "_articles_v_autosave_idx", + "columns": [ + { + "expression": "autosave", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "_articles_v_parent_id_articles_id_fk": { + "name": "_articles_v_parent_id_articles_id_fk", + "tableFrom": "_articles_v", + "tableTo": "articles", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "_articles_v_version_featured_image_id_media_id_fk": { + "name": "_articles_v_version_featured_image_id_media_id_fk", + "tableFrom": "_articles_v", + "tableTo": "media", + "columnsFrom": [ + "version_featured_image_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "_articles_v_version_author_id_users_id_fk": { + "name": "_articles_v_version_author_id_users_id_fk", + "tableFrom": "_articles_v", + "tableTo": "users", + "columnsFrom": [ + "version_author_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public._articles_v_texts": { + "name": "_articles_v_texts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "path": { + "name": "path", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "text": { + "name": "text", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "_articles_v_texts_order_parent": { + "name": "_articles_v_texts_order_parent", + "columns": [ + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "_articles_v_texts_parent_fk": { + "name": "_articles_v_texts_parent_fk", + "tableFrom": "_articles_v_texts", + "tableTo": "_articles_v", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public._articles_v_rels": { + "name": "_articles_v_rels", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "parent_id": { + "name": "parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "path": { + "name": "path", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "articles_id": { + "name": "articles_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "products_id": { + "name": "products_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "_articles_v_rels_order_idx": { + "name": "_articles_v_rels_order_idx", + "columns": [ + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "_articles_v_rels_parent_idx": { + "name": "_articles_v_rels_parent_idx", + "columns": [ + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "_articles_v_rels_path_idx": { + "name": "_articles_v_rels_path_idx", + "columns": [ + { + "expression": "path", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "_articles_v_rels_articles_id_idx": { + "name": "_articles_v_rels_articles_id_idx", + "columns": [ + { + "expression": "articles_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "_articles_v_rels_products_id_idx": { + "name": "_articles_v_rels_products_id_idx", + "columns": [ + { + "expression": "products_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "_articles_v_rels_parent_fk": { + "name": "_articles_v_rels_parent_fk", + "tableFrom": "_articles_v_rels", + "tableTo": "_articles_v", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "_articles_v_rels_articles_fk": { + "name": "_articles_v_rels_articles_fk", + "tableFrom": "_articles_v_rels", + "tableTo": "articles", + "columnsFrom": [ + "articles_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "_articles_v_rels_products_fk": { + "name": "_articles_v_rels_products_fk", + "tableFrom": "_articles_v_rels", + "tableTo": "products", + "columnsFrom": [ + "products_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.logs": { + "name": "logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "action": { + "name": "action", + "type": "enum_logs_action", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "collection": { + "name": "collection", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "document_id": { + "name": "document_id", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "document_title": { + "name": "document_title", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "changes": { + "name": "changes", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "ip": { + "name": "ip", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "logs_collection_idx": { + "name": "logs_collection_idx", + "columns": [ + { + "expression": "collection", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "logs_document_id_idx": { + "name": "logs_document_id_idx", + "columns": [ + { + "expression": "document_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "logs_user_idx": { + "name": "logs_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "logs_updated_at_idx": { + "name": "logs_updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "logs_created_at_idx": { + "name": "logs_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "logs_user_id_users_id_fk": { + "name": "logs_user_id_users_id_fk", + "tableFrom": "logs", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.payload_kv": { + "name": "payload_kv", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "key": { + "name": "key", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "payload_kv_key_idx": { + "name": "payload_kv_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.payload_jobs_log": { + "name": "payload_jobs_log", + "schema": "", + "columns": { + "_order": { + "name": "_order", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "_parent_id": { + "name": "_parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "executed_at": { + "name": "executed_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true + }, + "task_slug": { + "name": "task_slug", + "type": "enum_payload_jobs_log_task_slug", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "task_i_d": { + "name": "task_i_d", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "input": { + "name": "input", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "output": { + "name": "output", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "state": { + "name": "state", + "type": "enum_payload_jobs_log_state", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "error": { + "name": "error", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "payload_jobs_log_order_idx": { + "name": "payload_jobs_log_order_idx", + "columns": [ + { + "expression": "_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_jobs_log_parent_id_idx": { + "name": "payload_jobs_log_parent_id_idx", + "columns": [ + { + "expression": "_parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "payload_jobs_log_parent_id_fk": { + "name": "payload_jobs_log_parent_id_fk", + "tableFrom": "payload_jobs_log", + "tableTo": "payload_jobs", + "columnsFrom": [ + "_parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.payload_jobs": { + "name": "payload_jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "input": { + "name": "input", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + }, + "total_tried": { + "name": "total_tried", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "has_error": { + "name": "has_error", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "error": { + "name": "error", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "task_slug": { + "name": "task_slug", + "type": "enum_payload_jobs_task_slug", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "queue": { + "name": "queue", + "type": "varchar", + "primaryKey": false, + "notNull": false, + "default": "'default'" + }, + "wait_until": { + "name": "wait_until", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + }, + "processing": { + "name": "processing", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "payload_jobs_completed_at_idx": { + "name": "payload_jobs_completed_at_idx", + "columns": [ + { + "expression": "completed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_jobs_total_tried_idx": { + "name": "payload_jobs_total_tried_idx", + "columns": [ + { + "expression": "total_tried", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_jobs_has_error_idx": { + "name": "payload_jobs_has_error_idx", + "columns": [ + { + "expression": "has_error", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_jobs_task_slug_idx": { + "name": "payload_jobs_task_slug_idx", + "columns": [ + { + "expression": "task_slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_jobs_queue_idx": { + "name": "payload_jobs_queue_idx", + "columns": [ + { + "expression": "queue", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_jobs_wait_until_idx": { + "name": "payload_jobs_wait_until_idx", + "columns": [ + { + "expression": "wait_until", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_jobs_processing_idx": { + "name": "payload_jobs_processing_idx", + "columns": [ + { + "expression": "processing", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_jobs_updated_at_idx": { + "name": "payload_jobs_updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_jobs_created_at_idx": { + "name": "payload_jobs_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.payload_locked_documents": { + "name": "payload_locked_documents", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "global_slug": { + "name": "global_slug", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "payload_locked_documents_global_slug_idx": { + "name": "payload_locked_documents_global_slug_idx", + "columns": [ + { + "expression": "global_slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_locked_documents_updated_at_idx": { + "name": "payload_locked_documents_updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_locked_documents_created_at_idx": { + "name": "payload_locked_documents_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.payload_locked_documents_rels": { + "name": "payload_locked_documents_rels", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "parent_id": { + "name": "parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "path": { + "name": "path", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "users_id": { + "name": "users_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "media_id": { + "name": "media_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "products_id": { + "name": "products_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "announcements_id": { + "name": "announcements_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "articles_id": { + "name": "articles_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "logs_id": { + "name": "logs_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "payload_locked_documents_rels_order_idx": { + "name": "payload_locked_documents_rels_order_idx", + "columns": [ + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_locked_documents_rels_parent_idx": { + "name": "payload_locked_documents_rels_parent_idx", + "columns": [ + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_locked_documents_rels_path_idx": { + "name": "payload_locked_documents_rels_path_idx", + "columns": [ + { + "expression": "path", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_locked_documents_rels_users_id_idx": { + "name": "payload_locked_documents_rels_users_id_idx", + "columns": [ + { + "expression": "users_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_locked_documents_rels_media_id_idx": { + "name": "payload_locked_documents_rels_media_id_idx", + "columns": [ + { + "expression": "media_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_locked_documents_rels_products_id_idx": { + "name": "payload_locked_documents_rels_products_id_idx", + "columns": [ + { + "expression": "products_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_locked_documents_rels_announcements_id_idx": { + "name": "payload_locked_documents_rels_announcements_id_idx", + "columns": [ + { + "expression": "announcements_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_locked_documents_rels_articles_id_idx": { + "name": "payload_locked_documents_rels_articles_id_idx", + "columns": [ + { + "expression": "articles_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_locked_documents_rels_logs_id_idx": { + "name": "payload_locked_documents_rels_logs_id_idx", + "columns": [ + { + "expression": "logs_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "payload_locked_documents_rels_parent_fk": { + "name": "payload_locked_documents_rels_parent_fk", + "tableFrom": "payload_locked_documents_rels", + "tableTo": "payload_locked_documents", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "payload_locked_documents_rels_users_fk": { + "name": "payload_locked_documents_rels_users_fk", + "tableFrom": "payload_locked_documents_rels", + "tableTo": "users", + "columnsFrom": [ + "users_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "payload_locked_documents_rels_media_fk": { + "name": "payload_locked_documents_rels_media_fk", + "tableFrom": "payload_locked_documents_rels", + "tableTo": "media", + "columnsFrom": [ + "media_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "payload_locked_documents_rels_products_fk": { + "name": "payload_locked_documents_rels_products_fk", + "tableFrom": "payload_locked_documents_rels", + "tableTo": "products", + "columnsFrom": [ + "products_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "payload_locked_documents_rels_announcements_fk": { + "name": "payload_locked_documents_rels_announcements_fk", + "tableFrom": "payload_locked_documents_rels", + "tableTo": "announcements", + "columnsFrom": [ + "announcements_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "payload_locked_documents_rels_articles_fk": { + "name": "payload_locked_documents_rels_articles_fk", + "tableFrom": "payload_locked_documents_rels", + "tableTo": "articles", + "columnsFrom": [ + "articles_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "payload_locked_documents_rels_logs_fk": { + "name": "payload_locked_documents_rels_logs_fk", + "tableFrom": "payload_locked_documents_rels", + "tableTo": "logs", + "columnsFrom": [ + "logs_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.payload_preferences": { + "name": "payload_preferences", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "key": { + "name": "key", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "value": { + "name": "value", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "payload_preferences_key_idx": { + "name": "payload_preferences_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_preferences_updated_at_idx": { + "name": "payload_preferences_updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_preferences_created_at_idx": { + "name": "payload_preferences_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.payload_preferences_rels": { + "name": "payload_preferences_rels", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "parent_id": { + "name": "parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "path": { + "name": "path", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "users_id": { + "name": "users_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "payload_preferences_rels_order_idx": { + "name": "payload_preferences_rels_order_idx", + "columns": [ + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_preferences_rels_parent_idx": { + "name": "payload_preferences_rels_parent_idx", + "columns": [ + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_preferences_rels_path_idx": { + "name": "payload_preferences_rels_path_idx", + "columns": [ + { + "expression": "path", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_preferences_rels_users_id_idx": { + "name": "payload_preferences_rels_users_id_idx", + "columns": [ + { + "expression": "users_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "payload_preferences_rels_parent_fk": { + "name": "payload_preferences_rels_parent_fk", + "tableFrom": "payload_preferences_rels", + "tableTo": "payload_preferences", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "payload_preferences_rels_users_fk": { + "name": "payload_preferences_rels_users_fk", + "tableFrom": "payload_preferences_rels", + "tableTo": "users", + "columnsFrom": [ + "users_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.payload_migrations": { + "name": "payload_migrations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "batch": { + "name": "batch", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "payload_migrations_updated_at_idx": { + "name": "payload_migrations_updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "payload_migrations_created_at_idx": { + "name": "payload_migrations_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.admin_settings": { + "name": "admin_settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": false, + "default": "'管理员设置'" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.logs_manager": { + "name": "logs_manager", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "placeholder": { + "name": "placeholder", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hero_slider_slides": { + "name": "hero_slider_slides", + "schema": "", + "columns": { + "_order": { + "name": "_order", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "_parent_id": { + "name": "_parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "subtitle": { + "name": "subtitle", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "image_id": { + "name": "image_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "image_mobile_id": { + "name": "image_mobile_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "link": { + "name": "link", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "hero_slider_slides_order_idx": { + "name": "hero_slider_slides_order_idx", + "columns": [ + { + "expression": "_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "hero_slider_slides_parent_id_idx": { + "name": "hero_slider_slides_parent_id_idx", + "columns": [ + { + "expression": "_parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "hero_slider_slides_image_idx": { + "name": "hero_slider_slides_image_idx", + "columns": [ + { + "expression": "image_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "hero_slider_slides_image_mobile_idx": { + "name": "hero_slider_slides_image_mobile_idx", + "columns": [ + { + "expression": "image_mobile_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "hero_slider_slides_image_id_media_id_fk": { + "name": "hero_slider_slides_image_id_media_id_fk", + "tableFrom": "hero_slider_slides", + "tableTo": "media", + "columnsFrom": [ + "image_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "hero_slider_slides_image_mobile_id_media_id_fk": { + "name": "hero_slider_slides_image_mobile_id_media_id_fk", + "tableFrom": "hero_slider_slides", + "tableTo": "media", + "columnsFrom": [ + "image_mobile_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "hero_slider_slides_parent_id_fk": { + "name": "hero_slider_slides_parent_id_fk", + "tableFrom": "hero_slider_slides", + "tableTo": "hero_slider", + "columnsFrom": [ + "_parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hero_slider": { + "name": "hero_slider", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.product_recommendations_lists": { + "name": "product_recommendations_lists", + "schema": "", + "columns": { + "_order": { + "name": "_order", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "_parent_id": { + "name": "_parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "subtitle": { + "name": "subtitle", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "product_recommendations_lists_order_idx": { + "name": "product_recommendations_lists_order_idx", + "columns": [ + { + "expression": "_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "product_recommendations_lists_parent_id_idx": { + "name": "product_recommendations_lists_parent_id_idx", + "columns": [ + { + "expression": "_parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "product_recommendations_lists_parent_id_fk": { + "name": "product_recommendations_lists_parent_id_fk", + "tableFrom": "product_recommendations_lists", + "tableTo": "product_recommendations", + "columnsFrom": [ + "_parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.product_recommendations": { + "name": "product_recommendations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3) with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.product_recommendations_rels": { + "name": "product_recommendations_rels", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "parent_id": { + "name": "parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "path": { + "name": "path", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "products_id": { + "name": "products_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "product_recommendations_rels_order_idx": { + "name": "product_recommendations_rels_order_idx", + "columns": [ + { + "expression": "order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "product_recommendations_rels_parent_idx": { + "name": "product_recommendations_rels_parent_idx", + "columns": [ + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "product_recommendations_rels_path_idx": { + "name": "product_recommendations_rels_path_idx", + "columns": [ + { + "expression": "path", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "product_recommendations_rels_products_id_idx": { + "name": "product_recommendations_rels_products_id_idx", + "columns": [ + { + "expression": "products_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "product_recommendations_rels_parent_fk": { + "name": "product_recommendations_rels_parent_fk", + "tableFrom": "product_recommendations_rels", + "tableTo": "product_recommendations", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "product_recommendations_rels_products_fk": { + "name": "product_recommendations_rels_products_fk", + "tableFrom": "product_recommendations_rels", + "tableTo": "products", + "columnsFrom": [ + "products_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.enum_users_roles": { + "name": "enum_users_roles", + "schema": "public", + "values": [ + "admin", + "editor", + "user" + ] + }, + "public.enum_products_status": { + "name": "enum_products_status", + "schema": "public", + "values": [ + "draft", + "published" + ] + }, + "public.enum_announcements_type": { + "name": "enum_announcements_type", + "schema": "public", + "values": [ + "info", + "warning", + "important", + "urgent" + ] + }, + "public.enum_announcements_status": { + "name": "enum_announcements_status", + "schema": "public", + "values": [ + "draft", + "published", + "archived" + ] + }, + "public.enum_articles_status": { + "name": "enum_articles_status", + "schema": "public", + "values": [ + "draft", + "published" + ] + }, + "public.enum_articles_category": { + "name": "enum_articles_category", + "schema": "public", + "values": [ + "news", + "tutorial", + "tech", + "review", + "industry", + "other" + ] + }, + "public.enum__articles_v_version_status": { + "name": "enum__articles_v_version_status", + "schema": "public", + "values": [ + "draft", + "published" + ] + }, + "public.enum__articles_v_version_category": { + "name": "enum__articles_v_version_category", + "schema": "public", + "values": [ + "news", + "tutorial", + "tech", + "review", + "industry", + "other" + ] + }, + "public.enum_logs_action": { + "name": "enum_logs_action", + "schema": "public", + "values": [ + "create", + "update", + "delete", + "sync", + "login", + "logout" + ] + }, + "public.enum_payload_jobs_log_task_slug": { + "name": "enum_payload_jobs_log_task_slug", + "schema": "public", + "values": [ + "inline", + "schedulePublish" + ] + }, + "public.enum_payload_jobs_log_state": { + "name": "enum_payload_jobs_log_state", + "schema": "public", + "values": [ + "failed", + "succeeded" + ] + }, + "public.enum_payload_jobs_task_slug": { + "name": "enum_payload_jobs_task_slug", + "schema": "public", + "values": [ + "inline", + "schedulePublish" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "id": "198f576a-c5d0-4f07-998b-9c04b7f3b5b9", + "prevId": "00000000-0000-0000-0000-000000000000" +} \ No newline at end of file diff --git a/src/migrations/20260212_193303.ts b/src/migrations/20260212_193303.ts new file mode 100644 index 0000000..91aa70f --- /dev/null +++ b/src/migrations/20260212_193303.ts @@ -0,0 +1,370 @@ +import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres' + +export async function up({ db, payload, req }: MigrateUpArgs): Promise { + await db.execute(sql` + CREATE TYPE "public"."enum_users_roles" AS ENUM('admin', 'editor', 'user'); + CREATE TYPE "public"."enum_announcements_type" AS ENUM('info', 'warning', 'important', 'urgent'); + CREATE TYPE "public"."enum_announcements_status" AS ENUM('draft', 'published', 'archived'); + CREATE TYPE "public"."enum_articles_status" AS ENUM('draft', 'published'); + CREATE TYPE "public"."enum_articles_category" AS ENUM('news', 'tutorial', 'tech', 'review', 'industry', 'other'); + CREATE TYPE "public"."enum__articles_v_version_status" AS ENUM('draft', 'published'); + CREATE TYPE "public"."enum__articles_v_version_category" AS ENUM('news', 'tutorial', 'tech', 'review', 'industry', 'other'); + CREATE TYPE "public"."enum_logs_action" AS ENUM('create', 'update', 'delete', 'sync', 'login', 'logout'); + CREATE TYPE "public"."enum_payload_jobs_log_task_slug" AS ENUM('inline', 'schedulePublish'); + CREATE TYPE "public"."enum_payload_jobs_log_state" AS ENUM('failed', 'succeeded'); + CREATE TYPE "public"."enum_payload_jobs_task_slug" AS ENUM('inline', 'schedulePublish'); + CREATE TABLE "users_roles" ( + "order" integer NOT NULL, + "parent_id" integer NOT NULL, + "value" "enum_users_roles", + "id" serial PRIMARY KEY NOT NULL + ); + + CREATE TABLE "announcements" ( + "id" serial PRIMARY KEY NOT NULL, + "title" varchar NOT NULL, + "type" "enum_announcements_type" DEFAULT 'info' NOT NULL, + "status" "enum_announcements_status" DEFAULT 'draft' NOT NULL, + "priority" numeric DEFAULT 0, + "summary" varchar, + "content" jsonb NOT NULL, + "published_at" timestamp(3) with time zone, + "expires_at" timestamp(3) with time zone, + "show_on_homepage" boolean DEFAULT false, + "author_id" integer, + "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, + "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL + ); + + CREATE TABLE "articles" ( + "id" serial PRIMARY KEY NOT NULL, + "title" varchar, + "status" "enum_articles_status" DEFAULT 'draft', + "slug" varchar, + "featured_image_id" integer, + "excerpt" varchar, + "content" jsonb, + "category" "enum_articles_category", + "featured" boolean DEFAULT false, + "author_id" integer, + "published_at" timestamp(3) with time zone, + "meta_title" varchar, + "meta_description" varchar, + "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, + "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL, + "_status" "enum_articles_status" DEFAULT 'draft' + ); + + CREATE TABLE "articles_texts" ( + "id" serial PRIMARY KEY NOT NULL, + "order" integer NOT NULL, + "parent_id" integer NOT NULL, + "path" varchar NOT NULL, + "text" varchar + ); + + CREATE TABLE "articles_rels" ( + "id" serial PRIMARY KEY NOT NULL, + "order" integer, + "parent_id" integer NOT NULL, + "path" varchar NOT NULL, + "articles_id" integer, + "products_id" integer + ); + + CREATE TABLE "_articles_v" ( + "id" serial PRIMARY KEY NOT NULL, + "parent_id" integer, + "version_title" varchar, + "version_status" "enum__articles_v_version_status" DEFAULT 'draft', + "version_slug" varchar, + "version_featured_image_id" integer, + "version_excerpt" varchar, + "version_content" jsonb, + "version_category" "enum__articles_v_version_category", + "version_featured" boolean DEFAULT false, + "version_author_id" integer, + "version_published_at" timestamp(3) with time zone, + "version_meta_title" varchar, + "version_meta_description" varchar, + "version_updated_at" timestamp(3) with time zone, + "version_created_at" timestamp(3) with time zone, + "version__status" "enum__articles_v_version_status" DEFAULT 'draft', + "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, + "latest" boolean, + "autosave" boolean + ); + + CREATE TABLE "_articles_v_texts" ( + "id" serial PRIMARY KEY NOT NULL, + "order" integer NOT NULL, + "parent_id" integer NOT NULL, + "path" varchar NOT NULL, + "text" varchar + ); + + CREATE TABLE "_articles_v_rels" ( + "id" serial PRIMARY KEY NOT NULL, + "order" integer, + "parent_id" integer NOT NULL, + "path" varchar NOT NULL, + "articles_id" integer, + "products_id" integer + ); + + CREATE TABLE "logs" ( + "id" serial PRIMARY KEY NOT NULL, + "action" "enum_logs_action" NOT NULL, + "collection" varchar NOT NULL, + "document_id" varchar, + "document_title" varchar, + "user_id" integer NOT NULL, + "changes" jsonb, + "ip" varchar, + "user_agent" varchar, + "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, + "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL + ); + + CREATE TABLE "payload_jobs_log" ( + "_order" integer NOT NULL, + "_parent_id" integer NOT NULL, + "id" varchar PRIMARY KEY NOT NULL, + "executed_at" timestamp(3) with time zone NOT NULL, + "completed_at" timestamp(3) with time zone NOT NULL, + "task_slug" "enum_payload_jobs_log_task_slug" NOT NULL, + "task_i_d" varchar NOT NULL, + "input" jsonb, + "output" jsonb, + "state" "enum_payload_jobs_log_state" NOT NULL, + "error" jsonb + ); + + CREATE TABLE "payload_jobs" ( + "id" serial PRIMARY KEY NOT NULL, + "input" jsonb, + "completed_at" timestamp(3) with time zone, + "total_tried" numeric DEFAULT 0, + "has_error" boolean DEFAULT false, + "error" jsonb, + "task_slug" "enum_payload_jobs_task_slug", + "queue" varchar DEFAULT 'default', + "wait_until" timestamp(3) with time zone, + "processing" boolean DEFAULT false, + "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, + "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL + ); + + CREATE TABLE "admin_settings" ( + "id" serial PRIMARY KEY NOT NULL, + "title" varchar DEFAULT '管理员设置', + "updated_at" timestamp(3) with time zone, + "created_at" timestamp(3) with time zone + ); + + CREATE TABLE "logs_manager" ( + "id" serial PRIMARY KEY NOT NULL, + "placeholder" varchar, + "updated_at" timestamp(3) with time zone, + "created_at" timestamp(3) with time zone + ); + + CREATE TABLE "hero_slider_slides" ( + "_order" integer NOT NULL, + "_parent_id" integer NOT NULL, + "id" varchar PRIMARY KEY NOT NULL, + "title" varchar NOT NULL, + "subtitle" varchar, + "image_id" integer NOT NULL, + "image_mobile_id" integer, + "link" varchar + ); + + CREATE TABLE "hero_slider" ( + "id" serial PRIMARY KEY NOT NULL, + "updated_at" timestamp(3) with time zone, + "created_at" timestamp(3) with time zone + ); + + CREATE TABLE "product_recommendations_lists" ( + "_order" integer NOT NULL, + "_parent_id" integer NOT NULL, + "id" varchar PRIMARY KEY NOT NULL, + "title" varchar NOT NULL, + "subtitle" varchar + ); + + CREATE TABLE "product_recommendations" ( + "id" serial PRIMARY KEY NOT NULL, + "enabled" boolean DEFAULT true, + "updated_at" timestamp(3) with time zone, + "created_at" timestamp(3) with time zone + ); + + CREATE TABLE "product_recommendations_rels" ( + "id" serial PRIMARY KEY NOT NULL, + "order" integer, + "parent_id" integer NOT NULL, + "path" varchar NOT NULL, + "products_id" integer + ); + + ALTER TABLE "products" ADD COLUMN "content" jsonb; + ALTER TABLE "payload_locked_documents_rels" ADD COLUMN "announcements_id" integer; + ALTER TABLE "payload_locked_documents_rels" ADD COLUMN "articles_id" integer; + ALTER TABLE "payload_locked_documents_rels" ADD COLUMN "logs_id" integer; + ALTER TABLE "users_roles" ADD CONSTRAINT "users_roles_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "announcements" ADD CONSTRAINT "announcements_author_id_users_id_fk" FOREIGN KEY ("author_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action; + ALTER TABLE "articles" ADD CONSTRAINT "articles_featured_image_id_media_id_fk" FOREIGN KEY ("featured_image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action; + ALTER TABLE "articles" ADD CONSTRAINT "articles_author_id_users_id_fk" FOREIGN KEY ("author_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action; + ALTER TABLE "articles_texts" ADD CONSTRAINT "articles_texts_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."articles"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "articles_rels" ADD CONSTRAINT "articles_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."articles"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "articles_rels" ADD CONSTRAINT "articles_rels_articles_fk" FOREIGN KEY ("articles_id") REFERENCES "public"."articles"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "articles_rels" ADD CONSTRAINT "articles_rels_products_fk" FOREIGN KEY ("products_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "_articles_v" ADD CONSTRAINT "_articles_v_parent_id_articles_id_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."articles"("id") ON DELETE set null ON UPDATE no action; + ALTER TABLE "_articles_v" ADD CONSTRAINT "_articles_v_version_featured_image_id_media_id_fk" FOREIGN KEY ("version_featured_image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action; + ALTER TABLE "_articles_v" ADD CONSTRAINT "_articles_v_version_author_id_users_id_fk" FOREIGN KEY ("version_author_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action; + ALTER TABLE "_articles_v_texts" ADD CONSTRAINT "_articles_v_texts_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."_articles_v"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "_articles_v_rels" ADD CONSTRAINT "_articles_v_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."_articles_v"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "_articles_v_rels" ADD CONSTRAINT "_articles_v_rels_articles_fk" FOREIGN KEY ("articles_id") REFERENCES "public"."articles"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "_articles_v_rels" ADD CONSTRAINT "_articles_v_rels_products_fk" FOREIGN KEY ("products_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "logs" ADD CONSTRAINT "logs_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action; + ALTER TABLE "payload_jobs_log" ADD CONSTRAINT "payload_jobs_log_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."payload_jobs"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "hero_slider_slides" ADD CONSTRAINT "hero_slider_slides_image_id_media_id_fk" FOREIGN KEY ("image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action; + ALTER TABLE "hero_slider_slides" ADD CONSTRAINT "hero_slider_slides_image_mobile_id_media_id_fk" FOREIGN KEY ("image_mobile_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action; + ALTER TABLE "hero_slider_slides" ADD CONSTRAINT "hero_slider_slides_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."hero_slider"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "product_recommendations_lists" ADD CONSTRAINT "product_recommendations_lists_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."product_recommendations"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "product_recommendations_rels" ADD CONSTRAINT "product_recommendations_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."product_recommendations"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "product_recommendations_rels" ADD CONSTRAINT "product_recommendations_rels_products_fk" FOREIGN KEY ("products_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action; + CREATE INDEX "users_roles_order_idx" ON "users_roles" USING btree ("order"); + CREATE INDEX "users_roles_parent_idx" ON "users_roles" USING btree ("parent_id"); + CREATE INDEX "announcements_author_idx" ON "announcements" USING btree ("author_id"); + CREATE INDEX "announcements_updated_at_idx" ON "announcements" USING btree ("updated_at"); + CREATE INDEX "announcements_created_at_idx" ON "announcements" USING btree ("created_at"); + CREATE UNIQUE INDEX "articles_slug_idx" ON "articles" USING btree ("slug"); + CREATE INDEX "articles_featured_image_idx" ON "articles" USING btree ("featured_image_id"); + CREATE INDEX "articles_author_idx" ON "articles" USING btree ("author_id"); + CREATE INDEX "articles_updated_at_idx" ON "articles" USING btree ("updated_at"); + CREATE INDEX "articles_created_at_idx" ON "articles" USING btree ("created_at"); + CREATE INDEX "articles__status_idx" ON "articles" USING btree ("_status"); + CREATE INDEX "articles_texts_order_parent" ON "articles_texts" USING btree ("order","parent_id"); + CREATE INDEX "articles_rels_order_idx" ON "articles_rels" USING btree ("order"); + CREATE INDEX "articles_rels_parent_idx" ON "articles_rels" USING btree ("parent_id"); + CREATE INDEX "articles_rels_path_idx" ON "articles_rels" USING btree ("path"); + CREATE INDEX "articles_rels_articles_id_idx" ON "articles_rels" USING btree ("articles_id"); + CREATE INDEX "articles_rels_products_id_idx" ON "articles_rels" USING btree ("products_id"); + CREATE INDEX "_articles_v_parent_idx" ON "_articles_v" USING btree ("parent_id"); + CREATE INDEX "_articles_v_version_version_slug_idx" ON "_articles_v" USING btree ("version_slug"); + CREATE INDEX "_articles_v_version_version_featured_image_idx" ON "_articles_v" USING btree ("version_featured_image_id"); + CREATE INDEX "_articles_v_version_version_author_idx" ON "_articles_v" USING btree ("version_author_id"); + CREATE INDEX "_articles_v_version_version_updated_at_idx" ON "_articles_v" USING btree ("version_updated_at"); + CREATE INDEX "_articles_v_version_version_created_at_idx" ON "_articles_v" USING btree ("version_created_at"); + CREATE INDEX "_articles_v_version_version__status_idx" ON "_articles_v" USING btree ("version__status"); + CREATE INDEX "_articles_v_created_at_idx" ON "_articles_v" USING btree ("created_at"); + CREATE INDEX "_articles_v_updated_at_idx" ON "_articles_v" USING btree ("updated_at"); + CREATE INDEX "_articles_v_latest_idx" ON "_articles_v" USING btree ("latest"); + CREATE INDEX "_articles_v_autosave_idx" ON "_articles_v" USING btree ("autosave"); + CREATE INDEX "_articles_v_texts_order_parent" ON "_articles_v_texts" USING btree ("order","parent_id"); + CREATE INDEX "_articles_v_rels_order_idx" ON "_articles_v_rels" USING btree ("order"); + CREATE INDEX "_articles_v_rels_parent_idx" ON "_articles_v_rels" USING btree ("parent_id"); + CREATE INDEX "_articles_v_rels_path_idx" ON "_articles_v_rels" USING btree ("path"); + CREATE INDEX "_articles_v_rels_articles_id_idx" ON "_articles_v_rels" USING btree ("articles_id"); + CREATE INDEX "_articles_v_rels_products_id_idx" ON "_articles_v_rels" USING btree ("products_id"); + CREATE INDEX "logs_collection_idx" ON "logs" USING btree ("collection"); + CREATE INDEX "logs_document_id_idx" ON "logs" USING btree ("document_id"); + CREATE INDEX "logs_user_idx" ON "logs" USING btree ("user_id"); + CREATE INDEX "logs_updated_at_idx" ON "logs" USING btree ("updated_at"); + CREATE INDEX "logs_created_at_idx" ON "logs" USING btree ("created_at"); + CREATE INDEX "payload_jobs_log_order_idx" ON "payload_jobs_log" USING btree ("_order"); + CREATE INDEX "payload_jobs_log_parent_id_idx" ON "payload_jobs_log" USING btree ("_parent_id"); + CREATE INDEX "payload_jobs_completed_at_idx" ON "payload_jobs" USING btree ("completed_at"); + CREATE INDEX "payload_jobs_total_tried_idx" ON "payload_jobs" USING btree ("total_tried"); + CREATE INDEX "payload_jobs_has_error_idx" ON "payload_jobs" USING btree ("has_error"); + CREATE INDEX "payload_jobs_task_slug_idx" ON "payload_jobs" USING btree ("task_slug"); + CREATE INDEX "payload_jobs_queue_idx" ON "payload_jobs" USING btree ("queue"); + CREATE INDEX "payload_jobs_wait_until_idx" ON "payload_jobs" USING btree ("wait_until"); + CREATE INDEX "payload_jobs_processing_idx" ON "payload_jobs" USING btree ("processing"); + CREATE INDEX "payload_jobs_updated_at_idx" ON "payload_jobs" USING btree ("updated_at"); + CREATE INDEX "payload_jobs_created_at_idx" ON "payload_jobs" USING btree ("created_at"); + CREATE INDEX "hero_slider_slides_order_idx" ON "hero_slider_slides" USING btree ("_order"); + CREATE INDEX "hero_slider_slides_parent_id_idx" ON "hero_slider_slides" USING btree ("_parent_id"); + CREATE INDEX "hero_slider_slides_image_idx" ON "hero_slider_slides" USING btree ("image_id"); + CREATE INDEX "hero_slider_slides_image_mobile_idx" ON "hero_slider_slides" USING btree ("image_mobile_id"); + CREATE INDEX "product_recommendations_lists_order_idx" ON "product_recommendations_lists" USING btree ("_order"); + CREATE INDEX "product_recommendations_lists_parent_id_idx" ON "product_recommendations_lists" USING btree ("_parent_id"); + CREATE INDEX "product_recommendations_rels_order_idx" ON "product_recommendations_rels" USING btree ("order"); + CREATE INDEX "product_recommendations_rels_parent_idx" ON "product_recommendations_rels" USING btree ("parent_id"); + CREATE INDEX "product_recommendations_rels_path_idx" ON "product_recommendations_rels" USING btree ("path"); + CREATE INDEX "product_recommendations_rels_products_id_idx" ON "product_recommendations_rels" USING btree ("products_id"); + ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_announcements_fk" FOREIGN KEY ("announcements_id") REFERENCES "public"."announcements"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_articles_fk" FOREIGN KEY ("articles_id") REFERENCES "public"."articles"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_logs_fk" FOREIGN KEY ("logs_id") REFERENCES "public"."logs"("id") ON DELETE cascade ON UPDATE no action; + CREATE INDEX "payload_locked_documents_rels_announcements_id_idx" ON "payload_locked_documents_rels" USING btree ("announcements_id"); + CREATE INDEX "payload_locked_documents_rels_articles_id_idx" ON "payload_locked_documents_rels" USING btree ("articles_id"); + CREATE INDEX "payload_locked_documents_rels_logs_id_idx" ON "payload_locked_documents_rels" USING btree ("logs_id");`) +} + +export async function down({ db, payload, req }: MigrateDownArgs): Promise { + await db.execute(sql` + ALTER TABLE "users_roles" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "announcements" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "articles" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "articles_texts" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "articles_rels" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "_articles_v" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "_articles_v_texts" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "_articles_v_rels" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "logs" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "payload_jobs_log" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "payload_jobs" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "admin_settings" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "logs_manager" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "hero_slider_slides" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "hero_slider" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "product_recommendations_lists" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "product_recommendations" DISABLE ROW LEVEL SECURITY; + ALTER TABLE "product_recommendations_rels" DISABLE ROW LEVEL SECURITY; + DROP TABLE "users_roles" CASCADE; + DROP TABLE "announcements" CASCADE; + DROP TABLE "articles" CASCADE; + DROP TABLE "articles_texts" CASCADE; + DROP TABLE "articles_rels" CASCADE; + DROP TABLE "_articles_v" CASCADE; + DROP TABLE "_articles_v_texts" CASCADE; + DROP TABLE "_articles_v_rels" CASCADE; + DROP TABLE "logs" CASCADE; + DROP TABLE "payload_jobs_log" CASCADE; + DROP TABLE "payload_jobs" CASCADE; + DROP TABLE "admin_settings" CASCADE; + DROP TABLE "logs_manager" CASCADE; + DROP TABLE "hero_slider_slides" CASCADE; + DROP TABLE "hero_slider" CASCADE; + DROP TABLE "product_recommendations_lists" CASCADE; + DROP TABLE "product_recommendations" CASCADE; + DROP TABLE "product_recommendations_rels" CASCADE; + ALTER TABLE "payload_locked_documents_rels" DROP CONSTRAINT "payload_locked_documents_rels_announcements_fk"; + + ALTER TABLE "payload_locked_documents_rels" DROP CONSTRAINT "payload_locked_documents_rels_articles_fk"; + + ALTER TABLE "payload_locked_documents_rels" DROP CONSTRAINT "payload_locked_documents_rels_logs_fk"; + + DROP INDEX "payload_locked_documents_rels_announcements_id_idx"; + DROP INDEX "payload_locked_documents_rels_articles_id_idx"; + DROP INDEX "payload_locked_documents_rels_logs_id_idx"; + ALTER TABLE "products" DROP COLUMN "content"; + ALTER TABLE "payload_locked_documents_rels" DROP COLUMN "announcements_id"; + ALTER TABLE "payload_locked_documents_rels" DROP COLUMN "articles_id"; + ALTER TABLE "payload_locked_documents_rels" DROP COLUMN "logs_id"; + DROP TYPE "public"."enum_users_roles"; + DROP TYPE "public"."enum_announcements_type"; + DROP TYPE "public"."enum_announcements_status"; + DROP TYPE "public"."enum_articles_status"; + DROP TYPE "public"."enum_articles_category"; + DROP TYPE "public"."enum__articles_v_version_status"; + DROP TYPE "public"."enum__articles_v_version_category"; + DROP TYPE "public"."enum_logs_action"; + DROP TYPE "public"."enum_payload_jobs_log_task_slug"; + DROP TYPE "public"."enum_payload_jobs_log_state"; + DROP TYPE "public"."enum_payload_jobs_task_slug";`) +} diff --git a/src/migrations/hero_slider_simplify.ts b/src/migrations/hero_slider_simplify.ts new file mode 100644 index 0000000..a1687bc --- /dev/null +++ b/src/migrations/hero_slider_simplify.ts @@ -0,0 +1,24 @@ +import { MigrateUpArgs, sql } from '@payloadcms/db-postgres' + +export async function up({ db }: MigrateUpArgs): Promise { + await db.execute( + sql`ALTER TABLE hero_slider_slides ADD COLUMN IF NOT EXISTS link TEXT;` + ) + + await db.execute( + sql`UPDATE hero_slider_slides SET link = cta_link WHERE cta_link IS NOT NULL AND cta_enabled = true;` + ) + + await db.execute( + sql`ALTER TABLE hero_slider_slides + DROP COLUMN IF EXISTS cta_enabled, + DROP COLUMN IF EXISTS cta_text, + DROP COLUMN IF EXISTS cta_style, + DROP COLUMN IF EXISTS cta_link, + DROP COLUMN IF EXISTS cta_new_tab, + DROP COLUMN IF EXISTS text_position, + DROP COLUMN IF EXISTS text_color, + DROP COLUMN IF EXISTS overlay, + DROP COLUMN IF EXISTS status;` + ) +} diff --git a/src/migrations/index.ts b/src/migrations/index.ts index 935e859..3069545 100644 --- a/src/migrations/index.ts +++ b/src/migrations/index.ts @@ -1,4 +1,7 @@ -import * as migration_20260208_171142 from './20260208_171142' +import * as migration_20260208_171142 from './20260208_171142'; +import * as migration_20260212_193303 from './20260212_193303'; +import * as migration_hero_slider_simplify from './hero_slider_simplify'; +import * as migration_product_recommendations_simplify from './product_recommendations_simplify'; export const migrations = [ { @@ -6,4 +9,17 @@ export const migrations = [ down: migration_20260208_171142.down, name: '20260208_171142', }, -] + { + up: migration_20260212_193303.up, + down: migration_20260212_193303.down, + name: '20260212_193303' + }, + { + up: migration_hero_slider_simplify.up, + name: 'hero_slider_simplify' + }, + { + up: migration_product_recommendations_simplify.up, + name: 'product_recommendations_simplify' + }, +]; diff --git a/src/migrations/product_recommendations_simplify.ts b/src/migrations/product_recommendations_simplify.ts new file mode 100644 index 0000000..94ff21b --- /dev/null +++ b/src/migrations/product_recommendations_simplify.ts @@ -0,0 +1,18 @@ +import { MigrateUpArgs, sql } from '@payloadcms/db-postgres' + +export async function up({ db }: MigrateUpArgs): Promise { + await db.execute( + sql`ALTER TABLE product_recommendations_lists + DROP COLUMN IF EXISTS slug, + DROP COLUMN IF EXISTS type, + DROP COLUMN IF EXISTS display_limit, + DROP COLUMN IF EXISTS show_view_all, + DROP COLUMN IF EXISTS view_all_link, + DROP COLUMN IF EXISTS layout, + DROP COLUMN IF EXISTS columns, + DROP COLUMN IF EXISTS show_price, + DROP COLUMN IF EXISTS show_rating, + DROP COLUMN IF EXISTS show_quick_view, + DROP COLUMN IF EXISTS status;` + ) +} diff --git a/src/payload-types.ts b/src/payload-types.ts index 34060ca..8df5ba7 100644 --- a/src/payload-types.ts +++ b/src/payload-types.ts @@ -100,10 +100,14 @@ export interface Config { globals: { 'admin-settings': AdminSetting; 'logs-manager': LogsManager; + 'hero-slider': HeroSlider; + 'product-recommendations': ProductRecommendation; }; globalsSelect: { 'admin-settings': AdminSettingsSelect | AdminSettingsSelect; 'logs-manager': LogsManagerSelect | LogsManagerSelect; + 'hero-slider': HeroSliderSelect | HeroSliderSelect; + 'product-recommendations': ProductRecommendationsSelect | ProductRecommendationsSelect; }; locale: null; user: User; @@ -834,6 +838,68 @@ export interface LogsManager { updatedAt?: string | null; createdAt?: string | null; } +/** + * Manage homepage hero slider/banner + * + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "hero-slider". + */ +export interface HeroSlider { + id: number; + /** + * Add slides to the hero slider (drag to reorder) + */ + slides?: + | { + title: string; + subtitle?: string | null; + /** + * Recommended: 1920x800px + */ + image: number | Media; + /** + * Optional. Recommended: 750x1000px + */ + imageMobile?: (number | null) | Media; + /** + * Where to go when clicked (e.g., /products) + */ + link?: string | null; + id?: string | null; + }[] + | null; + updatedAt?: string | null; + createdAt?: string | null; +} +/** + * Manage product recommendation lists for homepage and other pages + * + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "product-recommendations". + */ +export interface ProductRecommendation { + id: number; + /** + * Toggle to show/hide product recommendations + */ + enabled?: boolean | null; + /** + * Create multiple product recommendation lists (e.g., Hot Items, New Arrivals, Limited Offers) + */ + lists?: + | { + title: string; + subtitle?: string | null; + /** + * Select and drag to reorder products + */ + products?: (number | Product)[] | null; + id?: string | null; + }[] + | null; + updatedAt?: string | null; + createdAt?: string | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "admin-settings_select". @@ -854,6 +920,43 @@ export interface LogsManagerSelect { createdAt?: T; globalType?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "hero-slider_select". + */ +export interface HeroSliderSelect { + slides?: + | T + | { + title?: T; + subtitle?: T; + image?: T; + imageMobile?: T; + link?: T; + id?: T; + }; + updatedAt?: T; + createdAt?: T; + globalType?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "product-recommendations_select". + */ +export interface ProductRecommendationsSelect { + enabled?: T; + lists?: + | T + | { + title?: T; + subtitle?: T; + products?: T; + id?: T; + }; + updatedAt?: T; + createdAt?: T; + globalType?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "TaskSchedulePublish". diff --git a/src/payload.config.ts b/src/payload.config.ts index 2c57bab..d99058c 100644 --- a/src/payload.config.ts +++ b/src/payload.config.ts @@ -13,6 +13,8 @@ import { Articles } from './collections/Articles' import { Logs } from './collections/Logs' import { AdminSettings } from './globals/AdminSettings' import { LogsManager } from './globals/LogsManager' +import { HeroSlider } from './globals/HeroSlider' +import { ProductRecommendations } from './globals/ProductRecommendations' import { s3Storage } from '@payloadcms/storage-s3' import { en } from '@payloadcms/translations/languages/en' import { zh } from '@payloadcms/translations/languages/zh' @@ -45,7 +47,7 @@ export default buildConfig({ fallbackLanguage: 'zh', }, collections: [Users, Media, Products, Announcements, Articles, Logs], - globals: [AdminSettings, LogsManager], + globals: [AdminSettings, LogsManager, HeroSlider, ProductRecommendations], editor: lexicalEditor(), secret: process.env.PAYLOAD_SECRET || '', typescript: {