ca-grow-ops-manager/backend/prisma/seed.js
fullsizemalt 0c970cadb7
Some checks failed
Deploy to Production / deploy (push) Failing after 0s
Test / backend-test (push) Failing after 0s
Test / frontend-test (push) Failing after 0s
fix(seed): Remove invalid createdById from Task creation in seed.js
2025-12-11 11:57:42 -08:00

371 lines
15 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const { PrismaClient, RoomType } = require('@prisma/client');
const bcrypt = require('bcryptjs');
const prisma = new PrismaClient();
// Demo data marker - all demo entities use this prefix for easy identification
const DEMO_PREFIX = '[DEMO]';
async function hashPassword(password) {
return bcrypt.hash(password, 10);
}
async function main() {
console.log('🌱 Seeding database with demo data...\n');
// ==================== ROLES ====================
console.log('📋 Creating Roles...');
const rolesData = [
{
name: 'Facility Owner',
description: 'Full access to all features and settings',
permissions: { admin: true, all: true },
isSystem: true
},
{
name: 'Manager',
description: 'Operational control and reporting',
permissions: {
users: { view: true, manage: true },
tasks: { view: true, manage: true, assign: true },
inventory: { view: true, manage: true },
reports: { view: true, export: true },
visitors: { view: true, manage: true },
compliance: { view: true }
},
isSystem: true
},
{
name: 'Grower',
description: 'Plant care and daily operations',
permissions: {
tasks: { view: true, complete: true },
inventory: { view: true },
batches: { view: true, update: true },
rooms: { view: true }
},
isSystem: true
},
{
name: 'Worker',
description: 'Basic task completion and logging',
permissions: {
tasks: { view: true, complete: true },
timeclock: { view: true, punch: true }
},
isSystem: true
},
{
name: 'Viewer',
description: 'Read-only access to dashboards',
permissions: {
dashboard: { view: true },
reports: { view: true }
},
isSystem: true
}
];
for (const r of rolesData) {
const existing = await prisma.role.findUnique({ where: { name: r.name } });
if (!existing) {
await prisma.role.create({ data: r });
console.log(` ✓ Created Role: ${r.name}`);
}
}
const ownerRole = await prisma.role.findUnique({ where: { name: 'Facility Owner' } });
const managerRole = await prisma.role.findUnique({ where: { name: 'Manager' } });
const cultivatorRole = await prisma.role.findUnique({ where: { name: 'Grower' } });
const workerRole = await prisma.role.findUnique({ where: { name: 'Worker' } });
// ==================== USERS ====================
console.log('\n👥 Creating Demo Users...');
const usersData = [
{
email: 'admin@runfoo.run',
password: 'password123',
name: 'Travis (Owner)',
role: 'OWNER',
roleId: ownerRole?.id,
rate: 100.00
},
{
email: 'manager@demo.local',
password: 'demo1234',
name: `${DEMO_PREFIX} Sarah Chen`,
role: 'MANAGER',
roleId: managerRole?.id,
rate: 45.00
},
{
email: 'cultivator@demo.local',
password: 'demo1234',
name: `${DEMO_PREFIX} Mike Thompson`,
role: 'GROWER',
roleId: cultivatorRole?.id,
rate: 28.00
},
{
email: 'worker@demo.local',
password: 'demo1234',
name: `${DEMO_PREFIX} Alex Rivera`,
role: 'STAFF',
roleId: workerRole?.id,
rate: 22.00
}
];
for (const u of usersData) {
const existing = await prisma.user.findUnique({ where: { email: u.email } });
if (!existing) {
const passwordHash = await hashPassword(u.password);
await prisma.user.create({
data: {
email: u.email,
passwordHash,
name: u.name,
role: u.role,
roleId: u.roleId,
rate: u.rate
}
});
console.log(` ✓ Created User: ${u.name} (${u.email})`);
}
}
// ==================== ROOMS ====================
console.log('\n🏠 Creating Demo Rooms...');
const rooms = [
{ name: `${DEMO_PREFIX} Veg Room 1`, type: RoomType.VEG, sqft: 1200, capacity: 500, targetTemp: 78, targetHumidity: 65 },
{ name: `${DEMO_PREFIX} Veg Room 2`, type: RoomType.VEG, sqft: 1000, capacity: 400, targetTemp: 78, targetHumidity: 65 },
{ name: `${DEMO_PREFIX} Flower Room A`, type: RoomType.FLOWER, sqft: 2500, capacity: 300, targetTemp: 75, targetHumidity: 50 },
{ name: `${DEMO_PREFIX} Flower Room B`, type: RoomType.FLOWER, sqft: 2500, capacity: 300, targetTemp: 75, targetHumidity: 50 },
{ name: `${DEMO_PREFIX} Flower Room C`, type: RoomType.FLOWER, sqft: 2000, capacity: 250, targetTemp: 75, targetHumidity: 50 },
{ name: `${DEMO_PREFIX} Dry Room`, type: RoomType.DRY, sqft: 800, capacity: 100, targetTemp: 60, targetHumidity: 55 },
{ name: `${DEMO_PREFIX} Cure Room`, type: RoomType.CURE, sqft: 600, capacity: 50, targetTemp: 62, targetHumidity: 60 },
{ name: `${DEMO_PREFIX} Mother Room`, type: RoomType.MOTHER, sqft: 400, capacity: 50, targetTemp: 76, targetHumidity: 60 },
];
const createdRooms = [];
for (const r of rooms) {
let room = await prisma.room.findFirst({ where: { name: r.name } });
if (!room) {
room = await prisma.room.create({ data: r });
console.log(` ✓ Created Room: ${r.name}`);
}
createdRooms.push(room);
}
// ==================== BATCHES ====================
console.log('\n🌱 Creating Demo Batches...');
const batchesData = [
{
name: `${DEMO_PREFIX} Gorilla Glue #4 - Batch 001`,
strain: 'Gorilla Glue #4',
status: 'ACTIVE',
stage: 'FLOWERING',
source: 'CLONE',
plantCount: 450,
startDate: new Date(Date.now() - 45 * 24 * 60 * 60 * 1000), // 45 days ago
roomId: createdRooms.find(r => r.name.includes('Flower Room A'))?.id
},
{
name: `${DEMO_PREFIX} Blue Dream - Batch 002`,
strain: 'Blue Dream',
status: 'ACTIVE',
stage: 'VEGETATIVE',
source: 'CLONE',
plantCount: 300,
startDate: new Date(Date.now() - 20 * 24 * 60 * 60 * 1000), // 20 days ago
roomId: createdRooms.find(r => r.name.includes('Veg Room 1'))?.id
},
{
name: `${DEMO_PREFIX} Wedding Cake - Batch 003`,
strain: 'Wedding Cake',
status: 'ACTIVE',
stage: 'FLOWERING',
source: 'CLONE',
plantCount: 400,
startDate: new Date(Date.now() - 10 * 24 * 60 * 60 * 1000), // 10 days ago (Just flipped)
roomId: createdRooms.find(r => r.name.includes('Flower Room B'))?.id
},
{
name: `${DEMO_PREFIX} Purple Punch - Batch 004`,
strain: 'Purple Punch',
status: 'ACTIVE',
stage: 'DRYING',
source: 'CLONE',
plantCount: 30,
startDate: new Date(Date.now() - 75 * 24 * 60 * 60 * 1000), // 75 days ago
roomId: createdRooms.find(r => r.name.includes('Dry Room'))?.id
},
{
name: `${DEMO_PREFIX} Gelato - Batch 005`,
strain: 'Gelato #41',
status: 'ACTIVE',
stage: 'CLONE_IN',
source: 'CLONE',
plantCount: 60,
startDate: new Date(), // Today
roomId: createdRooms.find(r => r.name.includes('Veg Room 2'))?.id
}
];
const createdBatches = [];
for (const b of batchesData) {
let batch = await prisma.batch.findFirst({ where: { name: b.name } });
if (!batch) {
batch = await prisma.batch.create({ data: b });
console.log(` ✓ Created Batch: ${b.name} (${b.stage})`);
}
createdBatches.push(batch);
}
// ==================== IPM SCHEDULES ====================
console.log('\n🛡 Creating IPM Schedules...');
for (const batch of createdBatches) {
if (batch.stage === 'VEGETATIVE' || batch.stage === 'FLOWERING') {
const existing = await prisma.iPMSchedule.findFirst({ where: { batchId: batch.id } });
if (!existing) {
const nextTreatment = new Date();
nextTreatment.setDate(nextTreatment.getDate() + Math.floor(Math.random() * 5) - 2); // -2 to +2 days
await prisma.iPMSchedule.create({
data: {
batchId: batch.id,
product: 'Pyganic 5.0',
intervalDays: 10,
nextTreatment
}
});
console.log(` ✓ Created IPM Schedule for: ${batch.name}`);
}
}
}
// ==================== SUPPLIES ====================
console.log('\n📦 Creating Demo Supplies...');
const supplies = [
{ name: `${DEMO_PREFIX} Nitrile Gloves (L)`, category: 'PPE', quantity: 5, minThreshold: 10, unit: 'box', location: 'Ante Room', vendor: 'Uline' },
{ name: `${DEMO_PREFIX} Nitrile Gloves (M)`, category: 'PPE', quantity: 8, minThreshold: 10, unit: 'box', location: 'Ante Room', vendor: 'Uline' },
{ name: `${DEMO_PREFIX} Tyvek Suits`, category: 'PPE', quantity: 25, minThreshold: 20, unit: 'each', location: 'Ante Room', vendor: 'Uline' },
{ name: `${DEMO_PREFIX} Hypochlorous Acid`, category: 'CLEANING', quantity: 12, minThreshold: 5, unit: 'gallon', location: 'Janitor Closet', vendor: 'Athena' },
{ name: `${DEMO_PREFIX} Isopropyl Alcohol 99%`, category: 'CLEANING', quantity: 6, minThreshold: 4, unit: 'gallon', location: 'Trim Room', vendor: 'GrowGen' },
{ name: `${DEMO_PREFIX} Rockwool Cubes 4"`, category: 'OTHER', quantity: 450, minThreshold: 200, unit: 'cube', location: 'Veg Storage', vendor: 'GrowGen' },
{ name: `${DEMO_PREFIX} Coco Coir`, category: 'OTHER', quantity: 15, minThreshold: 10, unit: 'bag', location: 'Veg Storage', vendor: 'Botanicare' },
{ name: `${DEMO_PREFIX} Trimmers (Fiskars)`, category: 'MAINTENANCE', quantity: 12, minThreshold: 15, unit: 'pair', location: 'Trim Room', vendor: 'Amazon' },
{ name: `${DEMO_PREFIX} Pruning Shears`, category: 'MAINTENANCE', quantity: 8, minThreshold: 6, unit: 'pair', location: 'Flower Room A', vendor: 'Amazon' },
{ name: `${DEMO_PREFIX} pH Test Kit`, category: 'MAINTENANCE', quantity: 3, minThreshold: 2, unit: 'kit', location: 'Nutrient Mix Station', vendor: 'Bluelab' },
];
for (const s of supplies) {
const existing = await prisma.supplyItem.findFirst({ where: { name: s.name } });
if (!existing) {
await prisma.supplyItem.create({ data: s });
console.log(` ✓ Created Supply: ${s.name} (qty: ${s.quantity})`);
}
}
// ==================== TASKS ====================
console.log('\n✅ Creating Demo Tasks...');
const manager = await prisma.user.findFirst({ where: { email: 'manager@demo.local' } });
const cultivator = await prisma.user.findFirst({ where: { email: 'cultivator@demo.local' } });
const tasksData = [
{
title: `${DEMO_PREFIX} Morning Walkthrough - Veg Rooms`,
description: 'Check all veg rooms for pest issues, water levels, and plant health',
status: 'PENDING',
priority: 'HIGH',
dueDate: new Date()
},
{
title: `${DEMO_PREFIX} IPM Treatment - Flower Room A`,
description: 'Apply Pyganic 5.0 root drench as per schedule',
status: 'IN_PROGRESS',
priority: 'HIGH',
dueDate: new Date()
},
{
title: `${DEMO_PREFIX} Trim Batch 004 - Purple Punch`,
description: 'Process dried material from Batch 004',
status: 'PENDING',
priority: 'MEDIUM',
dueDate: new Date(Date.now() + 24 * 60 * 60 * 1000) // Tomorrow
},
{
title: `${DEMO_PREFIX} Inventory Audit - PPE Supplies`,
description: 'Count and verify PPE stock levels, update system',
status: 'PENDING',
priority: 'LOW',
dueDate: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000) // 3 days
},
{
title: `${DEMO_PREFIX} Equipment Maintenance - HVAC Check`,
description: 'Quarterly HVAC filter replacement and system check',
status: 'COMPLETED',
priority: 'MEDIUM',
dueDate: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000) // 2 days ago
}
];
for (const t of tasksData) {
const existing = await prisma.task.findFirst({ where: { title: t.title } });
if (!existing) {
await prisma.task.create({
data: {
...t,
assignedToId: cultivator?.id,
batchId: createdBatches[0]?.id
}
});
console.log(` ✓ Created Task: ${t.title} (${t.status})`);
}
}
// ==================== ANNOUNCEMENTS ====================
console.log('\n📢 Creating Demo Announcements...');
const announcementsData = [
{
title: `${DEMO_PREFIX} Welcome to 777 Wolfpack Grow Ops`,
body: 'This is a demo environment. All data shown is sample data for testing purposes. Login credentials: admin@runfoo.run / password123',
priority: 'INFO',
requiresAck: false,
createdById: manager?.id
},
{
title: `${DEMO_PREFIX} Scheduled Facility Inspection - Dec 15`,
body: 'State inspector visit scheduled for December 15th. Please ensure all compliance documentation is up to date.',
priority: 'WARNING',
requiresAck: true,
createdById: manager?.id
}
];
for (const a of announcementsData) {
if (a.createdById) {
const existing = await prisma.announcement.findFirst({ where: { title: a.title } });
if (!existing) {
await prisma.announcement.create({ data: a });
console.log(` ✓ Created Announcement: ${a.title}`);
}
}
}
console.log('\n✨ Seeding complete!\n');
console.log('Demo Login Credentials:');
console.log(' Owner: admin@runfoo.run / password123');
console.log(' Manager: manager@demo.local / demo1234');
console.log(' Cultivator: cultivator@demo.local / demo1234');
console.log(' Worker: worker@demo.local / demo1234');
}
main()
.catch((e) => {
console.error('Seeding failed:', e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});