Files
2026-05-19 18:44:42 +02:00

258 lines
7.3 KiB
TypeScript

import {
PrismaClient,
RiskStatus,
TodoStatus,
Role,
PriorityStatus,
SecurityType,
} from "@prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";
import pg from "pg";
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 pool = new pg.Pool({
connectionString: process.env.DATABASE_URL,
});
const adapter = new PrismaPg(pool, { schema: "Athena" });
const prisma = new PrismaClient({ adapter });
const getRandom = <T>(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<Awaited<ReturnType<typeof prisma.user.create>>>;
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<Awaited<ReturnType<typeof prisma.user.create>>> = [];
const teamBAdmins: Array<Awaited<ReturnType<typeof prisma.user.create>>> = [];
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 = <T extends { id: string }>(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<Awaited<ReturnType<typeof prisma.user.create>>>,
) => {
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();
});