diff --git a/DEPLOYMENT_GUIDE.md b/DEPLOYMENT_GUIDE.md index 7d1bdad..964c33c 100644 --- a/DEPLOYMENT_GUIDE.md +++ b/DEPLOYMENT_GUIDE.md @@ -193,8 +193,8 @@ bun run prisma/seed.cjs ``` ระบบจะสร้าง: -- เมนูพื้นฐาน -- ข้อมูลจำลอง (แบรนด์, สินค้า, กลิ่น) +- เมนูพื้นฐาน (Core Menus) +- ข้อมูลพื้นฐาน (แบรนด์, หมวดหมู่ - ไม่ seed สินค้า) - บัญชี Admin (`admin` / `homaroma123`) --- diff --git a/apps/backend/prisma/seed.cjs b/apps/backend/prisma/seed.cjs index 38f3ca2..7b8a1c0 100644 --- a/apps/backend/prisma/seed.cjs +++ b/apps/backend/prisma/seed.cjs @@ -51,40 +51,7 @@ const categoryConfigs = [ ]; async function main() { - process.stdout.write('🚀 Starting Advanced Seeding (Products & Variants)...\n'); - - // Load or create category description files - const descriptionsDir = path.join(__dirname, 'descriptions'); - if (!fs.existsSync(descriptionsDir)) { - fs.mkdirSync(descriptionsDir); - } - - const categoryDescriptions = {}; - for (const config of categoryConfigs) { - const safeName = config.name.replace(/\s+/g, '_'); - const descPath = path.join(descriptionsDir, `${safeName}.txt`); - - // Auto-create with default template if not exists - if (!fs.existsSync(descPath)) { - const defaultDesc = `ผลิตภัณฑ์ ${config.name} กลิ่น {{brand}} มอบประสบการณ์ความหอมที่ผ่อนคลายและสดชื่น ช่วยให้บรรยากาศในห้องของคุณน่าอยู่มากยิ่งขึ้น`; - fs.writeFileSync(descPath, defaultDesc, 'utf8'); - } - - categoryDescriptions[config.name] = fs.readFileSync(descPath, 'utf8'); - - // Auto-create category details - const detailsDir = path.join(__dirname, 'details'); - if (!fs.existsSync(detailsDir)) { - fs.mkdirSync(detailsDir); - } - const detailPath = path.join(detailsDir, `${safeName}.txt`); - if (!fs.existsSync(detailPath)) { - const defaultDetail = `รายละเอียดฉบับเต็มของ ${config.name} กลิ่น {{brand}}\n- ส่วนประกอบนำเข้าคุณภาพสูง\n- กระจายความหอมได้ยาวนานในห้อง\n- ปลอดภัยต่อสุขภาพและเหมาะสำหรับทุกคนในครอบครัว`; - fs.writeFileSync(detailPath, defaultDetail, 'utf8'); - } - categoryConfigs[config.name] = categoryConfigs[config.name] || {}; - categoryConfigs[config.name].detailsTemplate = fs.readFileSync(detailPath, 'utf8'); - } + process.stdout.write('🚀 Starting System Seeding (Admin, Menus, Brands, Categories)...\n'); // 0. Seed Admin User await seedAdmin(prisma); @@ -131,119 +98,23 @@ async function main() { update: {}, create: { name: config.name } }); - categories.push({ ...c, allowedSizes: config.sizes, priceMap: config.priceMap, detailsTemplate: categoryConfigs[config.name].detailsTemplate }); + categories.push(c); } process.stdout.write(`✅ Seeded ${categories.length} Categories.\n`); - // 2. Cross Brands x Categories to create Products - process.stdout.write('📦 Generating Products and Variants...\n'); - let productCount = 0; - let variantCount = 0; - - for (const brand of brands) { - for (const category of categories) { - const productName = `${brand.name} ${category.name}`; - - // Get category description template and replace {{brand}} - let productDescription = categoryDescriptions[category.name] || `Product ${brand.name} in category ${category.name}`; - productDescription = productDescription.replace(/{{brand}}/g, brand.name); - productDescription = productDescription.replace(/{{scent}}/g, brand.name); - - let productDetails = category.detailsTemplate || ''; - productDetails = productDetails.replace(/{{brand}}/g, brand.name); - productDetails = productDetails.replace(/{{scent}}/g, brand.name); - - // Upsert Product without unique constraint on brandId + categoryId - let product = await prisma.product.findFirst({ - where: { brandId: brand.id, categoryId: category.id } - }); - if (product) { - product = await prisma.product.update({ - where: { id: product.id }, - data: { - name: productName, - description: productDescription, - details: productDetails - } - }); - } else { - product = await prisma.product.create({ - data: { - name: productName, - brandId: brand.id, - categoryId: category.id, - description: productDescription, - details: productDetails, - options: category.allowedSizes.length > 0 ? [{ name: "Size", values: category.allowedSizes }] : [] - } - }); - } - productCount++; - - // 3. Create Default Product Image - // Using existing category-based image paths as initial seed data - const defaultImagePath = category.name === 'Oil Ozone' || category.name === 'Aroma Oil' || category.name === 'Car Diffuser' - ? '/images/oil_ozone.png' - : '/images/reed_diffuser.png'; - - await prisma.productImage.upsert({ - where: { id: (product.id * 10) + 1 }, // Pseudo-stable ID for seed - update: { url: defaultImagePath }, - create: { - id: (product.id * 10) + 1, - productId: product.id, - url: defaultImagePath, - order: 0 - } - }).catch(() => { - // Fallback for cases where ID might conflict or upsert on non-unique field - return prisma.productImage.create({ - data: { - productId: product.id, - url: defaultImagePath, - order: 0 - } - }); - }); - - // 4. Create Variants (Sizes) with prices from priceMap - for (const size of category.allowedSizes) { - const price = category.priceMap?.[size] ?? 0; - await prisma.productVariant.upsert({ - where: { - productId_option1_option2_option3: { - productId: product.id, - option1: size, - option2: "", - option3: "" - } - }, - update: { price }, // อัปเดตราคาเมื่อ re-seed - create: { - productId: product.id, - sku: `${brand.id}-${category.id}-${size}`.replace(/\s+/g, '-').toUpperCase(), - option1: size, - option2: "", - option3: "", - price: price - } - }); - variantCount++; - } - } - process.stdout.write(`.`); // Progress indicator - } + // Skipped product & variant seeding per configuration process.stdout.write(`\n✨ Seeding Complete!\n`); process.stdout.write(`📊 Summary:\n`); + process.stdout.write(` - Admin: 1 (admin / homaroma123)\n`); + process.stdout.write(` - Menus: ${coreMenus.length}\n`); process.stdout.write(` - Brands: ${brands.length}\n`); process.stdout.write(` - Categories: ${categories.length}\n`); - process.stdout.write(` - Products: ${productCount}\n`); - process.stdout.write(` - Variants: ${variantCount}\n`); + process.stdout.write(` - Products: 0 (Skipped per configuration)\n`); + // Fix PostgreSQL sequence desync for tables where we hardcoded IDs process.stdout.write('🔄 Resetting sequences for hardcoded ID tables...\n'); await prisma.$executeRawUnsafe(`SELECT setval('"MenuItem_id_seq"', COALESCE((SELECT MAX(id) FROM "MenuItem") + 1, 1), false);`); - await prisma.$executeRawUnsafe(`SELECT setval('"ProductImage_id_seq"', COALESCE((SELECT MAX(id) FROM "ProductImage") + 1, 1), false);`); process.stdout.write('✅ Sequences reset successfully.\n'); }