import { PrismaClient, RiskStatus, TodoStatus, Role, PriorityStatus, SecurityType, } from "@prisma/client"; import bcrypt from "bcryptjs"; import { firstNames, lastNames, jobTitles, actionVerbs, subjects, loremWords, phoneNumbers, middleNames, departments, } from "./mockData"; const sentenceFrom = (seed: number, min = 10, max = 22) => { const len = min + (seed % (max - min + 1)); const words: string[] = []; let i = seed; for (let c = 0; c < len; c++) { i = (i * 9301 + 49297) % 233280; words.push(loremWords[i % loremWords.length]); } const s = words.join(" "); return s.charAt(0).toUpperCase() + s.slice(1) + "."; }; const uniqueTitle = (idx: number) => { const verb = actionVerbs[idx % actionVerbs.length]; const subj = subjects[(idx * 7) % subjects.length]; return `${verb} ${subj} #${idx + 1}`; }; const uniqueTask = (idx: number) => { // Blend a seeded lorem sentence with a hint to ensure uniqueness const hint = `${firstNames[idx % firstNames.length]} ${ lastNames[(idx * 3) % lastNames.length] } ${jobTitles[(idx * 5) % jobTitles.length]}`; return `${sentenceFrom(idx)}\n\nContext: ${hint} [T${idx + 1}]`; }; const prisma = new PrismaClient(); const getRandom = (arr: T[]): T => arr[Math.floor(Math.random() * arr.length)]; // Determine security type by role for consistent seed data const securityFor = (role: Role): SecurityType => { switch (role) { case Role.MANAGER: return SecurityType.MAXIMUM; case Role.ADMIN: return SecurityType.ASSISTANCE; case Role.USER: default: return SecurityType.BASIC; } }; async function main() { console.log("🌱 Starting seed..."); await prisma.todo.deleteMany(); await prisma.user.deleteMany(); const users = [] as Array>>; const defaultPassword = await bcrypt.hash("password", 10); const superAdmin = await prisma.user.create({ data: { firstName: "Super", middleName: "John Travolta", lastName: "Admin", email: "superadmin@example.com", password: defaultPassword, riskStatus: RiskStatus.NO_RISK, phoneNumber: "1234567890", department: "Admin", imageUrl: null, title: "Administrator", isLocked: false, isActivated: true, role: Role.MANAGER, securityType: securityFor(Role.MANAGER), }, }); users.push(superAdmin); // Second MANAGER (Manager) const managerSuperAdmin = await prisma.user.create({ data: { firstName: "Manager", middleName: "John Travolta", lastName: "SuperAdmin", email: "manager@example.com", password: defaultPassword, riskStatus: RiskStatus.NO_RISK, phoneNumber: "1234567890", department: "Admin", imageUrl: null, title: "Administrator", isLocked: false, isActivated: true, role: Role.MANAGER, securityType: securityFor(Role.MANAGER), }, }); users.push(managerSuperAdmin); // Create 10 ADMIN users and split them between the two MANAGERs' teams const teamAAdmins: Array>> = []; const teamBAdmins: Array>> = []; for (let i = 1; i <= 10; i++) { const assignedManagerId = i <= 5 ? superAdmin.id : managerSuperAdmin.id; const adminUser = await prisma.user.create({ data: { firstName: `Admin${i}`, middleName: "Admin", lastName: "User", email: `admin${i}@example.com`, phoneNumber: `123456789${i}`, department: "Admin", password: defaultPassword, riskStatus: RiskStatus.NO_RISK, imageUrl: null, title: "Administrator", isLocked: false, isActivated: true, role: Role.ADMIN, securityType: securityFor(Role.ADMIN), managerId: assignedManagerId, }, }); users.push(adminUser); if (assignedManagerId === superAdmin.id) { teamAAdmins.push(adminUser); } else { teamBAdmins.push(adminUser); } } for (let i = 0; i < 100; i++) { const firstName = getRandom(firstNames); const lastName = getRandom(lastNames); const middleName = getRandom(middleNames); const phoneNumber = getRandom(phoneNumbers); const department = getRandom(departments); const user = await prisma.user.create({ data: { firstName, middleName, lastName, email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}${i}@example.com`, phoneNumber, department, password: defaultPassword, riskStatus: getRandom(Object.values(RiskStatus)), imageUrl: Math.random() > 0.5 ? `https://i.pravatar.cc/150?u=${firstName}${lastName}${i}` : null, title: getRandom(jobTitles), isLocked: false, isActivated: true, role: Role.USER, securityType: securityFor(Role.USER), }, }); users.push(user); } // Build team pools (Manager + their Admins) const teamA = [superAdmin, ...teamAAdmins]; const teamB = [managerSuperAdmin, ...teamBAdmins]; // Helper: get a random subset from an array (unique, size k) const pickSubset = (arr: T[], k: number): T[] => { const n = Math.max(1, Math.min(k, arr.length)); const pool = [...arr]; for (let i = pool.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [pool[i], pool[j]] = [pool[j], pool[i]]; } return pool.slice(0, n); }; // Create 50 todos split evenly between the two teams. const totalTodos = 50; const half = Math.floor(totalTodos / 2); let todoIndex = 0; const createTeamTodo = async ( team: Array>> ) => { const createdByUser = getRandom(team); // 1-3 assignees from the same team (ensure createdBy is included) const baseAssignees = pickSubset( team, 1 + Math.floor(Math.random() * Math.min(3, team.length)) ); const ensureCreatedBy = baseAssignees.some((u) => u.id === createdByUser.id) ? baseAssignees : [...baseAssignees, createdByUser]; const uniqueAssignees = Array.from( new Map(ensureCreatedBy.map((u) => [u.id, u])).values() ); const dueDate = new Date(); dueDate.setDate(dueDate.getDate() + Math.floor(Math.random() * 30)); await prisma.todo.create({ data: { title: uniqueTitle(todoIndex), task: uniqueTask(todoIndex), status: getRandom(Object.values(TodoStatus)), priority: getRandom(Object.values(PriorityStatus)), dueDate, createdBy: { connect: { id: createdByUser.id } }, assignees: { connect: uniqueAssignees.map((u) => ({ id: u.id })) }, }, }); todoIndex += 1; }; for (let i = 0; i < half; i++) { await createTeamTodo(teamA); } for (let i = 0; i < totalTodos - half; i++) { await createTeamTodo(teamB); } console.log(`✅ Seeded ${users.length} users and 50 todos`); } main() .catch((e) => { console.error("❌ Seed error:", e); process.exit(1); }) .finally(async () => { await prisma.$disconnect(); });