import { PrismaClient, OrderStatus, SubscriptionPlan, SubscriptionTier, SubscriptionStatus, UserStatus, LogLevel } from '@prisma/client' import bcrypt from 'bcryptjs' const { hash } = bcrypt const prisma = new PrismaClient() // Random data helpers const companies = [ 'Acme Corp', 'TechStart Inc', 'Digital Solutions', 'CloudFirst Ltd', 'InnovateTech', 'DataDriven Co', 'SmartBiz Solutions', 'FutureTech Labs', 'AgileWorks', 'NextGen Systems', null, null, null ] const domains = [ 'acme.letsbe.cloud', 'techstart.letsbe.cloud', 'digital.letsbe.cloud', 'cloudfirst.letsbe.cloud', 'innovate.letsbe.cloud', 'datadriven.letsbe.cloud', 'smartbiz.letsbe.cloud', 'futuretech.letsbe.cloud', 'agileworks.letsbe.cloud', 'nextgen.letsbe.cloud', 'startup.letsbe.cloud', 'enterprise.letsbe.cloud', 'demo.letsbe.cloud', 'test.letsbe.cloud', 'dev.letsbe.cloud' ] const toolSets = { basic: ['nextcloud', 'keycloak'], standard: ['nextcloud', 'keycloak', 'minio', 'poste'], advanced: ['nextcloud', 'keycloak', 'minio', 'poste', 'n8n', 'filebrowser'], full: ['nextcloud', 'keycloak', 'minio', 'poste', 'n8n', 'filebrowser', 'portainer', 'grafana'], } const logMessages = { PAYMENT_CONFIRMED: ['Payment received via Stripe', 'Order confirmed'], AWAITING_SERVER: ['Waiting for server allocation', 'Server request submitted to provider'], SERVER_READY: ['Server provisioned', 'SSH access verified', 'Root password received'], DNS_PENDING: ['DNS records submitted', 'Waiting for DNS propagation'], DNS_READY: ['DNS records verified', 'Domain is resolving correctly'], PROVISIONING: [ 'Starting provisioning process', 'Downloading Docker images', 'Configuring Nginx reverse proxy', 'Installing Keycloak', 'Configuring Nextcloud', 'Setting up MinIO storage', 'Configuring email server', 'Running health checks', ], FULFILLED: ['Provisioning complete', 'All services healthy', 'Welcome email sent'], EMAIL_CONFIGURED: ['SMTP credentials configured', 'Email sending verified'], FAILED: ['Provisioning failed', 'See error details below'], } function randomDate(daysAgo: number): Date { const date = new Date() date.setDate(date.getDate() - Math.floor(Math.random() * daysAgo)) date.setHours(Math.floor(Math.random() * 24)) date.setMinutes(Math.floor(Math.random() * 60)) return date } function randomChoice(arr: T[]): T { return arr[Math.floor(Math.random() * arr.length)] } async function main() { console.log('Starting seed...') // 1. Create admin user if not exists const adminEmail = process.env.ADMIN_EMAIL || 'admin@letsbe.solutions' const adminPassword = process.env.ADMIN_PASSWORD || 'admin123' const existingAdmin = await prisma.staff.findUnique({ where: { email: adminEmail }, }) if (!existingAdmin) { const passwordHash = await hash(adminPassword, 12) await prisma.staff.create({ data: { email: adminEmail, passwordHash, name: 'Admin', role: 'ADMIN', }, }) console.log(`Created admin user: ${adminEmail}`) } else { console.log(`Admin user ${adminEmail} already exists`) } // 2. Create support staff const supportEmail = 'support@letsbe.solutions' const existingSupport = await prisma.staff.findUnique({ where: { email: supportEmail }, }) if (!existingSupport) { const passwordHash = await hash('support123', 12) await prisma.staff.create({ data: { email: supportEmail, passwordHash, name: 'Support Agent', role: 'SUPPORT', }, }) console.log(`Created support user: ${supportEmail}`) } // 3. Create test customers const customerData = [ { email: 'john@acme.com', name: 'John Smith', company: 'Acme Corp', status: UserStatus.ACTIVE }, { email: 'sarah@techstart.io', name: 'Sarah Johnson', company: 'TechStart Inc', status: UserStatus.ACTIVE }, { email: 'mike@cloudfirst.co', name: 'Mike Davis', company: 'CloudFirst Ltd', status: UserStatus.ACTIVE }, { email: 'emma@digital.io', name: 'Emma Wilson', company: 'Digital Solutions', status: UserStatus.ACTIVE }, { email: 'david@innovate.co', name: 'David Brown', company: 'InnovateTech', status: UserStatus.ACTIVE }, { email: 'lisa@datadriven.io', name: 'Lisa Chen', company: 'DataDriven Co', status: UserStatus.ACTIVE }, { email: 'james@smartbiz.com', name: 'James Miller', company: 'SmartBiz Solutions', status: UserStatus.ACTIVE }, { email: 'amy@futuretech.io', name: 'Amy Taylor', company: 'FutureTech Labs', status: UserStatus.PENDING_VERIFICATION }, { email: 'robert@agile.co', name: 'Robert Anderson', company: 'AgileWorks', status: UserStatus.ACTIVE }, { email: 'jennifer@nextgen.io', name: 'Jennifer Lee', company: 'NextGen Systems', status: UserStatus.SUSPENDED }, { email: 'freelancer@gmail.com', name: 'Alex Freelancer', company: null, status: UserStatus.ACTIVE }, { email: 'startup@mail.com', name: 'Startup Founder', company: null, status: UserStatus.PENDING_VERIFICATION }, ] const customers: { id: string; email: string }[] = [] for (const customer of customerData) { const existing = await prisma.user.findUnique({ where: { email: customer.email }, }) if (!existing) { const passwordHash = await hash('customer123', 12) const created = await prisma.user.create({ data: { email: customer.email, passwordHash, name: customer.name, company: customer.company, status: customer.status, emailVerified: customer.status === UserStatus.ACTIVE ? new Date() : null, }, }) customers.push({ id: created.id, email: created.email }) console.log(`Created customer: ${customer.email}`) } else { customers.push({ id: existing.id, email: existing.email }) console.log(`Customer ${customer.email} already exists`) } } // 4. Create subscriptions for customers const subscriptionConfigs = [ { plan: SubscriptionPlan.ENTERPRISE, tier: SubscriptionTier.HUB_DASHBOARD, status: SubscriptionStatus.ACTIVE }, { plan: SubscriptionPlan.PRO, tier: SubscriptionTier.HUB_DASHBOARD, status: SubscriptionStatus.ACTIVE }, { plan: SubscriptionPlan.PRO, tier: SubscriptionTier.ADVANCED, status: SubscriptionStatus.ACTIVE }, { plan: SubscriptionPlan.STARTER, tier: SubscriptionTier.ADVANCED, status: SubscriptionStatus.ACTIVE }, { plan: SubscriptionPlan.STARTER, tier: SubscriptionTier.ADVANCED, status: SubscriptionStatus.ACTIVE }, { plan: SubscriptionPlan.PRO, tier: SubscriptionTier.HUB_DASHBOARD, status: SubscriptionStatus.PAST_DUE }, { plan: SubscriptionPlan.STARTER, tier: SubscriptionTier.ADVANCED, status: SubscriptionStatus.ACTIVE }, { plan: SubscriptionPlan.TRIAL, tier: SubscriptionTier.HUB_DASHBOARD, status: SubscriptionStatus.TRIAL }, { plan: SubscriptionPlan.ENTERPRISE, tier: SubscriptionTier.HUB_DASHBOARD, status: SubscriptionStatus.CANCELED }, { plan: SubscriptionPlan.STARTER, tier: SubscriptionTier.ADVANCED, status: SubscriptionStatus.ACTIVE }, { plan: SubscriptionPlan.TRIAL, tier: SubscriptionTier.ADVANCED, status: SubscriptionStatus.TRIAL }, { plan: SubscriptionPlan.TRIAL, tier: SubscriptionTier.HUB_DASHBOARD, status: SubscriptionStatus.TRIAL }, ] for (let i = 0; i < customers.length; i++) { const customer = customers[i] const config = subscriptionConfigs[i] || subscriptionConfigs[0] const existingSub = await prisma.subscription.findFirst({ where: { userId: customer.id }, }) if (!existingSub) { await prisma.subscription.create({ data: { userId: customer.id, plan: config.plan, tier: config.tier, status: config.status, tokenLimit: config.plan === SubscriptionPlan.ENTERPRISE ? 100000 : config.plan === SubscriptionPlan.PRO ? 50000 : config.plan === SubscriptionPlan.STARTER ? 20000 : 10000, tokensUsed: Math.floor(Math.random() * 5000), trialEndsAt: config.status === SubscriptionStatus.TRIAL ? new Date(Date.now() + 14 * 24 * 60 * 60 * 1000) : null, }, }) console.log(`Created subscription for: ${customer.email}`) } } // 5. Create orders with various statuses const orderConfigs = [ // Orders in various pipeline stages { status: OrderStatus.PAYMENT_CONFIRMED, tier: SubscriptionTier.HUB_DASHBOARD }, { status: OrderStatus.PAYMENT_CONFIRMED, tier: SubscriptionTier.ADVANCED }, { status: OrderStatus.AWAITING_SERVER, tier: SubscriptionTier.HUB_DASHBOARD }, { status: OrderStatus.AWAITING_SERVER, tier: SubscriptionTier.ADVANCED }, { status: OrderStatus.SERVER_READY, tier: SubscriptionTier.HUB_DASHBOARD }, { status: OrderStatus.DNS_PENDING, tier: SubscriptionTier.ADVANCED }, { status: OrderStatus.DNS_PENDING, tier: SubscriptionTier.HUB_DASHBOARD }, { status: OrderStatus.DNS_READY, tier: SubscriptionTier.HUB_DASHBOARD }, { status: OrderStatus.DNS_READY, tier: SubscriptionTier.ADVANCED }, { status: OrderStatus.PROVISIONING, tier: SubscriptionTier.HUB_DASHBOARD }, { status: OrderStatus.FULFILLED, tier: SubscriptionTier.ADVANCED }, { status: OrderStatus.FULFILLED, tier: SubscriptionTier.HUB_DASHBOARD }, { status: OrderStatus.FULFILLED, tier: SubscriptionTier.ADVANCED }, { status: OrderStatus.EMAIL_CONFIGURED, tier: SubscriptionTier.HUB_DASHBOARD }, { status: OrderStatus.EMAIL_CONFIGURED, tier: SubscriptionTier.ADVANCED }, { status: OrderStatus.FAILED, tier: SubscriptionTier.HUB_DASHBOARD }, ] for (let i = 0; i < orderConfigs.length; i++) { const config = orderConfigs[i] const customer = customers[i % customers.length] const domain = domains[i % domains.length] const existingOrder = await prisma.order.findFirst({ where: { domain }, }) if (!existingOrder) { const tools = config.tier === SubscriptionTier.HUB_DASHBOARD ? toolSets.full : randomChoice([toolSets.basic, toolSets.standard, toolSets.advanced]) const createdAt = randomDate(30) const serverStatuses: OrderStatus[] = [ OrderStatus.SERVER_READY, OrderStatus.DNS_PENDING, OrderStatus.DNS_READY, OrderStatus.PROVISIONING, OrderStatus.FULFILLED, OrderStatus.EMAIL_CONFIGURED, OrderStatus.FAILED ] const hasServer = serverStatuses.includes(config.status) const order = await prisma.order.create({ data: { userId: customer.id, status: config.status, tier: config.tier, domain, tools, configJson: { tools, tier: config.tier, domain }, serverIp: hasServer ? `192.168.1.${100 + i}` : null, serverPasswordEncrypted: hasServer ? 'encrypted_placeholder' : null, sshPort: 22, portainerUrl: config.status === OrderStatus.FULFILLED || config.status === OrderStatus.EMAIL_CONFIGURED ? `https://portainer.${domain}` : null, dashboardUrl: config.status === OrderStatus.FULFILLED || config.status === OrderStatus.EMAIL_CONFIGURED ? `https://dashboard.${domain}` : null, failureReason: config.status === OrderStatus.FAILED ? 'Connection timeout during Docker installation' : null, createdAt, serverReadyAt: hasServer ? new Date(createdAt.getTime() + 2 * 60 * 60 * 1000) : null, provisioningStartedAt: config.status === OrderStatus.PROVISIONING || config.status === OrderStatus.FULFILLED || config.status === OrderStatus.EMAIL_CONFIGURED ? new Date(createdAt.getTime() + 4 * 60 * 60 * 1000) : null, completedAt: config.status === OrderStatus.FULFILLED || config.status === OrderStatus.EMAIL_CONFIGURED ? new Date(createdAt.getTime() + 5 * 60 * 60 * 1000) : null, }, }) // Add provisioning logs based on status const statusIndex = Object.keys(logMessages).indexOf(config.status) const statusesToLog = Object.keys(logMessages).slice(0, statusIndex + 1) as OrderStatus[] let logTime = new Date(createdAt) for (const logStatus of statusesToLog) { const messages = logMessages[logStatus] || [] for (const message of messages) { await prisma.provisioningLog.create({ data: { orderId: order.id, level: logStatus === OrderStatus.FAILED ? LogLevel.ERROR : LogLevel.INFO, message, step: logStatus, timestamp: new Date(logTime), }, }) logTime = new Date(logTime.getTime() + Math.random() * 5 * 60 * 1000) // 0-5 min later } } console.log(`Created order: ${domain} (${config.status})`) } } // 6. Create a runner token for testing const runnerTokenHash = await hash('test-runner-token', 12) const existingRunner = await prisma.runnerToken.findFirst({ where: { name: 'test-runner' }, }) if (!existingRunner) { await prisma.runnerToken.create({ data: { tokenHash: runnerTokenHash, name: 'test-runner', isActive: true, }, }) console.log('Created test runner token') } console.log('\nSeed completed successfully!') console.log('\nTest credentials:') console.log(' Admin: admin@letsbe.solutions / admin123') console.log(' Support: support@letsbe.solutions / support123') console.log(' Customers: / customer123') } main() .catch((e) => { console.error(e) process.exit(1) }) .finally(async () => { await prisma.$disconnect() })